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
, te
.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 Report
.SymbolRelatedToPreviousError (te
.Type
);
273 ErrorIsInaccesible (loc
, TypeManager
.CSharpName (te
.Type
));
281 public static void ErrorIsInaccesible (Location loc
, string name
)
283 Report
.Error (122, loc
, "`{0}' is inaccessible due to its protection level", name
);
286 protected static void Error_CannotAccessProtected (Location loc
, MemberInfo m
, Type qualifier
, Type container
)
288 Report
.Error (1540, loc
, "Cannot access protected member `{0}' via a qualifier of type `{1}';"
289 + " the qualifier must be of type `{2}' (or derived from it)",
290 TypeManager
.GetFullNameSignature (m
),
291 TypeManager
.CSharpName (qualifier
),
292 TypeManager
.CSharpName (container
));
296 public static void Error_VoidInvalidInTheContext (Location loc
)
298 Report
.Error (1547, loc
, "Keyword `void' cannot be used in this context");
301 public virtual void Error_ValueCannotBeConverted (Location loc
, Type target
, bool expl
)
303 if (Type
.Name
== target
.Name
){
304 Report
.ExtraInformation (loc
,
306 "The type {0} has two conflicting definitions, one comes from {1} and the other from {2}",
307 Type
.Name
, Type
.Assembly
.FullName
, target
.Assembly
.FullName
));
312 Report
.Error (30, loc
, "Cannot convert type `{0}' to `{1}'",
313 GetSignatureForError (), TypeManager
.CSharpName (target
));
317 Expression e
= (this is EnumConstant
) ? ((EnumConstant
)this).Child
: this;
318 bool b
= Convert
.ExplicitNumericConversion (e
, target
) != null;
320 if (b
|| Convert
.ExplicitReferenceConversionExists (Type
, target
) || Convert
.ExplicitUnsafe (e
, target
) != null) {
321 Report
.Error (266, loc
, "Cannot implicitly convert type `{0}' to `{1}'. An explicit conversion exists (are you missing a cast?)",
322 TypeManager
.CSharpName (Type
), TypeManager
.CSharpName (target
));
326 if (Type
!= TypeManager
.string_type
&& this is Constant
&& !(this is NullCast
)) {
327 Report
.Error (31, loc
, "Constant value `{0}' cannot be converted to a `{1}'",
328 GetSignatureForError (), TypeManager
.CSharpName (target
));
332 Report
.Error (29, loc
, "Cannot implicitly convert type {0} to `{1}'",
333 Type
== TypeManager
.anonymous_method_type
?
334 "anonymous method" : "`" + GetSignatureForError () + "'",
335 TypeManager
.CSharpName (target
));
338 protected static void Error_TypeDoesNotContainDefinition (Location loc
, Type type
, string name
)
340 Report
.Error (117, loc
, "`{0}' does not contain a definition for `{1}'",
341 TypeManager
.CSharpName (type
), name
);
344 ResolveFlags ExprClassToResolveFlags
349 case ExprClass
.Namespace
:
350 return ResolveFlags
.Type
;
352 case ExprClass
.MethodGroup
:
353 return ResolveFlags
.MethodGroup
;
355 case ExprClass
.Value
:
356 case ExprClass
.Variable
:
357 case ExprClass
.PropertyAccess
:
358 case ExprClass
.EventAccess
:
359 case ExprClass
.IndexerAccess
:
360 return ResolveFlags
.VariableOrValue
;
363 throw new Exception ("Expression " + GetType () +
364 " ExprClass is Invalid after resolve");
370 /// Resolves an expression and performs semantic analysis on it.
374 /// Currently Resolve wraps DoResolve to perform sanity
375 /// checking and assertion checking on what we expect from Resolve.
377 public Expression
Resolve (EmitContext ec
, ResolveFlags flags
)
379 if ((flags
& ResolveFlags
.MaskExprClass
) == ResolveFlags
.Type
)
380 return ResolveAsTypeStep (ec
, false);
382 bool do_flow_analysis
= ec
.DoFlowAnalysis
;
383 bool omit_struct_analysis
= ec
.OmitStructFlowAnalysis
;
384 if ((flags
& ResolveFlags
.DisableFlowAnalysis
) != 0)
385 do_flow_analysis
= false;
386 if ((flags
& ResolveFlags
.DisableStructFlowAnalysis
) != 0)
387 omit_struct_analysis
= true;
390 using (ec
.WithFlowAnalysis (do_flow_analysis
, omit_struct_analysis
)) {
391 if (this is SimpleName
) {
392 bool intermediate
= (flags
& ResolveFlags
.Intermediate
) == ResolveFlags
.Intermediate
;
393 e
= ((SimpleName
) this).DoResolve (ec
, intermediate
);
402 if ((flags
& e
.ExprClassToResolveFlags
) == 0) {
403 e
.Error_UnexpectedKind (flags
, loc
);
407 if (e
.type
== null && !(e
is Namespace
)) {
408 throw new Exception (
409 "Expression " + e
.GetType () +
410 " did not set its type after Resolve\n" +
411 "called from: " + this.GetType ());
418 /// Resolves an expression and performs semantic analysis on it.
420 public Expression
Resolve (EmitContext ec
)
422 Expression e
= Resolve (ec
, ResolveFlags
.VariableOrValue
| ResolveFlags
.MethodGroup
);
424 if (e
!= null && e
.eclass
== ExprClass
.MethodGroup
&& RootContext
.Version
== LanguageVersion
.ISO_1
) {
425 ((MethodGroupExpr
) e
).ReportUsageError ();
431 public Constant
ResolveAsConstant (EmitContext ec
, MemberCore mc
)
433 Expression e
= Resolve (ec
);
437 Constant c
= e
as Constant
;
441 Type constant_type
= null;
442 if (mc
is MemberBase
) {
443 constant_type
= ((MemberBase
)mc
).MemberType
;
446 Const
.Error_ExpressionMustBeConstant (constant_type
, loc
, mc
.GetSignatureForError ());
451 /// Resolves an expression for LValue assignment
455 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
456 /// checking and assertion checking on what we expect from Resolve
458 public Expression
ResolveLValue (EmitContext ec
, Expression right_side
, Location loc
)
460 int errors
= Report
.Errors
;
461 bool out_access
= right_side
== EmptyExpression
.OutAccess
;
463 Expression e
= DoResolveLValue (ec
, right_side
);
465 if (e
!= null && out_access
&& !(e
is IMemoryLocation
)) {
466 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
467 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
469 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
470 // e.GetType () + " " + e.GetSignatureForError ());
475 if (errors
== Report
.Errors
) {
477 Report
.Error (1510, loc
, "A ref or out argument must be an assignable variable");
479 Report
.Error (131, loc
, "The left-hand side of an assignment or mutating operation must be a variable, property or indexer");
484 if (e
.eclass
== ExprClass
.Invalid
)
485 throw new Exception ("Expression " + e
+ " ExprClass is Invalid after resolve");
487 if (e
.eclass
== ExprClass
.MethodGroup
) {
488 ((MethodGroupExpr
) e
).ReportUsageError ();
493 throw new Exception ("Expression " + e
+ " did not set its type after Resolve");
499 /// Emits the code for the expression
503 /// The Emit method is invoked to generate the code
504 /// for the expression.
506 public abstract void Emit (EmitContext ec
);
508 public virtual void EmitBranchable (EmitContext ec
, Label target
, bool onTrue
)
511 ec
.ig
.Emit (onTrue
? OpCodes
.Brtrue
: OpCodes
.Brfalse
, target
);
515 /// Protected constructor. Only derivate types should
516 /// be able to be created
519 protected Expression ()
521 eclass
= ExprClass
.Invalid
;
526 /// Returns a literalized version of a literal FieldInfo
530 /// The possible return values are:
531 /// IntConstant, UIntConstant
532 /// LongLiteral, ULongConstant
533 /// FloatConstant, DoubleConstant
536 /// The value returned is already resolved.
538 public static Constant
Constantify (object v
, Type t
)
540 if (t
== TypeManager
.int32_type
)
541 return new IntConstant ((int) v
, Location
.Null
);
542 else if (t
== TypeManager
.uint32_type
)
543 return new UIntConstant ((uint) v
, Location
.Null
);
544 else if (t
== TypeManager
.int64_type
)
545 return new LongConstant ((long) v
, Location
.Null
);
546 else if (t
== TypeManager
.uint64_type
)
547 return new ULongConstant ((ulong) v
, Location
.Null
);
548 else if (t
== TypeManager
.float_type
)
549 return new FloatConstant ((float) v
, Location
.Null
);
550 else if (t
== TypeManager
.double_type
)
551 return new DoubleConstant ((double) v
, Location
.Null
);
552 else if (t
== TypeManager
.string_type
)
553 return new StringConstant ((string) v
, Location
.Null
);
554 else if (t
== TypeManager
.short_type
)
555 return new ShortConstant ((short)v
, Location
.Null
);
556 else if (t
== TypeManager
.ushort_type
)
557 return new UShortConstant ((ushort)v
, Location
.Null
);
558 else if (t
== TypeManager
.sbyte_type
)
559 return new SByteConstant ((sbyte)v
, Location
.Null
);
560 else if (t
== TypeManager
.byte_type
)
561 return new ByteConstant ((byte)v
, Location
.Null
);
562 else if (t
== TypeManager
.char_type
)
563 return new CharConstant ((char)v
, Location
.Null
);
564 else if (t
== TypeManager
.bool_type
)
565 return new BoolConstant ((bool) v
, Location
.Null
);
566 else if (t
== TypeManager
.decimal_type
)
567 return new DecimalConstant ((decimal) v
, Location
.Null
);
568 else if (TypeManager
.IsEnumType (t
)){
569 Type real_type
= TypeManager
.TypeToCoreType (v
.GetType ());
571 real_type
= System
.Enum
.GetUnderlyingType (real_type
);
573 Constant e
= Constantify (v
, real_type
);
575 return new EnumConstant (e
, t
);
576 } else if (v
== null && !TypeManager
.IsValueType (t
))
577 return new NullLiteral (Location
.Null
);
579 throw new Exception ("Unknown type for constant (" + t
+
584 /// Returns a fully formed expression after a MemberLookup
587 public static Expression
ExprClassFromMemberInfo (Type containerType
, MemberInfo mi
, Location loc
)
590 return new EventExpr ((EventInfo
) mi
, loc
);
591 else if (mi
is FieldInfo
)
592 return new FieldExpr ((FieldInfo
) mi
, loc
);
593 else if (mi
is PropertyInfo
)
594 return new PropertyExpr (containerType
, (PropertyInfo
) mi
, loc
);
595 else if (mi
is Type
){
596 return new TypeExpression ((System
.Type
) mi
, loc
);
602 protected static ArrayList almostMatchedMembers
= new ArrayList (4);
605 // FIXME: Probably implement a cache for (t,name,current_access_set)?
607 // This code could use some optimizations, but we need to do some
608 // measurements. For example, we could use a delegate to `flag' when
609 // something can not any longer be a method-group (because it is something
613 // If the return value is an Array, then it is an array of
616 // If the return value is an MemberInfo, it is anything, but a Method
620 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
621 // the arguments here and have MemberLookup return only the methods that
622 // match the argument count/type, unlike we are doing now (we delay this
625 // This is so we can catch correctly attempts to invoke instance methods
626 // from a static body (scan for error 120 in ResolveSimpleName).
629 // FIXME: Potential optimization, have a static ArrayList
632 public static Expression
MemberLookup (Type container_type
, Type queried_type
, string name
,
633 MemberTypes mt
, BindingFlags bf
, Location loc
)
635 return MemberLookup (container_type
, null, queried_type
, name
, mt
, bf
, loc
);
639 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
640 // `qualifier_type' or null to lookup members in the current class.
643 public static Expression
MemberLookup (Type container_type
,
644 Type qualifier_type
, Type queried_type
,
645 string name
, MemberTypes mt
,
646 BindingFlags bf
, Location loc
)
648 almostMatchedMembers
.Clear ();
650 MemberInfo
[] mi
= TypeManager
.MemberLookup (container_type
, qualifier_type
,
651 queried_type
, mt
, bf
, name
, almostMatchedMembers
);
657 bool is_interface
= qualifier_type
!= null && qualifier_type
.IsInterface
;
658 MemberInfo non_method
= null;
659 ArrayList methods
= new ArrayList (2);
661 foreach (MemberInfo m
in mi
) {
662 if (m
is MethodBase
) {
667 if (non_method
== null) {
675 Report
.SymbolRelatedToPreviousError (m
);
676 Report
.SymbolRelatedToPreviousError (non_method
);
677 Report
.Error (229, loc
, "Ambiguity between `{0}' and `{1}'",
678 TypeManager
.GetFullNameSignature (m
), TypeManager
.GetFullNameSignature (non_method
));
682 if (non_method
!= null && is_interface
) {
683 MethodBase method
= (MethodBase
)methods
[0];
684 Report
.SymbolRelatedToPreviousError (method
);
685 Report
.SymbolRelatedToPreviousError (non_method
);
686 Report
.Warning (467, 2, loc
, "Ambiguity between method `{0}' and non-method `{1}'. Using method `{0}'",
687 TypeManager
.CSharpSignature (method
), TypeManager
.GetFullNameSignature (non_method
));
690 if (methods
.Count
== 0)
691 return new MethodGroupExpr (mi
, loc
);
693 return new MethodGroupExpr (methods
, loc
);
696 if (mi
[0] is MethodBase
)
697 return new MethodGroupExpr (mi
, loc
);
699 return ExprClassFromMemberInfo (container_type
, mi
[0], loc
);
702 public const MemberTypes AllMemberTypes
=
703 MemberTypes
.Constructor
|
707 MemberTypes
.NestedType
|
708 MemberTypes
.Property
;
710 public const BindingFlags AllBindingFlags
=
711 BindingFlags
.Public
|
712 BindingFlags
.Static
|
713 BindingFlags
.Instance
;
715 public static Expression
MemberLookup (Type container_type
, Type queried_type
,
716 string name
, Location loc
)
718 return MemberLookup (container_type
, null, queried_type
, name
,
719 AllMemberTypes
, AllBindingFlags
, loc
);
722 public static Expression
MemberLookup (Type container_type
, Type qualifier_type
,
723 Type queried_type
, string name
, Location loc
)
725 return MemberLookup (container_type
, qualifier_type
, queried_type
,
726 name
, AllMemberTypes
, AllBindingFlags
, loc
);
729 public static Expression
MethodLookup (EmitContext ec
, Type queried_type
,
730 string name
, Location loc
)
732 return MemberLookup (ec
.ContainerType
, null, queried_type
, name
,
733 MemberTypes
.Method
, AllBindingFlags
, loc
);
737 /// This is a wrapper for MemberLookup that is not used to "probe", but
738 /// to find a final definition. If the final definition is not found, we
739 /// look for private members and display a useful debugging message if we
742 public static Expression
MemberLookupFinal (EmitContext ec
, Type qualifier_type
,
743 Type queried_type
, string name
, Location loc
)
745 return MemberLookupFinal (ec
, qualifier_type
, queried_type
, name
,
746 AllMemberTypes
, AllBindingFlags
, loc
);
749 public static Expression
MemberLookupFinal (EmitContext ec
, Type qualifier_type
,
750 Type queried_type
, string name
,
751 MemberTypes mt
, BindingFlags bf
,
756 int errors
= Report
.Errors
;
758 e
= MemberLookup (ec
.ContainerType
, qualifier_type
, queried_type
, name
, mt
, bf
, loc
);
760 if (e
== null && errors
== Report
.Errors
)
761 // No errors were reported by MemberLookup, but there was an error.
762 MemberLookupFailed (ec
.ContainerType
, qualifier_type
, queried_type
, name
, null, true, loc
);
767 public static void MemberLookupFailed (Type container_type
, Type qualifier_type
,
768 Type queried_type
, string name
,
769 string class_name
, bool complain_if_none_found
,
772 if (almostMatchedMembers
.Count
!= 0) {
773 for (int i
= 0; i
< almostMatchedMembers
.Count
; ++i
) {
774 MemberInfo m
= (MemberInfo
) almostMatchedMembers
[i
];
775 for (int j
= 0; j
< i
; ++j
) {
776 if (m
== almostMatchedMembers
[j
]) {
784 Type declaring_type
= m
.DeclaringType
;
786 Report
.SymbolRelatedToPreviousError (m
);
787 if (qualifier_type
== null) {
788 Report
.Error (38, loc
, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
789 TypeManager
.CSharpName (m
.DeclaringType
),
790 TypeManager
.CSharpName (container_type
));
792 } else if (qualifier_type
!= container_type
&&
793 TypeManager
.IsNestedFamilyAccessible (container_type
, declaring_type
)) {
794 // Although a derived class can access protected members of
795 // its base class it cannot do so through an instance of the
796 // base class (CS1540). If the qualifier_type is a base of the
797 // ec.ContainerType and the lookup succeeds with the latter one,
798 // then we are in this situation.
799 Error_CannotAccessProtected (loc
, m
, qualifier_type
, container_type
);
801 Report
.SymbolRelatedToPreviousError (m
);
802 ErrorIsInaccesible (loc
, TypeManager
.GetFullNameSignature (m
));
805 almostMatchedMembers
.Clear ();
809 MemberInfo
[] lookup
= null;
810 if (queried_type
== null) {
811 class_name
= "global::";
813 lookup
= TypeManager
.MemberLookup (queried_type
, null, queried_type
,
814 AllMemberTypes
, AllBindingFlags
|
815 BindingFlags
.NonPublic
, name
, null);
818 if (lookup
== null) {
819 if (!complain_if_none_found
)
822 if (class_name
!= null)
823 Report
.Error (103, loc
, "The name `{0}' does not exist in the context of `{1}'",
826 Error_TypeDoesNotContainDefinition (loc
, queried_type
, name
);
830 MemberList ml
= TypeManager
.FindMembers (queried_type
, MemberTypes
.Constructor
,
831 BindingFlags
.Static
| BindingFlags
.Instance
| BindingFlags
.Public
| BindingFlags
.DeclaredOnly
, null, null);
832 if (name
== ".ctor" && ml
.Count
== 0)
834 Report
.Error (143, loc
, "The type `{0}' has no constructors defined", TypeManager
.CSharpName (queried_type
));
838 Report
.SymbolRelatedToPreviousError (lookup
[0]);
839 ErrorIsInaccesible (loc
, TypeManager
.GetFullNameSignature (lookup
[0]));
843 /// Returns an expression that can be used to invoke operator true
844 /// on the expression if it exists.
846 static public StaticCallExpr
GetOperatorTrue (EmitContext ec
, Expression e
, Location loc
)
848 return GetOperatorTrueOrFalse (ec
, e
, true, loc
);
852 /// Returns an expression that can be used to invoke operator false
853 /// on the expression if it exists.
855 static public StaticCallExpr
GetOperatorFalse (EmitContext ec
, Expression e
, Location loc
)
857 return GetOperatorTrueOrFalse (ec
, e
, false, loc
);
860 static StaticCallExpr
GetOperatorTrueOrFalse (EmitContext ec
, Expression e
, bool is_true
, Location loc
)
863 Expression operator_group
;
865 operator_group
= MethodLookup (ec
, e
.Type
, is_true
? "op_True" : "op_False", loc
);
866 if (operator_group
== null)
869 ArrayList arguments
= new ArrayList ();
870 arguments
.Add (new Argument (e
, Argument
.AType
.Expression
));
871 method
= Invocation
.OverloadResolve (
872 ec
, (MethodGroupExpr
) operator_group
, arguments
, false, loc
);
877 return new StaticCallExpr ((MethodInfo
) method
, arguments
, loc
);
881 /// Resolves the expression `e' into a boolean expression: either through
882 /// an implicit conversion, or through an `operator true' invocation
884 public static Expression
ResolveBoolean (EmitContext ec
, Expression e
, Location loc
)
890 if (e
.Type
== TypeManager
.bool_type
)
893 Expression converted
= Convert
.ImplicitConversion (ec
, e
, TypeManager
.bool_type
, Location
.Null
);
895 if (converted
!= null)
899 // If no implicit conversion to bool exists, try using `operator true'
901 converted
= Expression
.GetOperatorTrue (ec
, e
, loc
);
902 if (converted
== null){
903 e
.Error_ValueCannotBeConverted (loc
, TypeManager
.bool_type
, false);
909 public virtual string ExprClassName
913 case ExprClass
.Invalid
:
915 case ExprClass
.Value
:
917 case ExprClass
.Variable
:
919 case ExprClass
.Namespace
:
923 case ExprClass
.MethodGroup
:
924 return "method group";
925 case ExprClass
.PropertyAccess
:
926 return "property access";
927 case ExprClass
.EventAccess
:
928 return "event access";
929 case ExprClass
.IndexerAccess
:
930 return "indexer access";
931 case ExprClass
.Nothing
:
934 throw new Exception ("Should not happen");
939 /// Reports that we were expecting `expr' to be of class `expected'
941 public void Error_UnexpectedKind (DeclSpace ds
, string expected
, Location loc
)
943 Error_UnexpectedKind (ds
, expected
, ExprClassName
, loc
);
946 public void Error_UnexpectedKind (DeclSpace ds
, string expected
, string was
, Location loc
)
948 string name
= GetSignatureForError ();
950 name
= ds
.GetSignatureForError () + '.' + name
;
952 Report
.Error (118, loc
, "`{0}' is a `{1}' but a `{2}' was expected",
953 name
, was
, expected
);
956 public void Error_UnexpectedKind (ResolveFlags flags
, Location loc
)
958 string [] valid
= new string [4];
961 if ((flags
& ResolveFlags
.VariableOrValue
) != 0) {
962 valid
[count
++] = "variable";
963 valid
[count
++] = "value";
966 if ((flags
& ResolveFlags
.Type
) != 0)
967 valid
[count
++] = "type";
969 if ((flags
& ResolveFlags
.MethodGroup
) != 0)
970 valid
[count
++] = "method group";
973 valid
[count
++] = "unknown";
975 StringBuilder sb
= new StringBuilder (valid
[0]);
976 for (int i
= 1; i
< count
- 1; i
++) {
978 sb
.Append (valid
[i
]);
981 sb
.Append ("' or `");
982 sb
.Append (valid
[count
- 1]);
985 Report
.Error (119, loc
,
986 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName
, sb
.ToString ());
989 public static void UnsafeError (Location loc
)
991 Report
.Error (214, loc
, "Pointers and fixed size buffers may only be used in an unsafe context");
995 // Load the object from the pointer.
997 public static void LoadFromPtr (ILGenerator ig
, Type t
)
999 if (t
== TypeManager
.int32_type
)
1000 ig
.Emit (OpCodes
.Ldind_I4
);
1001 else if (t
== TypeManager
.uint32_type
)
1002 ig
.Emit (OpCodes
.Ldind_U4
);
1003 else if (t
== TypeManager
.short_type
)
1004 ig
.Emit (OpCodes
.Ldind_I2
);
1005 else if (t
== TypeManager
.ushort_type
)
1006 ig
.Emit (OpCodes
.Ldind_U2
);
1007 else if (t
== TypeManager
.char_type
)
1008 ig
.Emit (OpCodes
.Ldind_U2
);
1009 else if (t
== TypeManager
.byte_type
)
1010 ig
.Emit (OpCodes
.Ldind_U1
);
1011 else if (t
== TypeManager
.sbyte_type
)
1012 ig
.Emit (OpCodes
.Ldind_I1
);
1013 else if (t
== TypeManager
.uint64_type
)
1014 ig
.Emit (OpCodes
.Ldind_I8
);
1015 else if (t
== TypeManager
.int64_type
)
1016 ig
.Emit (OpCodes
.Ldind_I8
);
1017 else if (t
== TypeManager
.float_type
)
1018 ig
.Emit (OpCodes
.Ldind_R4
);
1019 else if (t
== TypeManager
.double_type
)
1020 ig
.Emit (OpCodes
.Ldind_R8
);
1021 else if (t
== TypeManager
.bool_type
)
1022 ig
.Emit (OpCodes
.Ldind_I1
);
1023 else if (t
== TypeManager
.intptr_type
)
1024 ig
.Emit (OpCodes
.Ldind_I
);
1025 else if (TypeManager
.IsEnumType (t
)) {
1026 if (t
== TypeManager
.enum_type
)
1027 ig
.Emit (OpCodes
.Ldind_Ref
);
1029 LoadFromPtr (ig
, TypeManager
.EnumToUnderlying (t
));
1030 } else if (t
.IsValueType
)
1031 ig
.Emit (OpCodes
.Ldobj
, t
);
1032 else if (t
.IsPointer
)
1033 ig
.Emit (OpCodes
.Ldind_I
);
1035 ig
.Emit (OpCodes
.Ldind_Ref
);
1039 // The stack contains the pointer and the value of type `type'
1041 public static void StoreFromPtr (ILGenerator ig
, Type type
)
1043 if (TypeManager
.IsEnumType (type
))
1044 type
= TypeManager
.EnumToUnderlying (type
);
1045 if (type
== TypeManager
.int32_type
|| type
== TypeManager
.uint32_type
)
1046 ig
.Emit (OpCodes
.Stind_I4
);
1047 else if (type
== TypeManager
.int64_type
|| type
== TypeManager
.uint64_type
)
1048 ig
.Emit (OpCodes
.Stind_I8
);
1049 else if (type
== TypeManager
.char_type
|| type
== TypeManager
.short_type
||
1050 type
== TypeManager
.ushort_type
)
1051 ig
.Emit (OpCodes
.Stind_I2
);
1052 else if (type
== TypeManager
.float_type
)
1053 ig
.Emit (OpCodes
.Stind_R4
);
1054 else if (type
== TypeManager
.double_type
)
1055 ig
.Emit (OpCodes
.Stind_R8
);
1056 else if (type
== TypeManager
.byte_type
|| type
== TypeManager
.sbyte_type
||
1057 type
== TypeManager
.bool_type
)
1058 ig
.Emit (OpCodes
.Stind_I1
);
1059 else if (type
== TypeManager
.intptr_type
)
1060 ig
.Emit (OpCodes
.Stind_I
);
1061 else if (type
.IsValueType
)
1062 ig
.Emit (OpCodes
.Stobj
, type
);
1064 ig
.Emit (OpCodes
.Stind_Ref
);
1068 // Returns the size of type `t' if known, otherwise, 0
1070 public static int GetTypeSize (Type t
)
1072 t
= TypeManager
.TypeToCoreType (t
);
1073 if (t
== TypeManager
.int32_type
||
1074 t
== TypeManager
.uint32_type
||
1075 t
== TypeManager
.float_type
)
1077 else if (t
== TypeManager
.int64_type
||
1078 t
== TypeManager
.uint64_type
||
1079 t
== TypeManager
.double_type
)
1081 else if (t
== TypeManager
.byte_type
||
1082 t
== TypeManager
.sbyte_type
||
1083 t
== TypeManager
.bool_type
)
1085 else if (t
== TypeManager
.short_type
||
1086 t
== TypeManager
.char_type
||
1087 t
== TypeManager
.ushort_type
)
1089 else if (t
== TypeManager
.decimal_type
)
1095 public static void Error_NegativeArrayIndex (Location loc
)
1097 Report
.Error (248, loc
, "Cannot create an array with a negative size");
1100 protected void Error_CannotCallAbstractBase (string name
)
1102 Report
.Error (205, loc
, "Cannot call an abstract base member `{0}'", name
);
1106 // Converts `source' to an int, uint, long or ulong.
1108 public Expression
ExpressionToArrayArgument (EmitContext ec
, Expression source
, Location loc
)
1112 using (ec
.With (EmitContext
.Flags
.CheckState
, true)) {
1113 target
= Convert
.ImplicitConversion (ec
, source
, TypeManager
.int32_type
, loc
);
1115 target
= Convert
.ImplicitConversion (ec
, source
, TypeManager
.uint32_type
, loc
);
1117 target
= Convert
.ImplicitConversion (ec
, source
, TypeManager
.int64_type
, loc
);
1119 target
= Convert
.ImplicitConversion (ec
, source
, TypeManager
.uint64_type
, loc
);
1121 if (target
== null) {
1122 source
.Error_ValueCannotBeConverted (loc
, TypeManager
.int32_type
, false);
1128 // Only positive constants are allowed at compile time
1130 if (target
is Constant
){
1131 if (target
is IntConstant
){
1132 if (((IntConstant
) target
).Value
< 0){
1133 Error_NegativeArrayIndex (loc
);
1138 if (target
is LongConstant
){
1139 if (((LongConstant
) target
).Value
< 0){
1140 Error_NegativeArrayIndex (loc
);
1153 /// This is just a base class for expressions that can
1154 /// appear on statements (invocations, object creation,
1155 /// assignments, post/pre increment and decrement). The idea
1156 /// being that they would support an extra Emition interface that
1157 /// does not leave a result on the stack.
1159 public abstract class ExpressionStatement
: Expression
{
1161 public virtual ExpressionStatement
ResolveStatement (EmitContext ec
)
1163 Expression e
= Resolve (ec
);
1167 ExpressionStatement es
= e
as ExpressionStatement
;
1169 Error (201, "Only assignment, call, increment, decrement and new object " +
1170 "expressions can be used as a statement");
1176 /// Requests the expression to be emitted in a `statement'
1177 /// context. This means that no new value is left on the
1178 /// stack after invoking this method (constrasted with
1179 /// Emit that will always leave a value on the stack).
1181 public abstract void EmitStatement (EmitContext ec
);
1185 /// This kind of cast is used to encapsulate the child
1186 /// whose type is child.Type into an expression that is
1187 /// reported to return "return_type". This is used to encapsulate
1188 /// expressions which have compatible types, but need to be dealt
1189 /// at higher levels with.
1191 /// For example, a "byte" expression could be encapsulated in one
1192 /// of these as an "unsigned int". The type for the expression
1193 /// would be "unsigned int".
1196 public class EmptyCast
: Expression
{
1197 protected readonly Expression child
;
1199 public EmptyCast (Expression child
, Type return_type
)
1201 eclass
= child
.eclass
;
1202 loc
= child
.Location
;
1207 public override Expression
DoResolve (EmitContext ec
)
1209 // This should never be invoked, we are born in fully
1210 // initialized state.
1215 public override void Emit (EmitContext ec
)
1220 public override bool GetAttributableValue (Type valueType
, out object value)
1222 return child
.GetAttributableValue (valueType
, out value);
1227 /// This is a numeric cast to a Decimal
1229 public class CastToDecimal
: EmptyCast
{
1231 MethodInfo conversion_operator
;
1233 public CastToDecimal (Expression child
)
1234 : this (child
, false)
1238 public CastToDecimal (Expression child
, bool find_explicit
)
1239 : base (child
, TypeManager
.decimal_type
)
1241 conversion_operator
= GetConversionOperator (find_explicit
);
1243 if (conversion_operator
== null)
1244 throw new InternalErrorException ("Outer conversion routine is out of sync");
1247 // Returns the implicit operator that converts from
1248 // 'child.Type' to System.Decimal.
1249 MethodInfo
GetConversionOperator (bool find_explicit
)
1251 string operator_name
= find_explicit
? "op_Explicit" : "op_Implicit";
1253 MemberInfo
[] mi
= TypeManager
.MemberLookup (type
, type
, type
, MemberTypes
.Method
,
1254 BindingFlags
.Static
| BindingFlags
.Public
, operator_name
, null);
1256 foreach (MethodInfo oper
in mi
) {
1257 ParameterData pd
= TypeManager
.GetParameterData (oper
);
1259 if (pd
.ParameterType (0) == child
.Type
&& oper
.ReturnType
== type
)
1265 public override void Emit (EmitContext ec
)
1267 ILGenerator ig
= ec
.ig
;
1270 ig
.Emit (OpCodes
.Call
, conversion_operator
);
1275 /// This is an explicit numeric cast from a Decimal
1277 public class CastFromDecimal
: EmptyCast
1279 static IDictionary operators
;
1281 public CastFromDecimal (Expression child
, Type return_type
)
1282 : base (child
, return_type
)
1284 if (child
.Type
!= TypeManager
.decimal_type
)
1285 throw new InternalErrorException (
1286 "The expected type is Decimal, instead it is " + child
.Type
.FullName
);
1289 // Returns the explicit operator that converts from an
1290 // express of type System.Decimal to 'type'.
1291 public Expression
Resolve ()
1293 if (operators
== null) {
1294 MemberInfo
[] all_oper
= TypeManager
.MemberLookup (TypeManager
.decimal_type
,
1295 TypeManager
.decimal_type
, TypeManager
.decimal_type
, MemberTypes
.Method
,
1296 BindingFlags
.Static
| BindingFlags
.Public
, "op_Explicit", null);
1298 operators
= new System
.Collections
.Specialized
.HybridDictionary ();
1299 foreach (MethodInfo oper
in all_oper
) {
1300 ParameterData pd
= TypeManager
.GetParameterData (oper
);
1301 if (pd
.ParameterType (0) == TypeManager
.decimal_type
)
1302 operators
.Add (oper
.ReturnType
, oper
);
1306 return operators
.Contains (type
) ? this : null;
1309 public override void Emit (EmitContext ec
)
1311 ILGenerator ig
= ec
.ig
;
1314 ig
.Emit (OpCodes
.Call
, (MethodInfo
)operators
[type
]);
1319 // We need to special case this since an empty cast of
1320 // a NullLiteral is still a Constant
1322 public class NullCast
: Constant
{
1323 public Constant child
;
1325 public NullCast (Constant child
, Type return_type
):
1326 base (Location
.Null
)
1328 eclass
= child
.eclass
;
1333 override public string AsString ()
1338 public override object GetValue ()
1343 public override Expression
DoResolve (EmitContext ec
)
1345 // This should never be invoked, we are born in fully
1346 // initialized state.
1351 public override void Emit (EmitContext ec
)
1356 public override Constant
Increment ()
1358 throw new NotSupportedException ();
1361 public override bool IsDefaultValue
{
1367 public override bool IsNegative
{
1373 public override Constant
Reduce (bool inCheckedContext
, Type target_type
)
1375 if (type
== target_type
)
1376 return child
.Reduce (inCheckedContext
, target_type
);
1385 /// This class is used to wrap literals which belong inside Enums
1387 public class EnumConstant
: Constant
{
1388 public Constant Child
;
1390 public EnumConstant (Constant child
, Type enum_type
):
1391 base (child
.Location
)
1393 eclass
= child
.eclass
;
1398 public override Expression
DoResolve (EmitContext ec
)
1400 // This should never be invoked, we are born in fully
1401 // initialized state.
1406 public override void Emit (EmitContext ec
)
1411 public override bool GetAttributableValue (Type valueType
, out object value)
1413 value = GetTypedValue ();
1417 public override string GetSignatureForError()
1419 return TypeManager
.CSharpName (Type
);
1422 public override object GetValue ()
1424 return Child
.GetValue ();
1427 public override object GetTypedValue ()
1429 // FIXME: runtime is not ready to work with just emited enums
1430 if (!RootContext
.StdLib
) {
1431 return Child
.GetValue ();
1434 return System
.Enum
.ToObject (type
, Child
.GetValue ());
1437 public override string AsString ()
1439 return Child
.AsString ();
1442 public override DoubleConstant
ConvertToDouble ()
1444 return Child
.ConvertToDouble ();
1447 public override FloatConstant
ConvertToFloat ()
1449 return Child
.ConvertToFloat ();
1452 public override ULongConstant
ConvertToULong ()
1454 return Child
.ConvertToULong ();
1457 public override LongConstant
ConvertToLong ()
1459 return Child
.ConvertToLong ();
1462 public override UIntConstant
ConvertToUInt ()
1464 return Child
.ConvertToUInt ();
1467 public override IntConstant
ConvertToInt ()
1469 return Child
.ConvertToInt ();
1472 public override Constant
Increment()
1474 return new EnumConstant (Child
.Increment (), type
);
1477 public override bool IsDefaultValue
{
1479 return Child
.IsDefaultValue
;
1483 public override bool IsZeroInteger
{
1484 get { return Child.IsZeroInteger; }
1487 public override bool IsNegative
{
1489 return Child
.IsNegative
;
1493 public override Constant
Reduce(bool inCheckedContext
, Type target_type
)
1495 if (Child
.Type
== target_type
)
1498 return Child
.Reduce (inCheckedContext
, target_type
);
1501 public override Constant
ToType (Type type
, Location loc
)
1504 // This is workaround of mono bug. It can be removed when the latest corlib spreads enough
1505 if (TypeManager
.IsEnumType (type
.UnderlyingSystemType
))
1508 if (type
.UnderlyingSystemType
!= Child
.Type
)
1509 Child
= Child
.ToType (type
.UnderlyingSystemType
, loc
);
1513 if (!Convert
.ImplicitStandardConversionExists (this, type
)){
1514 Error_ValueCannotBeConverted (loc
, type
, false);
1518 return Child
.ToType (type
, loc
);
1524 /// This kind of cast is used to encapsulate Value Types in objects.
1526 /// The effect of it is to box the value type emitted by the previous
1529 public class BoxedCast
: EmptyCast
{
1531 public BoxedCast (Expression expr
, Type target_type
)
1532 : base (expr
, target_type
)
1534 eclass
= ExprClass
.Value
;
1537 public override Expression
DoResolve (EmitContext ec
)
1539 // This should never be invoked, we are born in fully
1540 // initialized state.
1545 public override void Emit (EmitContext ec
)
1549 ec
.ig
.Emit (OpCodes
.Box
, child
.Type
);
1553 public class UnboxCast
: EmptyCast
{
1554 public UnboxCast (Expression expr
, Type return_type
)
1555 : base (expr
, return_type
)
1559 public override Expression
DoResolve (EmitContext ec
)
1561 // This should never be invoked, we are born in fully
1562 // initialized state.
1567 public override Expression
DoResolveLValue (EmitContext ec
, Expression right_side
)
1569 if (right_side
== EmptyExpression
.LValueMemberAccess
|| right_side
== EmptyExpression
.LValueMemberOutAccess
)
1570 Report
.Error (445, loc
, "Cannot modify the result of an unboxing conversion");
1571 return base.DoResolveLValue (ec
, right_side
);
1574 public override void Emit (EmitContext ec
)
1577 ILGenerator ig
= ec
.ig
;
1580 ig
.Emit (OpCodes
.Unbox
, t
);
1582 LoadFromPtr (ig
, t
);
1587 /// This is used to perform explicit numeric conversions.
1589 /// Explicit numeric conversions might trigger exceptions in a checked
1590 /// context, so they should generate the conv.ovf opcodes instead of
1593 public class ConvCast
: EmptyCast
{
1594 public enum Mode
: byte {
1595 I1_U1
, I1_U2
, I1_U4
, I1_U8
, I1_CH
,
1597 I2_I1
, I2_U1
, I2_U2
, I2_U4
, I2_U8
, I2_CH
,
1598 U2_I1
, U2_U1
, U2_I2
, U2_CH
,
1599 I4_I1
, I4_U1
, I4_I2
, I4_U2
, I4_U4
, I4_U8
, I4_CH
,
1600 U4_I1
, U4_U1
, U4_I2
, U4_U2
, U4_I4
, U4_CH
,
1601 I8_I1
, I8_U1
, I8_I2
, I8_U2
, I8_I4
, I8_U4
, I8_U8
, I8_CH
,
1602 U8_I1
, U8_U1
, U8_I2
, U8_U2
, U8_I4
, U8_U4
, U8_I8
, U8_CH
,
1603 CH_I1
, CH_U1
, CH_I2
,
1604 R4_I1
, R4_U1
, R4_I2
, R4_U2
, R4_I4
, R4_U4
, R4_I8
, R4_U8
, R4_CH
,
1605 R8_I1
, R8_U1
, R8_I2
, R8_U2
, R8_I4
, R8_U4
, R8_I8
, R8_U8
, R8_CH
, R8_R4
1610 public ConvCast (Expression child
, Type return_type
, Mode m
)
1611 : base (child
, return_type
)
1616 public override Expression
DoResolve (EmitContext ec
)
1618 // This should never be invoked, we are born in fully
1619 // initialized state.
1624 public override string ToString ()
1626 return String
.Format ("ConvCast ({0}, {1})", mode
, child
);
1629 public override void Emit (EmitContext ec
)
1631 ILGenerator ig
= ec
.ig
;
1637 case Mode
.I1_U1
: ig
.Emit (OpCodes
.Conv_Ovf_U1
); break;
1638 case Mode
.I1_U2
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
1639 case Mode
.I1_U4
: ig
.Emit (OpCodes
.Conv_Ovf_U4
); break;
1640 case Mode
.I1_U8
: ig
.Emit (OpCodes
.Conv_Ovf_U8
); break;
1641 case Mode
.I1_CH
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
1643 case Mode
.U1_I1
: ig
.Emit (OpCodes
.Conv_Ovf_I1_Un
); break;
1644 case Mode
.U1_CH
: /* nothing */ break;
1646 case Mode
.I2_I1
: ig
.Emit (OpCodes
.Conv_Ovf_I1
); break;
1647 case Mode
.I2_U1
: ig
.Emit (OpCodes
.Conv_Ovf_U1
); break;
1648 case Mode
.I2_U2
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
1649 case Mode
.I2_U4
: ig
.Emit (OpCodes
.Conv_Ovf_U4
); break;
1650 case Mode
.I2_U8
: ig
.Emit (OpCodes
.Conv_Ovf_U8
); break;
1651 case Mode
.I2_CH
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
1653 case Mode
.U2_I1
: ig
.Emit (OpCodes
.Conv_Ovf_I1_Un
); break;
1654 case Mode
.U2_U1
: ig
.Emit (OpCodes
.Conv_Ovf_U1_Un
); break;
1655 case Mode
.U2_I2
: ig
.Emit (OpCodes
.Conv_Ovf_I2_Un
); break;
1656 case Mode
.U2_CH
: /* nothing */ break;
1658 case Mode
.I4_I1
: ig
.Emit (OpCodes
.Conv_Ovf_I1
); break;
1659 case Mode
.I4_U1
: ig
.Emit (OpCodes
.Conv_Ovf_U1
); break;
1660 case Mode
.I4_I2
: ig
.Emit (OpCodes
.Conv_Ovf_I2
); break;
1661 case Mode
.I4_U4
: ig
.Emit (OpCodes
.Conv_Ovf_U4
); break;
1662 case Mode
.I4_U2
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
1663 case Mode
.I4_U8
: ig
.Emit (OpCodes
.Conv_Ovf_U8
); break;
1664 case Mode
.I4_CH
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
1666 case Mode
.U4_I1
: ig
.Emit (OpCodes
.Conv_Ovf_I1_Un
); break;
1667 case Mode
.U4_U1
: ig
.Emit (OpCodes
.Conv_Ovf_U1_Un
); break;
1668 case Mode
.U4_I2
: ig
.Emit (OpCodes
.Conv_Ovf_I2_Un
); break;
1669 case Mode
.U4_U2
: ig
.Emit (OpCodes
.Conv_Ovf_U2_Un
); break;
1670 case Mode
.U4_I4
: ig
.Emit (OpCodes
.Conv_Ovf_I4_Un
); break;
1671 case Mode
.U4_CH
: ig
.Emit (OpCodes
.Conv_Ovf_U2_Un
); break;
1673 case Mode
.I8_I1
: ig
.Emit (OpCodes
.Conv_Ovf_I1
); break;
1674 case Mode
.I8_U1
: ig
.Emit (OpCodes
.Conv_Ovf_U1
); break;
1675 case Mode
.I8_I2
: ig
.Emit (OpCodes
.Conv_Ovf_I2
); break;
1676 case Mode
.I8_U2
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
1677 case Mode
.I8_I4
: ig
.Emit (OpCodes
.Conv_Ovf_I4
); break;
1678 case Mode
.I8_U4
: ig
.Emit (OpCodes
.Conv_Ovf_U4
); break;
1679 case Mode
.I8_U8
: ig
.Emit (OpCodes
.Conv_Ovf_U8
); break;
1680 case Mode
.I8_CH
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
1682 case Mode
.U8_I1
: ig
.Emit (OpCodes
.Conv_Ovf_I1_Un
); break;
1683 case Mode
.U8_U1
: ig
.Emit (OpCodes
.Conv_Ovf_U1_Un
); break;
1684 case Mode
.U8_I2
: ig
.Emit (OpCodes
.Conv_Ovf_I2_Un
); break;
1685 case Mode
.U8_U2
: ig
.Emit (OpCodes
.Conv_Ovf_U2_Un
); break;
1686 case Mode
.U8_I4
: ig
.Emit (OpCodes
.Conv_Ovf_I4_Un
); break;
1687 case Mode
.U8_U4
: ig
.Emit (OpCodes
.Conv_Ovf_U4_Un
); break;
1688 case Mode
.U8_I8
: ig
.Emit (OpCodes
.Conv_Ovf_I8_Un
); break;
1689 case Mode
.U8_CH
: ig
.Emit (OpCodes
.Conv_Ovf_U2_Un
); break;
1691 case Mode
.CH_I1
: ig
.Emit (OpCodes
.Conv_Ovf_I1_Un
); break;
1692 case Mode
.CH_U1
: ig
.Emit (OpCodes
.Conv_Ovf_U1_Un
); break;
1693 case Mode
.CH_I2
: ig
.Emit (OpCodes
.Conv_Ovf_I2_Un
); break;
1695 case Mode
.R4_I1
: ig
.Emit (OpCodes
.Conv_Ovf_I1
); break;
1696 case Mode
.R4_U1
: ig
.Emit (OpCodes
.Conv_Ovf_U1
); break;
1697 case Mode
.R4_I2
: ig
.Emit (OpCodes
.Conv_Ovf_I2
); break;
1698 case Mode
.R4_U2
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
1699 case Mode
.R4_I4
: ig
.Emit (OpCodes
.Conv_Ovf_I4
); break;
1700 case Mode
.R4_U4
: ig
.Emit (OpCodes
.Conv_Ovf_U4
); break;
1701 case Mode
.R4_I8
: ig
.Emit (OpCodes
.Conv_Ovf_I8
); break;
1702 case Mode
.R4_U8
: ig
.Emit (OpCodes
.Conv_Ovf_U8
); break;
1703 case Mode
.R4_CH
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
1705 case Mode
.R8_I1
: ig
.Emit (OpCodes
.Conv_Ovf_I1
); break;
1706 case Mode
.R8_U1
: ig
.Emit (OpCodes
.Conv_Ovf_U1
); break;
1707 case Mode
.R8_I2
: ig
.Emit (OpCodes
.Conv_Ovf_I2
); break;
1708 case Mode
.R8_U2
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
1709 case Mode
.R8_I4
: ig
.Emit (OpCodes
.Conv_Ovf_I4
); break;
1710 case Mode
.R8_U4
: ig
.Emit (OpCodes
.Conv_Ovf_U4
); break;
1711 case Mode
.R8_I8
: ig
.Emit (OpCodes
.Conv_Ovf_I8
); break;
1712 case Mode
.R8_U8
: ig
.Emit (OpCodes
.Conv_Ovf_U8
); break;
1713 case Mode
.R8_CH
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
1714 case Mode
.R8_R4
: ig
.Emit (OpCodes
.Conv_R4
); break;
1718 case Mode
.I1_U1
: ig
.Emit (OpCodes
.Conv_U1
); break;
1719 case Mode
.I1_U2
: ig
.Emit (OpCodes
.Conv_U2
); break;
1720 case Mode
.I1_U4
: ig
.Emit (OpCodes
.Conv_U4
); break;
1721 case Mode
.I1_U8
: ig
.Emit (OpCodes
.Conv_I8
); break;
1722 case Mode
.I1_CH
: ig
.Emit (OpCodes
.Conv_U2
); break;
1724 case Mode
.U1_I1
: ig
.Emit (OpCodes
.Conv_I1
); break;
1725 case Mode
.U1_CH
: ig
.Emit (OpCodes
.Conv_U2
); break;
1727 case Mode
.I2_I1
: ig
.Emit (OpCodes
.Conv_I1
); break;
1728 case Mode
.I2_U1
: ig
.Emit (OpCodes
.Conv_U1
); break;
1729 case Mode
.I2_U2
: ig
.Emit (OpCodes
.Conv_U2
); break;
1730 case Mode
.I2_U4
: ig
.Emit (OpCodes
.Conv_U4
); break;
1731 case Mode
.I2_U8
: ig
.Emit (OpCodes
.Conv_I8
); break;
1732 case Mode
.I2_CH
: ig
.Emit (OpCodes
.Conv_U2
); break;
1734 case Mode
.U2_I1
: ig
.Emit (OpCodes
.Conv_I1
); break;
1735 case Mode
.U2_U1
: ig
.Emit (OpCodes
.Conv_U1
); break;
1736 case Mode
.U2_I2
: ig
.Emit (OpCodes
.Conv_I2
); break;
1737 case Mode
.U2_CH
: /* nothing */ break;
1739 case Mode
.I4_I1
: ig
.Emit (OpCodes
.Conv_I1
); break;
1740 case Mode
.I4_U1
: ig
.Emit (OpCodes
.Conv_U1
); break;
1741 case Mode
.I4_I2
: ig
.Emit (OpCodes
.Conv_I2
); break;
1742 case Mode
.I4_U4
: /* nothing */ break;
1743 case Mode
.I4_U2
: ig
.Emit (OpCodes
.Conv_U2
); break;
1744 case Mode
.I4_U8
: ig
.Emit (OpCodes
.Conv_I8
); break;
1745 case Mode
.I4_CH
: ig
.Emit (OpCodes
.Conv_U2
); break;
1747 case Mode
.U4_I1
: ig
.Emit (OpCodes
.Conv_I1
); break;
1748 case Mode
.U4_U1
: ig
.Emit (OpCodes
.Conv_U1
); break;
1749 case Mode
.U4_I2
: ig
.Emit (OpCodes
.Conv_I2
); break;
1750 case Mode
.U4_U2
: ig
.Emit (OpCodes
.Conv_U2
); break;
1751 case Mode
.U4_I4
: /* nothing */ break;
1752 case Mode
.U4_CH
: ig
.Emit (OpCodes
.Conv_U2
); break;
1754 case Mode
.I8_I1
: ig
.Emit (OpCodes
.Conv_I1
); break;
1755 case Mode
.I8_U1
: ig
.Emit (OpCodes
.Conv_U1
); break;
1756 case Mode
.I8_I2
: ig
.Emit (OpCodes
.Conv_I2
); break;
1757 case Mode
.I8_U2
: ig
.Emit (OpCodes
.Conv_U2
); break;
1758 case Mode
.I8_I4
: ig
.Emit (OpCodes
.Conv_I4
); break;
1759 case Mode
.I8_U4
: ig
.Emit (OpCodes
.Conv_U4
); break;
1760 case Mode
.I8_U8
: /* nothing */ break;
1761 case Mode
.I8_CH
: ig
.Emit (OpCodes
.Conv_U2
); break;
1763 case Mode
.U8_I1
: ig
.Emit (OpCodes
.Conv_I1
); break;
1764 case Mode
.U8_U1
: ig
.Emit (OpCodes
.Conv_U1
); break;
1765 case Mode
.U8_I2
: ig
.Emit (OpCodes
.Conv_I2
); break;
1766 case Mode
.U8_U2
: ig
.Emit (OpCodes
.Conv_U2
); break;
1767 case Mode
.U8_I4
: ig
.Emit (OpCodes
.Conv_I4
); break;
1768 case Mode
.U8_U4
: ig
.Emit (OpCodes
.Conv_U4
); break;
1769 case Mode
.U8_I8
: /* nothing */ break;
1770 case Mode
.U8_CH
: ig
.Emit (OpCodes
.Conv_U2
); break;
1772 case Mode
.CH_I1
: ig
.Emit (OpCodes
.Conv_I1
); break;
1773 case Mode
.CH_U1
: ig
.Emit (OpCodes
.Conv_U1
); break;
1774 case Mode
.CH_I2
: ig
.Emit (OpCodes
.Conv_I2
); break;
1776 case Mode
.R4_I1
: ig
.Emit (OpCodes
.Conv_I1
); break;
1777 case Mode
.R4_U1
: ig
.Emit (OpCodes
.Conv_U1
); break;
1778 case Mode
.R4_I2
: ig
.Emit (OpCodes
.Conv_I2
); break;
1779 case Mode
.R4_U2
: ig
.Emit (OpCodes
.Conv_U2
); break;
1780 case Mode
.R4_I4
: ig
.Emit (OpCodes
.Conv_I4
); break;
1781 case Mode
.R4_U4
: ig
.Emit (OpCodes
.Conv_U4
); break;
1782 case Mode
.R4_I8
: ig
.Emit (OpCodes
.Conv_I8
); break;
1783 case Mode
.R4_U8
: ig
.Emit (OpCodes
.Conv_U8
); break;
1784 case Mode
.R4_CH
: ig
.Emit (OpCodes
.Conv_U2
); break;
1786 case Mode
.R8_I1
: ig
.Emit (OpCodes
.Conv_I1
); break;
1787 case Mode
.R8_U1
: ig
.Emit (OpCodes
.Conv_U1
); break;
1788 case Mode
.R8_I2
: ig
.Emit (OpCodes
.Conv_I2
); break;
1789 case Mode
.R8_U2
: ig
.Emit (OpCodes
.Conv_U2
); break;
1790 case Mode
.R8_I4
: ig
.Emit (OpCodes
.Conv_I4
); break;
1791 case Mode
.R8_U4
: ig
.Emit (OpCodes
.Conv_U4
); break;
1792 case Mode
.R8_I8
: ig
.Emit (OpCodes
.Conv_I8
); break;
1793 case Mode
.R8_U8
: ig
.Emit (OpCodes
.Conv_U8
); break;
1794 case Mode
.R8_CH
: ig
.Emit (OpCodes
.Conv_U2
); break;
1795 case Mode
.R8_R4
: ig
.Emit (OpCodes
.Conv_R4
); break;
1801 public class OpcodeCast
: EmptyCast
{
1805 public OpcodeCast (Expression child
, Type return_type
, OpCode op
)
1806 : base (child
, return_type
)
1810 second_valid
= false;
1813 public OpcodeCast (Expression child
, Type return_type
, OpCode op
, OpCode op2
)
1814 : base (child
, return_type
)
1819 second_valid
= true;
1822 public override Expression
DoResolve (EmitContext ec
)
1824 // This should never be invoked, we are born in fully
1825 // initialized state.
1830 public override void Emit (EmitContext ec
)
1841 /// This kind of cast is used to encapsulate a child and cast it
1842 /// to the class requested
1844 public class ClassCast
: EmptyCast
{
1845 public ClassCast (Expression child
, Type return_type
)
1846 : base (child
, return_type
)
1851 public override Expression
DoResolve (EmitContext ec
)
1853 // This should never be invoked, we are born in fully
1854 // initialized state.
1859 public override void Emit (EmitContext ec
)
1863 ec
.ig
.Emit (OpCodes
.Castclass
, type
);
1869 /// SimpleName expressions are formed of a single word and only happen at the beginning
1870 /// of a dotted-name.
1872 public class SimpleName
: Expression
{
1876 public SimpleName (string name
, Location l
)
1882 public static void Error_ObjectRefRequired (EmitContext ec
, Location l
, string name
)
1884 if (ec
.IsFieldInitializer
)
1885 Report
.Error (236, l
,
1886 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
1890 120, l
, "`{0}': An object reference is required for the nonstatic field, method or property",
1894 public bool IdenticalNameAndTypeName (EmitContext ec
, Expression resolved_to
, Location loc
)
1896 return resolved_to
!= null && resolved_to
.Type
!= null &&
1897 resolved_to
.Type
.Name
== Name
&&
1898 (ec
.DeclContainer
.LookupType (Name
, loc
, /* ignore_cs0104 = */ true) != null);
1901 public override Expression
DoResolve (EmitContext ec
)
1903 return SimpleNameResolve (ec
, null, false);
1906 public override Expression
DoResolveLValue (EmitContext ec
, Expression right_side
)
1908 return SimpleNameResolve (ec
, right_side
, false);
1912 public Expression
DoResolve (EmitContext ec
, bool intermediate
)
1914 return SimpleNameResolve (ec
, null, intermediate
);
1917 public override FullNamedExpression
ResolveAsTypeStep (IResolveContext ec
, bool silent
)
1919 int errors
= Report
.Errors
;
1920 FullNamedExpression fne
= ec
.DeclContainer
.LookupType (Name
, loc
, /*ignore_cs0104=*/ false);
1924 if (silent
|| errors
!= Report
.Errors
)
1927 MemberCore mc
= ec
.DeclContainer
.GetDefinition (Name
);
1929 Error_UnexpectedKind (ec
.DeclContainer
, "type", GetMemberType (mc
), loc
);
1933 string ns
= ec
.DeclContainer
.NamespaceEntry
.NS
.Name
;
1934 string fullname
= (ns
.Length
> 0) ? ns
+ "." + Name
: Name
;
1935 foreach (Assembly a
in RootNamespace
.Global
.Assemblies
) {
1936 Type type
= a
.GetType (fullname
);
1938 Report
.SymbolRelatedToPreviousError (type
);
1939 Expression
.ErrorIsInaccesible (loc
, fullname
);
1944 NamespaceEntry
.Error_NamespaceNotFound (loc
, Name
);
1948 // TODO: I am still not convinced about this. If someone else will need it
1949 // implement this as virtual property in MemberCore hierarchy
1950 string GetMemberType (MemberCore mc
)
1952 if (mc
is PropertyBase
)
1956 if (mc
is FieldBase
)
1958 if (mc
is MethodCore
)
1960 if (mc
is EnumMember
)
1966 Expression
SimpleNameResolve (EmitContext ec
, Expression right_side
, bool intermediate
)
1972 Expression e
= DoSimpleNameResolve (ec
, right_side
, intermediate
);
1976 if (ec
.CurrentBlock
== null || ec
.CurrentBlock
.CheckInvariantMeaningInBlock (Name
, e
, Location
))
1983 /// 7.5.2: Simple Names.
1985 /// Local Variables and Parameters are handled at
1986 /// parse time, so they never occur as SimpleNames.
1988 /// The `intermediate' flag is used by MemberAccess only
1989 /// and it is used to inform us that it is ok for us to
1990 /// avoid the static check, because MemberAccess might end
1991 /// up resolving the Name as a Type name and the access as
1992 /// a static type access.
1994 /// ie: Type Type; .... { Type.GetType (""); }
1996 /// Type is both an instance variable and a Type; Type.GetType
1997 /// is the static method not an instance method of type.
1999 Expression
DoSimpleNameResolve (EmitContext ec
, Expression right_side
, bool intermediate
)
2001 Expression e
= null;
2004 // Stage 1: Performed by the parser (binding to locals or parameters).
2006 Block current_block
= ec
.CurrentBlock
;
2007 if (current_block
!= null){
2008 LocalInfo vi
= current_block
.GetLocalInfo (Name
);
2010 LocalVariableReference
var = new LocalVariableReference (ec
.CurrentBlock
, Name
, loc
);
2011 if (right_side
!= null) {
2012 return var.ResolveLValue (ec
, right_side
, loc
);
2014 ResolveFlags rf
= ResolveFlags
.VariableOrValue
;
2016 rf
|= ResolveFlags
.DisableFlowAnalysis
;
2017 return var.Resolve (ec
, rf
);
2021 ParameterReference pref
= current_block
.Toplevel
.GetParameterReference (Name
, loc
);
2023 if (right_side
!= null)
2024 return pref
.ResolveLValue (ec
, right_side
, loc
);
2026 return pref
.Resolve (ec
);
2031 // Stage 2: Lookup members
2034 DeclSpace lookup_ds
= ec
.DeclContainer
;
2035 Type almost_matched_type
= null;
2036 ArrayList almost_matched
= null;
2038 if (lookup_ds
.TypeBuilder
== null)
2041 e
= MemberLookup (ec
.ContainerType
, lookup_ds
.TypeBuilder
, Name
, loc
);
2045 if (almost_matched
== null && almostMatchedMembers
.Count
> 0) {
2046 almost_matched_type
= lookup_ds
.TypeBuilder
;
2047 almost_matched
= (ArrayList
) almostMatchedMembers
.Clone ();
2050 lookup_ds
=lookup_ds
.Parent
;
2051 } while (lookup_ds
!= null);
2053 if (e
== null && ec
.ContainerType
!= null)
2054 e
= MemberLookup (ec
.ContainerType
, ec
.ContainerType
, Name
, loc
);
2057 if (almost_matched
== null && almostMatchedMembers
.Count
> 0) {
2058 almost_matched_type
= ec
.ContainerType
;
2059 almost_matched
= (ArrayList
) almostMatchedMembers
.Clone ();
2061 e
= ResolveAsTypeStep (ec
, true);
2065 if (almost_matched
!= null)
2066 almostMatchedMembers
= almost_matched
;
2067 if (almost_matched_type
== null)
2068 almost_matched_type
= ec
.ContainerType
;
2069 MemberLookupFailed (ec
.ContainerType
, null, almost_matched_type
, ((SimpleName
) this).Name
, ec
.DeclContainer
.Name
, true, loc
);
2076 if (e
is MemberExpr
) {
2077 MemberExpr me
= (MemberExpr
) e
;
2080 if (me
.IsInstance
) {
2081 if (ec
.IsStatic
|| ec
.IsFieldInitializer
) {
2083 // Note that an MemberExpr can be both IsInstance and IsStatic.
2084 // An unresolved MethodGroupExpr can contain both kinds of methods
2085 // and each predicate is true if the MethodGroupExpr contains
2086 // at least one of that kind of method.
2090 (!intermediate
|| !IdenticalNameAndTypeName (ec
, me
, loc
))) {
2091 Error_ObjectRefRequired (ec
, loc
, me
.GetSignatureForError ());
2092 return EmptyExpression
.Null
;
2096 // Pass the buck to MemberAccess and Invocation.
2098 left
= EmptyExpression
.Null
;
2100 left
= ec
.GetThis (loc
);
2103 left
= new TypeExpression (ec
.ContainerType
, loc
);
2106 e
= me
.ResolveMemberAccess (ec
, left
, loc
, null);
2110 me
= e
as MemberExpr
;
2115 TypeManager
.IsNestedFamilyAccessible (me
.InstanceExpression
.Type
, me
.DeclaringType
) &&
2116 me
.InstanceExpression
.Type
!= me
.DeclaringType
&&
2117 !me
.InstanceExpression
.Type
.IsSubclassOf (me
.DeclaringType
) &&
2118 (!intermediate
|| !IdenticalNameAndTypeName (ec
, e
, loc
))) {
2119 Report
.Error (38, loc
, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2120 TypeManager
.CSharpName (me
.DeclaringType
), TypeManager
.CSharpName (me
.InstanceExpression
.Type
));
2124 return (right_side
!= null)
2125 ? me
.DoResolveLValue (ec
, right_side
)
2126 : me
.DoResolve (ec
);
2132 public override void Emit (EmitContext ec
)
2135 // If this is ever reached, then we failed to
2136 // find the name as a namespace
2139 Error (103, "The name `" + Name
+
2140 "' does not exist in the class `" +
2141 ec
.DeclContainer
.Name
+ "'");
2144 public override string ToString ()
2149 public override string GetSignatureForError ()
2156 /// Represents a namespace or a type. The name of the class was inspired by
2157 /// section 10.8.1 (Fully Qualified Names).
2159 public abstract class FullNamedExpression
: Expression
{
2160 public override FullNamedExpression
ResolveAsTypeStep (IResolveContext ec
, bool silent
)
2165 public abstract string FullName
{
2171 /// Expression that evaluates to a type
2173 public abstract class TypeExpr
: FullNamedExpression
{
2174 override public FullNamedExpression
ResolveAsTypeStep (IResolveContext ec
, bool silent
)
2176 TypeExpr t
= DoResolveAsTypeStep (ec
);
2180 eclass
= ExprClass
.Type
;
2184 override public Expression
DoResolve (EmitContext ec
)
2186 return ResolveAsTypeTerminal (ec
, false);
2189 override public void Emit (EmitContext ec
)
2191 throw new Exception ("Should never be called");
2194 public virtual bool CheckAccessLevel (DeclSpace ds
)
2196 return ds
.CheckAccessLevel (Type
);
2199 public virtual bool AsAccessible (DeclSpace ds
, int flags
)
2201 return ds
.AsAccessible (Type
, flags
);
2204 public virtual bool IsClass
{
2205 get { return Type.IsClass; }
2208 public virtual bool IsValueType
{
2209 get { return Type.IsValueType; }
2212 public virtual bool IsInterface
{
2213 get { return Type.IsInterface; }
2216 public virtual bool IsSealed
{
2217 get { return Type.IsSealed; }
2220 public virtual bool CanInheritFrom ()
2222 if (Type
== TypeManager
.enum_type
||
2223 (Type
== TypeManager
.value_type
&& RootContext
.StdLib
) ||
2224 Type
== TypeManager
.multicast_delegate_type
||
2225 Type
== TypeManager
.delegate_type
||
2226 Type
== TypeManager
.array_type
)
2232 protected abstract TypeExpr
DoResolveAsTypeStep (IResolveContext ec
);
2234 public abstract string Name
{
2238 public override bool Equals (object obj
)
2240 TypeExpr tobj
= obj
as TypeExpr
;
2244 return Type
== tobj
.Type
;
2247 public override int GetHashCode ()
2249 return Type
.GetHashCode ();
2252 public override string ToString ()
2259 /// Fully resolved Expression that already evaluated to a type
2261 public class TypeExpression
: TypeExpr
{
2262 public TypeExpression (Type t
, Location l
)
2265 eclass
= ExprClass
.Type
;
2269 protected override TypeExpr
DoResolveAsTypeStep (IResolveContext ec
)
2274 public override TypeExpr
ResolveAsTypeTerminal (IResolveContext ec
, bool silent
)
2279 public override string Name
{
2280 get { return Type.ToString (); }
2283 public override string FullName
{
2284 get { return Type.FullName; }
2289 /// Used to create types from a fully qualified name. These are just used
2290 /// by the parser to setup the core types. A TypeLookupExpression is always
2291 /// classified as a type.
2293 public sealed class TypeLookupExpression
: TypeExpr
{
2294 readonly string name
;
2296 public TypeLookupExpression (string name
)
2299 eclass
= ExprClass
.Type
;
2302 public override TypeExpr
ResolveAsTypeTerminal (IResolveContext ec
, bool silent
)
2304 // It's null for corlib compilation only
2306 return DoResolveAsTypeStep (ec
);
2311 static readonly char [] dot_array
= { '.' }
;
2312 protected override TypeExpr
DoResolveAsTypeStep (IResolveContext ec
)
2314 // If name is of the form `N.I', first lookup `N', then search a member `I' in it.
2316 string lookup_name
= name
;
2317 int pos
= name
.IndexOf ('.');
2319 rest
= name
.Substring (pos
+ 1);
2320 lookup_name
= name
.Substring (0, pos
);
2323 FullNamedExpression resolved
= RootNamespace
.Global
.Lookup (ec
.DeclContainer
, lookup_name
, Location
.Null
);
2325 if (resolved
!= null && rest
!= null) {
2326 // Now handle the rest of the the name.
2327 string [] elements
= rest
.Split (dot_array
);
2329 int count
= elements
.Length
;
2331 while (i
< count
&& resolved
!= null && resolved
is Namespace
) {
2332 Namespace ns
= resolved
as Namespace
;
2333 element
= elements
[i
++];
2334 lookup_name
+= "." + element
;
2335 resolved
= ns
.Lookup (ec
.DeclContainer
, element
, Location
.Null
);
2338 if (resolved
!= null && resolved
is TypeExpr
) {
2339 Type t
= ((TypeExpr
) resolved
).Type
;
2341 if (!ec
.DeclContainer
.CheckAccessLevel (t
)) {
2343 lookup_name
= t
.FullName
;
2350 t
= TypeManager
.GetNestedType (t
, elements
[i
++]);
2355 if (resolved
== null) {
2356 NamespaceEntry
.Error_NamespaceNotFound (loc
, lookup_name
);
2360 if (!(resolved
is TypeExpr
)) {
2361 resolved
.Error_UnexpectedKind (ec
.DeclContainer
, "type", loc
);
2365 type
= resolved
.Type
;
2369 public override string Name
{
2370 get { return name; }
2373 public override string FullName
{
2374 get { return name; }
2378 public class TypeAliasExpression
: TypeExpr
{
2381 public TypeAliasExpression (TypeExpr texpr
, Location l
)
2384 loc
= texpr
.Location
;
2386 eclass
= ExprClass
.Type
;
2389 public override string Name
{
2390 get { return texpr.Name; }
2393 public override string FullName
{
2394 get { return texpr.FullName; }
2397 protected override TypeExpr
DoResolveAsTypeStep (IResolveContext ec
)
2402 public override bool CheckAccessLevel (DeclSpace ds
)
2404 return texpr
.CheckAccessLevel (ds
);
2407 public override bool AsAccessible (DeclSpace ds
, int flags
)
2409 return texpr
.AsAccessible (ds
, flags
);
2412 public override bool IsClass
{
2413 get { return texpr.IsClass; }
2416 public override bool IsValueType
{
2417 get { return texpr.IsValueType; }
2420 public override bool IsInterface
{
2421 get { return texpr.IsInterface; }
2424 public override bool IsSealed
{
2425 get { return texpr.IsSealed; }
2430 /// This class denotes an expression which evaluates to a member
2431 /// of a struct or a class.
2433 public abstract class MemberExpr
: Expression
2436 /// The name of this member.
2438 public abstract string Name
{
2443 /// Whether this is an instance member.
2445 public abstract bool IsInstance
{
2450 /// Whether this is a static member.
2452 public abstract bool IsStatic
{
2457 /// The type which declares this member.
2459 public abstract Type DeclaringType
{
2464 /// The instance expression associated with this member, if it's a
2465 /// non-static member.
2467 public Expression InstanceExpression
;
2469 public static void error176 (Location loc
, string name
)
2471 Report
.Error (176, loc
, "Static member `{0}' cannot be accessed " +
2472 "with an instance reference, qualify it with a type name instead", name
);
2475 // TODO: possible optimalization
2476 // Cache resolved constant result in FieldBuilder <-> expression map
2477 public virtual Expression
ResolveMemberAccess (EmitContext ec
, Expression left
, Location loc
,
2478 SimpleName original
)
2482 // original == null || original.Resolve (...) ==> left
2485 if (left
is TypeExpr
) {
2487 SimpleName
.Error_ObjectRefRequired (ec
, loc
, GetSignatureForError ());
2495 if (original
!= null && original
.IdenticalNameAndTypeName (ec
, left
, loc
))
2498 error176 (loc
, GetSignatureForError ());
2502 InstanceExpression
= left
;
2507 protected void EmitInstance (EmitContext ec
, bool prepare_for_load
)
2512 if (InstanceExpression
== EmptyExpression
.Null
) {
2513 SimpleName
.Error_ObjectRefRequired (ec
, loc
, GetSignatureForError ());
2517 if (InstanceExpression
.Type
.IsValueType
) {
2518 if (InstanceExpression
is IMemoryLocation
) {
2519 ((IMemoryLocation
) InstanceExpression
).AddressOf (ec
, AddressOp
.LoadStore
);
2521 LocalTemporary t
= new LocalTemporary (InstanceExpression
.Type
);
2522 InstanceExpression
.Emit (ec
);
2524 t
.AddressOf (ec
, AddressOp
.Store
);
2527 InstanceExpression
.Emit (ec
);
2529 if (prepare_for_load
)
2530 ec
.ig
.Emit (OpCodes
.Dup
);
2535 /// MethodGroup Expression.
2537 /// This is a fully resolved expression that evaluates to a type
2539 public class MethodGroupExpr
: MemberExpr
{
2540 public MethodBase
[] Methods
;
2541 bool identical_type_name
= false;
2544 public MethodGroupExpr (MemberInfo
[] mi
, Location l
)
2546 Methods
= new MethodBase
[mi
.Length
];
2547 mi
.CopyTo (Methods
, 0);
2548 eclass
= ExprClass
.MethodGroup
;
2549 type
= TypeManager
.object_type
;
2553 public MethodGroupExpr (ArrayList list
, Location l
)
2555 Methods
= new MethodBase
[list
.Count
];
2558 list
.CopyTo (Methods
, 0);
2560 foreach (MemberInfo m
in list
){
2561 if (!(m
is MethodBase
)){
2562 Console
.WriteLine ("Name " + m
.Name
);
2563 Console
.WriteLine ("Found a: " + m
.GetType ().FullName
);
2570 eclass
= ExprClass
.MethodGroup
;
2571 type
= TypeManager
.object_type
;
2574 public override Type DeclaringType
{
2577 // The methods are arranged in this order:
2578 // derived type -> base type
2580 return Methods
[0].DeclaringType
;
2584 public bool IdenticalTypeName
{
2586 return identical_type_name
;
2590 identical_type_name
= value;
2594 public bool IsBase
{
2603 public override string GetSignatureForError ()
2605 return TypeManager
.CSharpSignature (Methods
[0]);
2608 public override string Name
{
2610 return Methods
[0].Name
;
2614 public override bool IsInstance
{
2616 foreach (MethodBase mb
in Methods
)
2624 public override bool IsStatic
{
2626 foreach (MethodBase mb
in Methods
)
2634 public override Expression
ResolveMemberAccess (EmitContext ec
, Expression left
, Location loc
,
2635 SimpleName original
)
2637 if (!(left
is TypeExpr
) &&
2638 original
!= null && original
.IdenticalNameAndTypeName (ec
, left
, loc
))
2639 IdenticalTypeName
= true;
2641 return base.ResolveMemberAccess (ec
, left
, loc
, original
);
2644 override public Expression
DoResolve (EmitContext ec
)
2647 InstanceExpression
= null;
2649 if (InstanceExpression
!= null) {
2650 InstanceExpression
= InstanceExpression
.DoResolve (ec
);
2651 if (InstanceExpression
== null)
2658 public void ReportUsageError ()
2660 Report
.Error (654, loc
, "Method `" + DeclaringType
+ "." +
2661 Name
+ "()' is referenced without parentheses");
2664 override public void Emit (EmitContext ec
)
2666 ReportUsageError ();
2669 bool RemoveMethods (bool keep_static
)
2671 ArrayList smethods
= new ArrayList ();
2673 foreach (MethodBase mb
in Methods
){
2674 if (mb
.IsStatic
== keep_static
)
2678 if (smethods
.Count
== 0)
2681 Methods
= new MethodBase
[smethods
.Count
];
2682 smethods
.CopyTo (Methods
, 0);
2688 /// Removes any instance methods from the MethodGroup, returns
2689 /// false if the resulting set is empty.
2691 public bool RemoveInstanceMethods ()
2693 return RemoveMethods (true);
2697 /// Removes any static methods from the MethodGroup, returns
2698 /// false if the resulting set is empty.
2700 public bool RemoveStaticMethods ()
2702 return RemoveMethods (false);
2707 /// Fully resolved expression that evaluates to a Field
2709 public class FieldExpr
: MemberExpr
, IAssignMethod
, IMemoryLocation
, IVariable
{
2710 public readonly FieldInfo FieldInfo
;
2711 VariableInfo variable_info
;
2713 LocalTemporary temp
;
2715 bool in_initializer
;
2717 public FieldExpr (FieldInfo fi
, Location l
, bool in_initializer
):
2720 this.in_initializer
= in_initializer
;
2723 public FieldExpr (FieldInfo fi
, Location l
)
2726 eclass
= ExprClass
.Variable
;
2727 type
= fi
.FieldType
;
2731 public override string Name
{
2733 return FieldInfo
.Name
;
2737 public override bool IsInstance
{
2739 return !FieldInfo
.IsStatic
;
2743 public override bool IsStatic
{
2745 return FieldInfo
.IsStatic
;
2749 public override Type DeclaringType
{
2751 return FieldInfo
.DeclaringType
;
2755 public override string GetSignatureForError ()
2757 return TypeManager
.GetFullNameSignature (FieldInfo
);
2760 public VariableInfo VariableInfo
{
2762 return variable_info
;
2766 public override Expression
ResolveMemberAccess (EmitContext ec
, Expression left
, Location loc
,
2767 SimpleName original
)
2769 Type t
= FieldInfo
.FieldType
;
2771 if (FieldInfo
.IsLiteral
|| (FieldInfo
.IsInitOnly
&& t
== TypeManager
.decimal_type
)) {
2772 IConstant ic
= TypeManager
.GetConstant (FieldInfo
);
2774 if (FieldInfo
.IsLiteral
) {
2775 ic
= new ExternalConstant (FieldInfo
);
2777 ic
= ExternalConstant
.CreateDecimal (FieldInfo
);
2779 return base.ResolveMemberAccess (ec
, left
, loc
, original
);
2782 TypeManager
.RegisterConstant (FieldInfo
, ic
);
2785 bool left_is_type
= left
is TypeExpr
;
2786 if (!left_is_type
&& (original
== null || !original
.IdenticalNameAndTypeName (ec
, left
, loc
))) {
2787 Report
.SymbolRelatedToPreviousError (FieldInfo
);
2788 error176 (loc
, TypeManager
.GetFullNameSignature (FieldInfo
));
2792 if (ic
.ResolveValue ()) {
2793 if (!ec
.IsInObsoleteScope
)
2794 ic
.CheckObsoleteness (loc
);
2800 if (t
.IsPointer
&& !ec
.InUnsafe
) {
2805 return base.ResolveMemberAccess (ec
, left
, loc
, original
);
2808 override public Expression
DoResolve (EmitContext ec
)
2810 return DoResolve (ec
, false, false);
2813 Expression
DoResolve (EmitContext ec
, bool lvalue_instance
, bool out_access
)
2815 if (!FieldInfo
.IsStatic
){
2816 if (InstanceExpression
== null){
2818 // This can happen when referencing an instance field using
2819 // a fully qualified type expression: TypeName.InstanceField = xxx
2821 SimpleName
.Error_ObjectRefRequired (ec
, loc
, GetSignatureForError ());
2825 // Resolve the field's instance expression while flow analysis is turned
2826 // off: when accessing a field "a.b", we must check whether the field
2827 // "a.b" is initialized, not whether the whole struct "a" is initialized.
2829 if (lvalue_instance
) {
2830 using (ec
.With (EmitContext
.Flags
.DoFlowAnalysis
, false)) {
2831 Expression right_side
=
2832 out_access
? EmptyExpression
.LValueMemberOutAccess
: EmptyExpression
.LValueMemberAccess
;
2833 InstanceExpression
= InstanceExpression
.ResolveLValue (ec
, right_side
, loc
);
2836 ResolveFlags rf
= ResolveFlags
.VariableOrValue
| ResolveFlags
.DisableFlowAnalysis
;
2837 InstanceExpression
= InstanceExpression
.Resolve (ec
, rf
);
2840 if (InstanceExpression
== null)
2843 InstanceExpression
.CheckMarshalByRefAccess ();
2846 if (!in_initializer
&& !ec
.IsFieldInitializer
) {
2847 ObsoleteAttribute oa
;
2848 FieldBase f
= TypeManager
.GetField (FieldInfo
);
2850 if (!ec
.IsInObsoleteScope
)
2851 f
.CheckObsoleteness (loc
);
2853 // To be sure that type is external because we do not register generated fields
2854 } else if (!(FieldInfo
.DeclaringType
is TypeBuilder
)) {
2855 oa
= AttributeTester
.GetMemberObsoleteAttribute (FieldInfo
);
2857 AttributeTester
.Report_ObsoleteMessage (oa
, TypeManager
.GetFullNameSignature (FieldInfo
), loc
);
2861 AnonymousContainer am
= ec
.CurrentAnonymousMethod
;
2863 if (!FieldInfo
.IsStatic
){
2864 if (!am
.IsIterator
&& (ec
.TypeContainer
is Struct
)){
2865 Report
.Error (1673, loc
,
2866 "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",
2870 if ((am
.ContainerAnonymousMethod
== null) && (InstanceExpression
is This
))
2871 ec
.CaptureField (this);
2875 // If the instance expression is a local variable or parameter.
2876 IVariable
var = InstanceExpression
as IVariable
;
2877 if ((var == null) || (var.VariableInfo
== null))
2880 VariableInfo vi
= var.VariableInfo
;
2881 if (!vi
.IsFieldAssigned (ec
, FieldInfo
.Name
, loc
))
2884 variable_info
= vi
.GetSubStruct (FieldInfo
.Name
);
2888 static readonly int [] codes
= {
2889 191, // instance, write access
2890 192, // instance, out access
2891 198, // static, write access
2892 199, // static, out access
2893 1648, // member of value instance, write access
2894 1649, // member of value instance, out access
2895 1650, // member of value static, write access
2896 1651 // member of value static, out access
2899 static readonly string [] msgs
= {
2900 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
2901 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
2902 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
2903 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
2904 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
2905 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
2906 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
2907 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
2910 // The return value is always null. Returning a value simplifies calling code.
2911 Expression
Report_AssignToReadonly (Expression right_side
)
2914 if (right_side
== EmptyExpression
.OutAccess
|| right_side
== EmptyExpression
.LValueMemberOutAccess
)
2918 if (right_side
== EmptyExpression
.LValueMemberAccess
|| right_side
== EmptyExpression
.LValueMemberOutAccess
)
2920 Report
.Error (codes
[i
], loc
, msgs
[i
], GetSignatureForError ());
2925 override public Expression
DoResolveLValue (EmitContext ec
, Expression right_side
)
2927 IVariable
var = InstanceExpression
as IVariable
;
2928 if ((var != null) && (var.VariableInfo
!= null))
2929 var.VariableInfo
.SetFieldAssigned (ec
, FieldInfo
.Name
);
2931 bool lvalue_instance
= !FieldInfo
.IsStatic
&& FieldInfo
.DeclaringType
.IsValueType
;
2932 bool out_access
= right_side
== EmptyExpression
.OutAccess
|| right_side
== EmptyExpression
.LValueMemberOutAccess
;
2934 Expression e
= DoResolve (ec
, lvalue_instance
, out_access
);
2939 FieldBase fb
= TypeManager
.GetField (FieldInfo
);
2943 if (FieldInfo
.IsInitOnly
) {
2944 // InitOnly fields can only be assigned in constructors or initializers
2945 if (!ec
.IsFieldInitializer
&& !ec
.IsConstructor
)
2946 return Report_AssignToReadonly (right_side
);
2948 if (ec
.IsConstructor
) {
2949 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
2950 if (ec
.ContainerType
!= FieldInfo
.DeclaringType
)
2951 return Report_AssignToReadonly (right_side
);
2952 // static InitOnly fields cannot be assigned-to in an instance constructor
2953 if (IsStatic
&& !ec
.IsStatic
)
2954 return Report_AssignToReadonly (right_side
);
2955 // instance constructors can't modify InitOnly fields of other instances of the same type
2956 if (!IsStatic
&& !(InstanceExpression
is This
))
2957 return Report_AssignToReadonly (right_side
);
2961 if (right_side
== EmptyExpression
.OutAccess
&&
2962 !IsStatic
&& !(InstanceExpression
is This
) && DeclaringType
.IsSubclassOf (TypeManager
.mbr_type
)) {
2963 Report
.SymbolRelatedToPreviousError (DeclaringType
);
2964 Report
.Warning (197, 1, loc
,
2965 "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",
2966 GetSignatureForError ());
2972 public override void CheckMarshalByRefAccess ()
2974 if (!IsStatic
&& Type
.IsValueType
&& !(InstanceExpression
is This
) && DeclaringType
.IsSubclassOf (TypeManager
.mbr_type
)) {
2975 Report
.SymbolRelatedToPreviousError (DeclaringType
);
2976 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",
2977 GetSignatureForError ());
2981 public bool VerifyFixed ()
2983 IVariable variable
= InstanceExpression
as IVariable
;
2984 // A variable of the form V.I is fixed when V is a fixed variable of a struct type.
2985 // We defer the InstanceExpression check after the variable check to avoid a
2986 // separate null check on InstanceExpression.
2987 return variable
!= null && InstanceExpression
.Type
.IsValueType
&& variable
.VerifyFixed ();
2990 public override int GetHashCode ()
2992 return FieldInfo
.GetHashCode ();
2995 public override bool Equals (object obj
)
2997 FieldExpr fe
= obj
as FieldExpr
;
3001 if (FieldInfo
!= fe
.FieldInfo
)
3004 if (InstanceExpression
== null || fe
.InstanceExpression
== null)
3007 return InstanceExpression
.Equals (fe
.InstanceExpression
);
3010 public void Emit (EmitContext ec
, bool leave_copy
)
3012 ILGenerator ig
= ec
.ig
;
3013 bool is_volatile
= false;
3015 FieldBase f
= TypeManager
.GetField (FieldInfo
);
3017 if ((f
.ModFlags
& Modifiers
.VOLATILE
) != 0)
3020 f
.SetMemberIsUsed ();
3023 if (FieldInfo
.IsStatic
){
3025 ig
.Emit (OpCodes
.Volatile
);
3027 ig
.Emit (OpCodes
.Ldsfld
, FieldInfo
);
3030 EmitInstance (ec
, false);
3033 ig
.Emit (OpCodes
.Volatile
);
3035 IFixedBuffer ff
= AttributeTester
.GetFixedBuffer (FieldInfo
);
3038 ig
.Emit (OpCodes
.Ldflda
, FieldInfo
);
3039 ig
.Emit (OpCodes
.Ldflda
, ff
.Element
);
3042 ig
.Emit (OpCodes
.Ldfld
, FieldInfo
);
3047 ec
.ig
.Emit (OpCodes
.Dup
);
3048 if (!FieldInfo
.IsStatic
) {
3049 temp
= new LocalTemporary (this.Type
);
3055 public void EmitAssign (EmitContext ec
, Expression source
, bool leave_copy
, bool prepare_for_load
)
3057 FieldAttributes fa
= FieldInfo
.Attributes
;
3058 bool is_static
= (fa
& FieldAttributes
.Static
) != 0;
3059 bool is_readonly
= (fa
& FieldAttributes
.InitOnly
) != 0;
3060 ILGenerator ig
= ec
.ig
;
3061 prepared
= prepare_for_load
;
3063 if (is_readonly
&& !ec
.IsConstructor
){
3064 Report_AssignToReadonly (source
);
3068 EmitInstance (ec
, prepare_for_load
);
3072 ec
.ig
.Emit (OpCodes
.Dup
);
3073 if (!FieldInfo
.IsStatic
) {
3074 temp
= new LocalTemporary (this.Type
);
3079 if (FieldInfo
is FieldBuilder
){
3080 FieldBase f
= TypeManager
.GetField (FieldInfo
);
3082 if ((f
.ModFlags
& Modifiers
.VOLATILE
) != 0)
3083 ig
.Emit (OpCodes
.Volatile
);
3090 ig
.Emit (OpCodes
.Stsfld
, FieldInfo
);
3092 ig
.Emit (OpCodes
.Stfld
, FieldInfo
);
3100 public override void Emit (EmitContext ec
)
3105 public void AddressOf (EmitContext ec
, AddressOp mode
)
3107 ILGenerator ig
= ec
.ig
;
3109 if (FieldInfo
is FieldBuilder
){
3110 FieldBase f
= TypeManager
.GetField (FieldInfo
);
3112 if ((f
.ModFlags
& Modifiers
.VOLATILE
) != 0){
3113 Report
.Warning (420, 1, loc
, "`{0}': A volatile fields cannot be passed using a ref or out parameter",
3114 f
.GetSignatureForError ());
3118 if ((mode
& AddressOp
.Store
) != 0)
3120 if ((mode
& AddressOp
.Load
) != 0)
3121 f
.SetMemberIsUsed ();
3126 // Handle initonly fields specially: make a copy and then
3127 // get the address of the copy.
3130 if (FieldInfo
.IsInitOnly
){
3132 if (ec
.IsConstructor
){
3133 if (FieldInfo
.IsStatic
){
3145 local
= ig
.DeclareLocal (type
);
3146 ig
.Emit (OpCodes
.Stloc
, local
);
3147 ig
.Emit (OpCodes
.Ldloca
, local
);
3152 if (FieldInfo
.IsStatic
){
3153 ig
.Emit (OpCodes
.Ldsflda
, FieldInfo
);
3155 EmitInstance (ec
, false);
3156 ig
.Emit (OpCodes
.Ldflda
, FieldInfo
);
3162 // A FieldExpr whose address can not be taken
3164 public class FieldExprNoAddress
: FieldExpr
, IMemoryLocation
{
3165 public FieldExprNoAddress (FieldInfo fi
, Location loc
) : base (fi
, loc
)
3169 public new void AddressOf (EmitContext ec
, AddressOp mode
)
3171 Report
.Error (-215, "Report this: Taking the address of a remapped parameter not supported");
3176 /// Expression that evaluates to a Property. The Assign class
3177 /// might set the `Value' expression if we are in an assignment.
3179 /// This is not an LValue because we need to re-write the expression, we
3180 /// can not take data from the stack and store it.
3182 public class PropertyExpr
: MemberExpr
, IAssignMethod
{
3183 public readonly PropertyInfo PropertyInfo
;
3186 // This is set externally by the `BaseAccess' class
3189 MethodInfo getter
, setter
;
3194 LocalTemporary temp
;
3197 internal static PtrHashtable AccessorTable
= new PtrHashtable ();
3199 public PropertyExpr (Type containerType
, PropertyInfo pi
, Location l
)
3202 eclass
= ExprClass
.PropertyAccess
;
3206 type
= TypeManager
.TypeToCoreType (pi
.PropertyType
);
3208 ResolveAccessors (containerType
);
3211 public override string Name
{
3213 return PropertyInfo
.Name
;
3217 public override bool IsInstance
{
3223 public override bool IsStatic
{
3229 public override Type DeclaringType
{
3231 return PropertyInfo
.DeclaringType
;
3235 public override string GetSignatureForError ()
3237 return TypeManager
.GetFullNameSignature (PropertyInfo
);
3240 void FindAccessors (Type invocation_type
)
3242 const BindingFlags flags
= BindingFlags
.Public
| BindingFlags
.NonPublic
|
3243 BindingFlags
.Static
| BindingFlags
.Instance
|
3244 BindingFlags
.DeclaredOnly
;
3246 Type current
= PropertyInfo
.DeclaringType
;
3247 for (; current
!= null; current
= current
.BaseType
) {
3248 MemberInfo
[] group = TypeManager
.MemberLookup (
3249 invocation_type
, invocation_type
, current
,
3250 MemberTypes
.Property
, flags
, PropertyInfo
.Name
, null);
3255 if (group.Length
!= 1)
3256 // Oooops, can this ever happen ?
3259 PropertyInfo pi
= (PropertyInfo
) group [0];
3262 getter
= pi
.GetGetMethod (true);
3265 setter
= pi
.GetSetMethod (true);
3267 MethodInfo accessor
= getter
!= null ? getter
: setter
;
3269 if (!accessor
.IsVirtual
)
3275 // We also perform the permission checking here, as the PropertyInfo does not
3276 // hold the information for the accessibility of its setter/getter
3278 // TODO: can use TypeManager.GetProperty to boost performance
3279 void ResolveAccessors (Type containerType
)
3281 FindAccessors (containerType
);
3283 if (getter
!= null) {
3284 IMethodData md
= TypeManager
.GetMethod (getter
);
3286 md
.SetMemberIsUsed ();
3288 AccessorTable
[getter
] = PropertyInfo
;
3289 is_static
= getter
.IsStatic
;
3292 if (setter
!= null) {
3293 IMethodData md
= TypeManager
.GetMethod (setter
);
3295 md
.SetMemberIsUsed ();
3297 AccessorTable
[setter
] = PropertyInfo
;
3298 is_static
= setter
.IsStatic
;
3302 bool InstanceResolve (EmitContext ec
, bool lvalue_instance
, bool must_do_cs1540_check
)
3305 InstanceExpression
= null;
3309 if (InstanceExpression
== null) {
3310 SimpleName
.Error_ObjectRefRequired (ec
, loc
, GetSignatureForError ());
3314 if (lvalue_instance
)
3315 InstanceExpression
= InstanceExpression
.ResolveLValue (ec
, EmptyExpression
.LValueMemberAccess
, loc
);
3317 InstanceExpression
= InstanceExpression
.DoResolve (ec
);
3318 if (InstanceExpression
== null)
3321 InstanceExpression
.CheckMarshalByRefAccess ();
3323 if (must_do_cs1540_check
&& InstanceExpression
!= EmptyExpression
.Null
&&
3324 InstanceExpression
.Type
!= ec
.ContainerType
&&
3325 ec
.ContainerType
.IsSubclassOf (PropertyInfo
.DeclaringType
) &&
3326 !InstanceExpression
.Type
.IsSubclassOf (ec
.ContainerType
)) {
3327 Error_CannotAccessProtected (loc
, PropertyInfo
, InstanceExpression
.Type
, ec
.ContainerType
);
3334 void Error_PropertyNotFound (MethodInfo mi
, bool getter
)
3336 // TODO: correctly we should compare arguments but it will lead to bigger changes
3337 if (mi
is MethodBuilder
) {
3338 Error_TypeDoesNotContainDefinition (loc
, PropertyInfo
.DeclaringType
, Name
);
3342 StringBuilder sig
= new StringBuilder (TypeManager
.CSharpName (mi
.DeclaringType
));
3344 ParameterData iparams
= TypeManager
.GetParameterData (mi
);
3345 sig
.Append (getter
? "get_" : "set_");
3347 sig
.Append (iparams
.GetSignatureForError ());
3349 Report
.SymbolRelatedToPreviousError (mi
);
3350 Report
.Error (1546, loc
, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
3351 Name
, sig
.ToString ());
3354 override public Expression
DoResolve (EmitContext ec
)
3359 if (getter
!= null){
3360 if (TypeManager
.GetParameterData (getter
).Count
!= 0){
3361 Error_PropertyNotFound (getter
, true);
3366 if (getter
== null){
3368 // The following condition happens if the PropertyExpr was
3369 // created, but is invalid (ie, the property is inaccessible),
3370 // and we did not want to embed the knowledge about this in
3371 // the caller routine. This only avoids double error reporting.
3376 if (InstanceExpression
!= EmptyExpression
.Null
) {
3377 Report
.Error (154, loc
, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
3378 TypeManager
.GetFullNameSignature (PropertyInfo
));
3383 bool must_do_cs1540_check
= false;
3384 if (getter
!= null &&
3385 !IsAccessorAccessible (ec
.ContainerType
, getter
, out must_do_cs1540_check
)) {
3386 PropertyBase
.PropertyMethod pm
= TypeManager
.GetMethod (getter
) as PropertyBase
.PropertyMethod
;
3387 if (pm
!= null && pm
.HasCustomAccessModifier
) {
3388 Report
.SymbolRelatedToPreviousError (pm
);
3389 Report
.Error (271, loc
, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
3390 TypeManager
.CSharpSignature (getter
));
3393 Report
.SymbolRelatedToPreviousError (getter
);
3394 ErrorIsInaccesible (loc
, TypeManager
.CSharpSignature (getter
));
3399 if (!InstanceResolve (ec
, false, must_do_cs1540_check
))
3403 // Only base will allow this invocation to happen.
3405 if (IsBase
&& getter
.IsAbstract
) {
3406 Error_CannotCallAbstractBase (TypeManager
.GetFullNameSignature (PropertyInfo
));
3410 if (PropertyInfo
.PropertyType
.IsPointer
&& !ec
.InUnsafe
){
3420 override public Expression
DoResolveLValue (EmitContext ec
, Expression right_side
)
3422 if (right_side
== EmptyExpression
.OutAccess
) {
3423 Report
.Error (206, loc
, "A property or indexer `{0}' may not be passed as an out or ref parameter",
3424 GetSignatureForError ());
3428 if (right_side
== EmptyExpression
.LValueMemberAccess
|| right_side
== EmptyExpression
.LValueMemberOutAccess
) {
3429 Report
.Error (1612, loc
, "Cannot modify the return value of `{0}' because it is not a variable",
3430 GetSignatureForError ());
3434 if (setter
== null){
3436 // The following condition happens if the PropertyExpr was
3437 // created, but is invalid (ie, the property is inaccessible),
3438 // and we did not want to embed the knowledge about this in
3439 // the caller routine. This only avoids double error reporting.
3443 Report
.Error (200, loc
, "Property or indexer `{0}' cannot be assigned to (it is read only)",
3444 GetSignatureForError ());
3448 if (TypeManager
.GetParameterData (setter
).Count
!= 1){
3449 Error_PropertyNotFound (setter
, false);
3453 bool must_do_cs1540_check
;
3454 if (!IsAccessorAccessible (ec
.ContainerType
, setter
, out must_do_cs1540_check
)) {
3455 PropertyBase
.PropertyMethod pm
= TypeManager
.GetMethod (setter
) as PropertyBase
.PropertyMethod
;
3456 if (pm
!= null && pm
.HasCustomAccessModifier
) {
3457 Report
.SymbolRelatedToPreviousError (pm
);
3458 Report
.Error (272, loc
, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
3459 TypeManager
.CSharpSignature (setter
));
3462 Report
.SymbolRelatedToPreviousError (setter
);
3463 ErrorIsInaccesible (loc
, TypeManager
.CSharpSignature (setter
));
3468 if (!InstanceResolve (ec
, PropertyInfo
.DeclaringType
.IsValueType
, must_do_cs1540_check
))
3472 // Only base will allow this invocation to happen.
3474 if (IsBase
&& setter
.IsAbstract
){
3475 Error_CannotCallAbstractBase (TypeManager
.GetFullNameSignature (PropertyInfo
));
3482 public override void Emit (EmitContext ec
)
3487 public void Emit (EmitContext ec
, bool leave_copy
)
3490 // Special case: length of single dimension array property is turned into ldlen
3492 if ((getter
== TypeManager
.system_int_array_get_length
) ||
3493 (getter
== TypeManager
.int_array_get_length
)){
3494 Type iet
= InstanceExpression
.Type
;
3497 // System.Array.Length can be called, but the Type does not
3498 // support invoking GetArrayRank, so test for that case first
3500 if (iet
!= TypeManager
.array_type
&& (iet
.GetArrayRank () == 1)) {
3502 EmitInstance (ec
, false);
3503 ec
.ig
.Emit (OpCodes
.Ldlen
);
3504 ec
.ig
.Emit (OpCodes
.Conv_I4
);
3509 Invocation
.EmitCall (ec
, IsBase
, IsStatic
, InstanceExpression
, getter
, null, loc
, prepared
, false);
3512 ec
.ig
.Emit (OpCodes
.Dup
);
3514 temp
= new LocalTemporary (this.Type
);
3521 // Implements the IAssignMethod interface for assignments
3523 public void EmitAssign (EmitContext ec
, Expression source
, bool leave_copy
, bool prepare_for_load
)
3525 Expression my_source
= source
;
3527 prepared
= prepare_for_load
;
3532 ec
.ig
.Emit (OpCodes
.Dup
);
3534 temp
= new LocalTemporary (this.Type
);
3538 } else if (leave_copy
) {
3541 temp
= new LocalTemporary (this.Type
);
3547 ArrayList args
= new ArrayList (1);
3548 args
.Add (new Argument (my_source
, Argument
.AType
.Expression
));
3550 Invocation
.EmitCall (ec
, IsBase
, IsStatic
, InstanceExpression
, setter
, args
, loc
, false, prepared
);
3560 /// Fully resolved expression that evaluates to an Event
3562 public class EventExpr
: MemberExpr
{
3563 public readonly EventInfo EventInfo
;
3566 MethodInfo add_accessor
, remove_accessor
;
3568 internal static PtrHashtable AccessorTable
= new PtrHashtable ();
3570 public EventExpr (EventInfo ei
, Location loc
)
3574 eclass
= ExprClass
.EventAccess
;
3576 add_accessor
= TypeManager
.GetAddMethod (ei
);
3577 remove_accessor
= TypeManager
.GetRemoveMethod (ei
);
3578 if (add_accessor
!= null)
3579 AccessorTable
[add_accessor
] = ei
;
3580 if (remove_accessor
!= null)
3581 AccessorTable
[remove_accessor
] = ei
;
3583 if (add_accessor
.IsStatic
|| remove_accessor
.IsStatic
)
3586 if (EventInfo
is MyEventBuilder
){
3587 MyEventBuilder eb
= (MyEventBuilder
) EventInfo
;
3588 type
= eb
.EventType
;
3591 type
= EventInfo
.EventHandlerType
;
3594 public override string Name
{
3596 return EventInfo
.Name
;
3600 public override bool IsInstance
{
3606 public override bool IsStatic
{
3612 public override Type DeclaringType
{
3614 return EventInfo
.DeclaringType
;
3618 public override Expression
ResolveMemberAccess (EmitContext ec
, Expression left
, Location loc
,
3619 SimpleName original
)
3622 // If the event is local to this class, we transform ourselves into a FieldExpr
3625 if (EventInfo
.DeclaringType
== ec
.ContainerType
||
3626 TypeManager
.IsNestedChildOf(ec
.ContainerType
, EventInfo
.DeclaringType
)) {
3627 MemberInfo mi
= TypeManager
.GetPrivateFieldOfEvent (EventInfo
);
3630 MemberExpr ml
= (MemberExpr
) ExprClassFromMemberInfo (ec
.ContainerType
, mi
, loc
);
3633 Report
.Error (-200, loc
, "Internal error!!");
3637 InstanceExpression
= null;
3639 return ml
.ResolveMemberAccess (ec
, left
, loc
, original
);
3643 return base.ResolveMemberAccess (ec
, left
, loc
, original
);
3647 bool InstanceResolve (EmitContext ec
, bool must_do_cs1540_check
)
3650 InstanceExpression
= null;
3654 if (InstanceExpression
== null) {
3655 SimpleName
.Error_ObjectRefRequired (ec
, loc
, GetSignatureForError ());
3659 InstanceExpression
= InstanceExpression
.DoResolve (ec
);
3660 if (InstanceExpression
== null)
3664 // This is using the same mechanism as the CS1540 check in PropertyExpr.
3665 // However, in the Event case, we reported a CS0122 instead.
3667 if (must_do_cs1540_check
&& InstanceExpression
!= EmptyExpression
.Null
&&
3668 InstanceExpression
.Type
!= ec
.ContainerType
&&
3669 ec
.ContainerType
.IsSubclassOf (InstanceExpression
.Type
)) {
3670 Report
.SymbolRelatedToPreviousError (EventInfo
);
3671 ErrorIsInaccesible (loc
, TypeManager
.CSharpSignature (EventInfo
));
3678 public override Expression
DoResolveLValue (EmitContext ec
, Expression right_side
)
3680 return DoResolve (ec
);
3683 public override Expression
DoResolve (EmitContext ec
)
3685 bool must_do_cs1540_check
;
3686 if (!(IsAccessorAccessible (ec
.ContainerType
, add_accessor
, out must_do_cs1540_check
) &&
3687 IsAccessorAccessible (ec
.ContainerType
, remove_accessor
, out must_do_cs1540_check
))) {
3688 Report
.SymbolRelatedToPreviousError (EventInfo
);
3689 ErrorIsInaccesible (loc
, TypeManager
.CSharpSignature (EventInfo
));
3693 if (!InstanceResolve (ec
, must_do_cs1540_check
))
3699 public override void Emit (EmitContext ec
)
3701 if (InstanceExpression
is This
)
3702 Report
.Error (79, loc
, "The event `{0}' can only appear on the left hand side of += or -=", GetSignatureForError ());
3704 Report
.Error (70, loc
, "The event `{0}' can only appear on the left hand side of += or -= "+
3705 "(except on the defining type)", Name
);
3708 public override string GetSignatureForError ()
3710 return TypeManager
.CSharpSignature (EventInfo
);
3713 public void EmitAddOrRemove (EmitContext ec
, Expression source
)
3715 BinaryDelegate source_del
= (BinaryDelegate
) source
;
3716 Expression handler
= source_del
.Right
;
3718 Argument arg
= new Argument (handler
, Argument
.AType
.Expression
);
3719 ArrayList args
= new ArrayList ();
3723 if (source_del
.IsAddition
)
3724 Invocation
.EmitCall (
3725 ec
, false, IsStatic
, InstanceExpression
, add_accessor
, args
, loc
);
3727 Invocation
.EmitCall (
3728 ec
, false, IsStatic
, InstanceExpression
, remove_accessor
, args
, loc
);
3733 public class TemporaryVariable
: Expression
, IMemoryLocation
3737 public TemporaryVariable (Type type
, Location loc
)
3741 eclass
= ExprClass
.Value
;
3744 public override Expression
DoResolve (EmitContext ec
)
3749 TypeExpr te
= new TypeExpression (type
, loc
);
3750 li
= ec
.CurrentBlock
.AddTemporaryVariable (te
, loc
);
3751 if (!li
.Resolve (ec
))
3754 AnonymousContainer am
= ec
.CurrentAnonymousMethod
;
3755 if ((am
!= null) && am
.IsIterator
)
3756 ec
.CaptureVariable (li
);
3761 public override void Emit (EmitContext ec
)
3763 ILGenerator ig
= ec
.ig
;
3765 if (li
.FieldBuilder
!= null) {
3766 ig
.Emit (OpCodes
.Ldarg_0
);
3767 ig
.Emit (OpCodes
.Ldfld
, li
.FieldBuilder
);
3769 ig
.Emit (OpCodes
.Ldloc
, li
.LocalBuilder
);
3773 public void EmitLoadAddress (EmitContext ec
)
3775 ILGenerator ig
= ec
.ig
;
3777 if (li
.FieldBuilder
!= null) {
3778 ig
.Emit (OpCodes
.Ldarg_0
);
3779 ig
.Emit (OpCodes
.Ldflda
, li
.FieldBuilder
);
3781 ig
.Emit (OpCodes
.Ldloca
, li
.LocalBuilder
);
3785 public void Store (EmitContext ec
, Expression right_side
)
3787 if (li
.FieldBuilder
!= null)
3788 ec
.ig
.Emit (OpCodes
.Ldarg_0
);
3790 right_side
.Emit (ec
);
3791 if (li
.FieldBuilder
!= null) {
3792 ec
.ig
.Emit (OpCodes
.Stfld
, li
.FieldBuilder
);
3794 ec
.ig
.Emit (OpCodes
.Stloc
, li
.LocalBuilder
);
3798 public void EmitThis (EmitContext ec
)
3800 if (li
.FieldBuilder
!= null) {
3801 ec
.ig
.Emit (OpCodes
.Ldarg_0
);
3805 public void EmitStore (ILGenerator ig
)
3807 if (li
.FieldBuilder
!= null)
3808 ig
.Emit (OpCodes
.Stfld
, li
.FieldBuilder
);
3810 ig
.Emit (OpCodes
.Stloc
, li
.LocalBuilder
);
3813 public void AddressOf (EmitContext ec
, AddressOp mode
)
3815 EmitLoadAddress (ec
);