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 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
13 namespace Mono
.CSharp
{
15 using System
.Collections
;
16 using System
.Diagnostics
;
17 using System
.Reflection
;
18 using System
.Reflection
.Emit
;
22 /// The ExprClass class contains the is used to pass the
23 /// classification of an expression (value, variable, namespace,
24 /// type, method group, property access, event access, indexer access,
27 public enum ExprClass
: byte {
43 /// This is used to tell Resolve in which types of expressions we're
47 public enum ResolveFlags
{
48 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
51 // Returns a type expression.
54 // Returns a method group.
57 TypeParameter
= 1 << 3,
59 // Mask of all the expression class flags.
60 MaskExprClass
= VariableOrValue
| Type
| MethodGroup
| TypeParameter
,
62 // Disable control flow analysis while resolving the expression.
63 // This is used when resolving the instance expression of a field expression.
64 DisableFlowAnalysis
= 1 << 10,
66 // Set if this is resolving the first part of a MemberAccess.
67 Intermediate
= 1 << 11,
69 // Disable control flow analysis _of struct_ while resolving the expression.
70 // This is used when resolving the instance expression of a field expression.
71 DisableStructFlowAnalysis
= 1 << 12,
76 // This is just as a hint to AddressOf of what will be done with the
79 public enum AddressOp
{
86 /// This interface is implemented by variables
88 public interface IMemoryLocation
{
90 /// The AddressOf method should generate code that loads
91 /// the address of the object and leaves it on the stack.
93 /// The `mode' argument is used to notify the expression
94 /// of whether this will be used to read from the address or
95 /// write to the address.
97 /// This is just a hint that can be used to provide good error
98 /// reporting, and should have no other side effects.
100 void AddressOf (EmitContext ec
, AddressOp mode
);
104 // An expressions resolved as a direct variable reference
106 public interface IVariableReference
: IFixedExpression
108 bool IsHoisted { get; }
110 VariableInfo VariableInfo { get; }
112 void SetHasAddressTaken ();
116 // Implemented by an expression which could be or is always
119 public interface IFixedExpression
121 bool IsFixed { get; }
125 /// Base class for expressions
127 public abstract class Expression
{
128 public ExprClass eclass
;
130 protected Location loc
;
134 set { type = value; }
137 public virtual Location Location
{
142 /// Utility wrapper routine for Error, just to beautify the code
144 public void Error (int error
, string s
)
146 Report
.Error (error
, loc
, s
);
149 // Not nice but we have broken hierarchy.
150 public virtual void CheckMarshalByRefAccess (EmitContext ec
)
154 public virtual bool GetAttributableValue (EmitContext ec
, Type value_type
, out object value)
156 Attribute
.Error_AttributeArgumentNotValid (loc
);
161 public virtual string GetSignatureForError ()
163 return TypeManager
.CSharpName (type
);
166 public static bool IsAccessorAccessible (Type invocation_type
, MethodInfo mi
, out bool must_do_cs1540_check
)
168 MethodAttributes ma
= mi
.Attributes
& MethodAttributes
.MemberAccessMask
;
170 must_do_cs1540_check
= false; // by default we do not check for this
172 if (ma
== MethodAttributes
.Public
)
176 // If only accessible to the current class or children
178 if (ma
== MethodAttributes
.Private
)
179 return TypeManager
.IsPrivateAccessible (invocation_type
, mi
.DeclaringType
) ||
180 TypeManager
.IsNestedChildOf (invocation_type
, mi
.DeclaringType
);
182 if (TypeManager
.IsThisOrFriendAssembly (mi
.DeclaringType
.Assembly
)) {
183 if (ma
== MethodAttributes
.Assembly
|| ma
== MethodAttributes
.FamORAssem
)
186 if (ma
== MethodAttributes
.Assembly
|| ma
== MethodAttributes
.FamANDAssem
)
190 // Family and FamANDAssem require that we derive.
191 // FamORAssem requires that we derive if in different assemblies.
192 if (!TypeManager
.IsNestedFamilyAccessible (invocation_type
, mi
.DeclaringType
))
195 if (!TypeManager
.IsNestedChildOf (invocation_type
, mi
.DeclaringType
))
196 must_do_cs1540_check
= true;
201 public virtual bool IsNull
{
208 /// Performs semantic analysis on the Expression
212 /// The Resolve method is invoked to perform the semantic analysis
215 /// The return value is an expression (it can be the
216 /// same expression in some cases) or a new
217 /// expression that better represents this node.
219 /// For example, optimizations of Unary (LiteralInt)
220 /// would return a new LiteralInt with a negated
223 /// If there is an error during semantic analysis,
224 /// then an error should be reported (using Report)
225 /// and a null value should be returned.
227 /// There are two side effects expected from calling
228 /// Resolve(): the the field variable "eclass" should
229 /// be set to any value of the enumeration
230 /// `ExprClass' and the type variable should be set
231 /// to a valid type (this is the type of the
234 public abstract Expression
DoResolve (EmitContext ec
);
236 public virtual Expression
DoResolveLValue (EmitContext ec
, Expression right_side
)
242 // This is used if the expression should be resolved as a type or namespace name.
243 // the default implementation fails.
245 public virtual FullNamedExpression
ResolveAsTypeStep (IResolveContext rc
, bool silent
)
249 EmitContext ec
= rc
as EmitContext
;
253 e
.Error_UnexpectedKind (ResolveFlags
.Type
, loc
);
259 // C# 3.0 introduced contextual keywords (var) which behaves like a type if type with
260 // same name exists or as a keyword when no type was found
262 public virtual TypeExpr
ResolveAsContextualType (IResolveContext rc
, bool silent
)
264 return ResolveAsTypeTerminal (rc
, silent
);
268 // This is used to resolve the expression as a type, a null
269 // value will be returned if the expression is not a type
272 public virtual TypeExpr
ResolveAsTypeTerminal (IResolveContext ec
, bool silent
)
274 TypeExpr te
= ResolveAsBaseTerminal (ec
, silent
);
278 if (!silent
) { // && !(te is TypeParameterExpr)) {
279 ObsoleteAttribute obsolete_attr
= AttributeTester
.GetObsoleteAttribute (te
.Type
);
280 if (obsolete_attr
!= null && !ec
.IsInObsoleteScope
) {
281 AttributeTester
.Report_ObsoleteMessage (obsolete_attr
, te
.GetSignatureForError (), Location
);
285 ConstructedType ct
= te
as ConstructedType
;
287 // Skip constrains check for overrides and explicit implementations
288 // TODO: they should use different overload
289 GenericMethod gm
= ec
.GenericDeclContainer
as GenericMethod
;
290 if (gm
!= null && ((gm
.ModFlags
& Modifiers
.OVERRIDE
) != 0 || gm
.MemberName
.Left
!= null)) {
295 // TODO: silent flag is ignored
296 ct
.CheckConstraints (ec
);
302 public TypeExpr
ResolveAsBaseTerminal (IResolveContext ec
, bool silent
)
304 int errors
= Report
.Errors
;
306 FullNamedExpression fne
= ResolveAsTypeStep (ec
, silent
);
311 TypeExpr te
= fne
as TypeExpr
;
313 if (!silent
&& errors
== Report
.Errors
)
314 fne
.Error_UnexpectedKind (null, "type", loc
);
318 if (!te
.CheckAccessLevel (ec
.GenericDeclContainer
)) {
319 Report
.SymbolRelatedToPreviousError (te
.Type
);
320 ErrorIsInaccesible (loc
, TypeManager
.CSharpName (te
.Type
));
328 public static void ErrorIsInaccesible (Location loc
, string name
)
330 Report
.Error (122, loc
, "`{0}' is inaccessible due to its protection level", name
);
333 protected static void Error_CannotAccessProtected (Location loc
, MemberInfo m
, Type qualifier
, Type container
)
335 Report
.Error (1540, loc
, "Cannot access protected member `{0}' via a qualifier of type `{1}'."
336 + " The qualifier must be of type `{2}' or derived from it",
337 TypeManager
.GetFullNameSignature (m
),
338 TypeManager
.CSharpName (qualifier
),
339 TypeManager
.CSharpName (container
));
343 public static void Error_InvalidExpressionStatement (Location loc
)
345 Report
.Error (201, loc
, "Only assignment, call, increment, decrement, and new object " +
346 "expressions can be used as a statement");
349 public void Error_InvalidExpressionStatement ()
351 Error_InvalidExpressionStatement (loc
);
354 protected void Error_CannotAssign (string to
, string roContext
)
356 Report
.Error (1656, loc
, "Cannot assign to `{0}' because it is a `{1}'",
360 public static void Error_VoidInvalidInTheContext (Location loc
)
362 Report
.Error (1547, loc
, "Keyword `void' cannot be used in this context");
365 public virtual void Error_ValueCannotBeConverted (EmitContext ec
, Location loc
, Type target
, bool expl
)
367 // The error was already reported as CS1660
368 if (type
== TypeManager
.anonymous_method_type
)
371 if (TypeManager
.IsGenericParameter (Type
) && TypeManager
.IsGenericParameter (target
) && type
.Name
== target
.Name
) {
373 string sig1
= type
.DeclaringMethod
== null ?
374 TypeManager
.CSharpName (type
.DeclaringType
) :
375 TypeManager
.CSharpSignature (type
.DeclaringMethod
);
376 string sig2
= target
.DeclaringMethod
== null ?
377 TypeManager
.CSharpName (target
.DeclaringType
) :
378 TypeManager
.CSharpSignature (target
.DeclaringMethod
);
379 Report
.ExtraInformation (loc
,
381 "The generic parameter `{0}' of `{1}' cannot be converted to the generic parameter `{0}' of `{2}' (in the previous ",
382 Type
.Name
, sig1
, sig2
));
384 } else if (Type
.FullName
== target
.FullName
){
385 Report
.ExtraInformation (loc
,
387 "The type `{0}' has two conflicting definitions, one comes from `{1}' and the other from `{2}' (in the previous ",
388 Type
.FullName
, Type
.Assembly
.FullName
, target
.Assembly
.FullName
));
392 Report
.Error (30, loc
, "Cannot convert type `{0}' to `{1}'",
393 TypeManager
.CSharpName (type
), TypeManager
.CSharpName (target
));
397 Report
.DisableReporting ();
398 bool expl_exists
= Convert
.ExplicitConversion (ec
, this, target
, Location
.Null
) != null;
399 Report
.EnableReporting ();
402 Report
.Error (266, loc
, "Cannot implicitly convert type `{0}' to `{1}'. " +
403 "An explicit conversion exists (are you missing a cast?)",
404 TypeManager
.CSharpName (Type
), TypeManager
.CSharpName (target
));
408 Report
.Error (29, loc
, "Cannot implicitly convert type `{0}' to `{1}'",
409 TypeManager
.CSharpName (type
),
410 TypeManager
.CSharpName (target
));
413 public virtual void Error_VariableIsUsedBeforeItIsDeclared (string name
)
415 Report
.Error (841, loc
, "A local variable `{0}' cannot be used before it is declared", name
);
418 protected virtual void Error_TypeDoesNotContainDefinition (Type type
, string name
)
420 Error_TypeDoesNotContainDefinition (loc
, type
, name
);
423 public static void Error_TypeDoesNotContainDefinition (Location loc
, Type type
, string name
)
425 Report
.SymbolRelatedToPreviousError (type
);
426 Report
.Error (117, loc
, "`{0}' does not contain a definition for `{1}'",
427 TypeManager
.CSharpName (type
), name
);
430 protected static void Error_ValueAssignment (Location loc
)
432 Report
.Error (131, loc
, "The left-hand side of an assignment must be a variable, a property or an indexer");
435 ResolveFlags ExprClassToResolveFlags
440 case ExprClass
.Namespace
:
441 return ResolveFlags
.Type
;
443 case ExprClass
.MethodGroup
:
444 return ResolveFlags
.MethodGroup
;
446 case ExprClass
.TypeParameter
:
447 return ResolveFlags
.TypeParameter
;
449 case ExprClass
.Value
:
450 case ExprClass
.Variable
:
451 case ExprClass
.PropertyAccess
:
452 case ExprClass
.EventAccess
:
453 case ExprClass
.IndexerAccess
:
454 return ResolveFlags
.VariableOrValue
;
457 throw new InternalErrorException (loc
.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
463 /// Resolves an expression and performs semantic analysis on it.
467 /// Currently Resolve wraps DoResolve to perform sanity
468 /// checking and assertion checking on what we expect from Resolve.
470 public Expression
Resolve (EmitContext ec
, ResolveFlags flags
)
472 if ((flags
& ResolveFlags
.MaskExprClass
) == ResolveFlags
.Type
)
473 return ResolveAsTypeStep (ec
, false);
475 bool do_flow_analysis
= ec
.DoFlowAnalysis
;
476 bool omit_struct_analysis
= ec
.OmitStructFlowAnalysis
;
477 if ((flags
& ResolveFlags
.DisableFlowAnalysis
) != 0)
478 do_flow_analysis
= false;
479 if ((flags
& ResolveFlags
.DisableStructFlowAnalysis
) != 0)
480 omit_struct_analysis
= true;
483 using (ec
.WithFlowAnalysis (do_flow_analysis
, omit_struct_analysis
)) {
484 if (this is SimpleName
) {
485 bool intermediate
= (flags
& ResolveFlags
.Intermediate
) == ResolveFlags
.Intermediate
;
486 e
= ((SimpleName
) this).DoResolve (ec
, intermediate
);
495 if ((flags
& e
.ExprClassToResolveFlags
) == 0) {
496 e
.Error_UnexpectedKind (flags
, loc
);
500 if (e
.type
== null && !(e
is Namespace
)) {
501 throw new Exception (
502 "Expression " + e
.GetType () +
503 " did not set its type after Resolve\n" +
504 "called from: " + this.GetType ());
511 /// Resolves an expression and performs semantic analysis on it.
513 public Expression
Resolve (EmitContext ec
)
515 Expression e
= Resolve (ec
, ResolveFlags
.VariableOrValue
| ResolveFlags
.MethodGroup
);
517 if (e
!= null && e
.eclass
== ExprClass
.MethodGroup
&& RootContext
.Version
== LanguageVersion
.ISO_1
) {
518 ((MethodGroupExpr
) e
).ReportUsageError ();
524 public Constant
ResolveAsConstant (EmitContext ec
, MemberCore mc
)
526 Expression e
= Resolve (ec
);
530 Constant c
= e
as Constant
;
534 if (type
!= null && TypeManager
.IsReferenceType (type
))
535 Const
.Error_ConstantCanBeInitializedWithNullOnly (type
, loc
, mc
.GetSignatureForError ());
537 Const
.Error_ExpressionMustBeConstant (loc
, mc
.GetSignatureForError ());
543 /// Resolves an expression for LValue assignment
547 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
548 /// checking and assertion checking on what we expect from Resolve
550 public Expression
ResolveLValue (EmitContext ec
, Expression right_side
, Location loc
)
552 int errors
= Report
.Errors
;
553 bool out_access
= right_side
== EmptyExpression
.OutAccess
;
555 Expression e
= DoResolveLValue (ec
, right_side
);
557 if (e
!= null && out_access
&& !(e
is IMemoryLocation
)) {
558 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
559 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
561 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
562 // e.GetType () + " " + e.GetSignatureForError ());
567 if (errors
== Report
.Errors
) {
569 Report
.Error (1510, loc
, "A ref or out argument must be an assignable variable");
571 Error_ValueAssignment (loc
);
576 if (e
.eclass
== ExprClass
.Invalid
)
577 throw new Exception ("Expression " + e
+ " ExprClass is Invalid after resolve");
579 if ((e
.type
== null) && !(e
is ConstructedType
))
580 throw new Exception ("Expression " + e
+ " did not set its type after Resolve");
586 /// Emits the code for the expression
590 /// The Emit method is invoked to generate the code
591 /// for the expression.
593 public abstract void Emit (EmitContext ec
);
595 // Emit code to branch to @target if this expression is equivalent to @on_true.
596 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
597 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
598 // including the use of conditional branches. Note also that a branch MUST be emitted
599 public virtual void EmitBranchable (EmitContext ec
, Label target
, bool on_true
)
602 ec
.ig
.Emit (on_true
? OpCodes
.Brtrue
: OpCodes
.Brfalse
, target
);
605 // Emit this expression for its side effects, not for its value.
606 // The default implementation is to emit the value, and then throw it away.
607 // Subclasses can provide more efficient implementations, but those MUST be equivalent
608 public virtual void EmitSideEffect (EmitContext ec
)
611 ec
.ig
.Emit (OpCodes
.Pop
);
615 /// Protected constructor. Only derivate types should
616 /// be able to be created
619 protected Expression ()
621 eclass
= ExprClass
.Invalid
;
626 /// Returns a fully formed expression after a MemberLookup
629 public static Expression
ExprClassFromMemberInfo (Type container_type
, MemberInfo mi
, Location loc
)
632 return new EventExpr ((EventInfo
) mi
, loc
);
633 else if (mi
is FieldInfo
) {
634 FieldInfo fi
= (FieldInfo
) mi
;
635 if (fi
.IsLiteral
|| (fi
.IsInitOnly
&& fi
.FieldType
== TypeManager
.decimal_type
))
636 return new ConstantExpr (fi
, loc
);
637 return new FieldExpr (fi
, loc
);
638 } else if (mi
is PropertyInfo
)
639 return new PropertyExpr (container_type
, (PropertyInfo
) mi
, loc
);
640 else if (mi
is Type
) {
641 return new TypeExpression ((System
.Type
) mi
, loc
);
647 protected static ArrayList almost_matched_members
= new ArrayList (4);
650 // FIXME: Probably implement a cache for (t,name,current_access_set)?
652 // This code could use some optimizations, but we need to do some
653 // measurements. For example, we could use a delegate to `flag' when
654 // something can not any longer be a method-group (because it is something
658 // If the return value is an Array, then it is an array of
661 // If the return value is an MemberInfo, it is anything, but a Method
665 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
666 // the arguments here and have MemberLookup return only the methods that
667 // match the argument count/type, unlike we are doing now (we delay this
670 // This is so we can catch correctly attempts to invoke instance methods
671 // from a static body (scan for error 120 in ResolveSimpleName).
674 // FIXME: Potential optimization, have a static ArrayList
677 public static Expression
MemberLookup (Type container_type
, Type queried_type
, string name
,
678 MemberTypes mt
, BindingFlags bf
, Location loc
)
680 return MemberLookup (container_type
, null, queried_type
, name
, mt
, bf
, loc
);
684 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
685 // `qualifier_type' or null to lookup members in the current class.
688 public static Expression
MemberLookup (Type container_type
,
689 Type qualifier_type
, Type queried_type
,
690 string name
, MemberTypes mt
,
691 BindingFlags bf
, Location loc
)
693 almost_matched_members
.Clear ();
695 MemberInfo
[] mi
= TypeManager
.MemberLookup (container_type
, qualifier_type
,
696 queried_type
, mt
, bf
, name
, almost_matched_members
);
702 bool is_interface
= qualifier_type
!= null && qualifier_type
.IsInterface
;
703 ArrayList methods
= new ArrayList (2);
704 ArrayList non_methods
= null;
706 foreach (MemberInfo m
in mi
) {
707 if (m
is MethodBase
) {
712 if (non_methods
== null) {
713 non_methods
= new ArrayList (2);
718 foreach (MemberInfo n_m
in non_methods
) {
719 if (m
.DeclaringType
.IsInterface
&& TypeManager
.ImplementsInterface (m
.DeclaringType
, n_m
.DeclaringType
))
722 Report
.SymbolRelatedToPreviousError (m
);
723 Report
.Error (229, loc
, "Ambiguity between `{0}' and `{1}'",
724 TypeManager
.GetFullNameSignature (m
), TypeManager
.GetFullNameSignature (n_m
));
729 if (methods
.Count
== 0)
730 return ExprClassFromMemberInfo (container_type
, (MemberInfo
)non_methods
[0], loc
);
732 if (non_methods
!= null) {
733 MethodBase method
= (MethodBase
) methods
[0];
734 MemberInfo non_method
= (MemberInfo
) non_methods
[0];
735 if (method
.DeclaringType
== non_method
.DeclaringType
) {
736 // Cannot happen with C# code, but is valid in IL
737 Report
.SymbolRelatedToPreviousError (method
);
738 Report
.SymbolRelatedToPreviousError (non_method
);
739 Report
.Error (229, loc
, "Ambiguity between `{0}' and `{1}'",
740 TypeManager
.GetFullNameSignature (non_method
),
741 TypeManager
.CSharpSignature (method
));
746 Report
.SymbolRelatedToPreviousError (method
);
747 Report
.SymbolRelatedToPreviousError (non_method
);
748 Report
.Warning (467, 2, loc
, "Ambiguity between method `{0}' and non-method `{1}'. Using method `{0}'",
749 TypeManager
.CSharpSignature (method
), TypeManager
.GetFullNameSignature (non_method
));
753 return new MethodGroupExpr (methods
, queried_type
, loc
);
756 if (mi
[0] is MethodBase
)
757 return new MethodGroupExpr (mi
, queried_type
, loc
);
759 return ExprClassFromMemberInfo (container_type
, mi
[0], loc
);
762 public const MemberTypes AllMemberTypes
=
763 MemberTypes
.Constructor
|
767 MemberTypes
.NestedType
|
768 MemberTypes
.Property
;
770 public const BindingFlags AllBindingFlags
=
771 BindingFlags
.Public
|
772 BindingFlags
.Static
|
773 BindingFlags
.Instance
;
775 public static Expression
MemberLookup (Type container_type
, Type queried_type
,
776 string name
, Location loc
)
778 return MemberLookup (container_type
, null, queried_type
, name
,
779 AllMemberTypes
, AllBindingFlags
, loc
);
782 public static Expression
MemberLookup (Type container_type
, Type qualifier_type
,
783 Type queried_type
, string name
, Location loc
)
785 return MemberLookup (container_type
, qualifier_type
, queried_type
,
786 name
, AllMemberTypes
, AllBindingFlags
, loc
);
789 public static MethodGroupExpr
MethodLookup (Type container_type
, Type queried_type
,
790 string name
, Location loc
)
792 return (MethodGroupExpr
)MemberLookup (container_type
, null, queried_type
, name
,
793 MemberTypes
.Method
, AllBindingFlags
, loc
);
797 /// This is a wrapper for MemberLookup that is not used to "probe", but
798 /// to find a final definition. If the final definition is not found, we
799 /// look for private members and display a useful debugging message if we
802 protected Expression
MemberLookupFinal (EmitContext ec
, Type qualifier_type
,
803 Type queried_type
, string name
,
804 MemberTypes mt
, BindingFlags bf
,
809 int errors
= Report
.Errors
;
810 e
= MemberLookup (ec
.ContainerType
, qualifier_type
, queried_type
, name
, mt
, bf
, loc
);
812 if (e
!= null || errors
!= Report
.Errors
)
815 // No errors were reported by MemberLookup, but there was an error.
816 return Error_MemberLookupFailed (ec
.ContainerType
, qualifier_type
, queried_type
,
820 protected virtual Expression
Error_MemberLookupFailed (Type container_type
, Type qualifier_type
,
821 Type queried_type
, string name
, string class_name
,
822 MemberTypes mt
, BindingFlags bf
)
824 if (almost_matched_members
.Count
!= 0) {
825 for (int i
= 0; i
< almost_matched_members
.Count
; ++i
) {
826 MemberInfo m
= (MemberInfo
) almost_matched_members
[i
];
827 for (int j
= 0; j
< i
; ++j
) {
828 if (m
== almost_matched_members
[j
]) {
836 Type declaring_type
= m
.DeclaringType
;
838 Report
.SymbolRelatedToPreviousError (m
);
839 if (qualifier_type
== null) {
840 Report
.Error (38, loc
, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
841 TypeManager
.CSharpName (m
.DeclaringType
),
842 TypeManager
.CSharpName (container_type
));
844 } else if (qualifier_type
!= container_type
&&
845 TypeManager
.IsNestedFamilyAccessible (container_type
, declaring_type
)) {
846 // Although a derived class can access protected members of
847 // its base class it cannot do so through an instance of the
848 // base class (CS1540). If the qualifier_type is a base of the
849 // ec.ContainerType and the lookup succeeds with the latter one,
850 // then we are in this situation.
851 Error_CannotAccessProtected (loc
, m
, qualifier_type
, container_type
);
853 ErrorIsInaccesible (loc
, TypeManager
.GetFullNameSignature (m
));
856 almost_matched_members
.Clear ();
860 MemberInfo
[] lookup
= null;
861 if (queried_type
== null) {
862 class_name
= "global::";
864 lookup
= TypeManager
.MemberLookup (queried_type
, null, queried_type
,
865 mt
, (bf
& ~BindingFlags
.Public
) | BindingFlags
.NonPublic
,
868 if (lookup
!= null) {
869 Report
.SymbolRelatedToPreviousError (lookup
[0]);
870 ErrorIsInaccesible (loc
, TypeManager
.GetFullNameSignature (lookup
[0]));
871 return Error_MemberLookupFailed (lookup
);
874 lookup
= TypeManager
.MemberLookup (queried_type
, null, queried_type
,
875 AllMemberTypes
, AllBindingFlags
| BindingFlags
.NonPublic
,
879 if (lookup
== null) {
880 if (class_name
!= null) {
881 Report
.Error (103, loc
, "The name `{0}' does not exist in the current context",
884 Error_TypeDoesNotContainDefinition (queried_type
, name
);
889 if (TypeManager
.MemberLookup (queried_type
, null, queried_type
,
890 AllMemberTypes
, AllBindingFlags
|
891 BindingFlags
.NonPublic
, name
, null) == null) {
892 if ((lookup
.Length
== 1) && (lookup
[0] is Type
)) {
893 Type t
= (Type
) lookup
[0];
895 Report
.Error (305, loc
,
896 "Using the generic type `{0}' " +
897 "requires {1} type arguments",
898 TypeManager
.CSharpName (t
),
899 TypeManager
.GetNumberOfTypeArguments (t
).ToString ());
904 return Error_MemberLookupFailed (lookup
);
907 protected virtual Expression
Error_MemberLookupFailed (MemberInfo
[] members
)
909 for (int i
= 0; i
< members
.Length
; ++i
) {
910 if (!(members
[i
] is MethodBase
))
914 // By default propagate the closest candidates upwards
915 return new MethodGroupExpr (members
, type
, loc
);
918 protected virtual void Error_NegativeArrayIndex (Location loc
)
920 throw new NotImplementedException ();
923 protected void Error_PointerInsideExpressionTree ()
925 Report
.Error (1944, loc
, "An expression tree cannot contain an unsafe pointer operation");
929 /// Returns an expression that can be used to invoke operator true
930 /// on the expression if it exists.
932 static public Expression
GetOperatorTrue (EmitContext ec
, Expression e
, Location loc
)
934 return GetOperatorTrueOrFalse (ec
, e
, true, loc
);
938 /// Returns an expression that can be used to invoke operator false
939 /// on the expression if it exists.
941 static public Expression
GetOperatorFalse (EmitContext ec
, Expression e
, Location loc
)
943 return GetOperatorTrueOrFalse (ec
, e
, false, loc
);
946 static Expression
GetOperatorTrueOrFalse (EmitContext ec
, Expression e
, bool is_true
, Location loc
)
948 MethodGroupExpr operator_group
;
949 string mname
= Operator
.GetMetadataName (is_true
? Operator
.OpType
.True
: Operator
.OpType
.False
);
950 operator_group
= MethodLookup (ec
.ContainerType
, e
.Type
, mname
, loc
) as MethodGroupExpr
;
951 if (operator_group
== null)
954 ArrayList arguments
= new ArrayList (1);
955 arguments
.Add (new Argument (e
, Argument
.AType
.Expression
));
956 operator_group
= operator_group
.OverloadResolve (
957 ec
, ref arguments
, false, loc
);
959 if (operator_group
== null)
962 return new UserOperatorCall (operator_group
, arguments
, null, loc
);
966 /// Resolves the expression `e' into a boolean expression: either through
967 /// an implicit conversion, or through an `operator true' invocation
969 public static Expression
ResolveBoolean (EmitContext ec
, Expression e
, Location loc
)
975 if (e
.Type
== TypeManager
.bool_type
)
978 Expression converted
= Convert
.ImplicitConversion (ec
, e
, TypeManager
.bool_type
, Location
.Null
);
980 if (converted
!= null)
984 // If no implicit conversion to bool exists, try using `operator true'
986 converted
= Expression
.GetOperatorTrue (ec
, e
, loc
);
987 if (converted
== null){
988 e
.Error_ValueCannotBeConverted (ec
, loc
, TypeManager
.bool_type
, false);
994 public virtual string ExprClassName
998 case ExprClass
.Invalid
:
1000 case ExprClass
.Value
:
1002 case ExprClass
.Variable
:
1004 case ExprClass
.Namespace
:
1006 case ExprClass
.Type
:
1008 case ExprClass
.MethodGroup
:
1009 return "method group";
1010 case ExprClass
.PropertyAccess
:
1011 return "property access";
1012 case ExprClass
.EventAccess
:
1013 return "event access";
1014 case ExprClass
.IndexerAccess
:
1015 return "indexer access";
1016 case ExprClass
.Nothing
:
1018 case ExprClass
.TypeParameter
:
1019 return "type parameter";
1021 throw new Exception ("Should not happen");
1026 /// Reports that we were expecting `expr' to be of class `expected'
1028 public void Error_UnexpectedKind (DeclSpace ds
, string expected
, Location loc
)
1030 Error_UnexpectedKind (ds
, expected
, ExprClassName
, loc
);
1033 public void Error_UnexpectedKind (DeclSpace ds
, string expected
, string was
, Location loc
)
1035 string name
= GetSignatureForError ();
1037 name
= ds
.GetSignatureForError () + '.' + name
;
1039 Report
.Error (118, loc
, "`{0}' is a `{1}' but a `{2}' was expected",
1040 name
, was
, expected
);
1043 public void Error_UnexpectedKind (ResolveFlags flags
, Location loc
)
1045 string [] valid
= new string [4];
1048 if ((flags
& ResolveFlags
.VariableOrValue
) != 0) {
1049 valid
[count
++] = "variable";
1050 valid
[count
++] = "value";
1053 if ((flags
& ResolveFlags
.Type
) != 0)
1054 valid
[count
++] = "type";
1056 if ((flags
& ResolveFlags
.MethodGroup
) != 0)
1057 valid
[count
++] = "method group";
1060 valid
[count
++] = "unknown";
1062 StringBuilder sb
= new StringBuilder (valid
[0]);
1063 for (int i
= 1; i
< count
- 1; i
++) {
1065 sb
.Append (valid
[i
]);
1068 sb
.Append ("' or `");
1069 sb
.Append (valid
[count
- 1]);
1072 Report
.Error (119, loc
,
1073 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName
, sb
.ToString ());
1076 public static void UnsafeError (Location loc
)
1078 Report
.Error (214, loc
, "Pointers and fixed size buffers may only be used in an unsafe context");
1082 // Load the object from the pointer.
1084 public static void LoadFromPtr (ILGenerator ig
, Type t
)
1086 if (t
== TypeManager
.int32_type
)
1087 ig
.Emit (OpCodes
.Ldind_I4
);
1088 else if (t
== TypeManager
.uint32_type
)
1089 ig
.Emit (OpCodes
.Ldind_U4
);
1090 else if (t
== TypeManager
.short_type
)
1091 ig
.Emit (OpCodes
.Ldind_I2
);
1092 else if (t
== TypeManager
.ushort_type
)
1093 ig
.Emit (OpCodes
.Ldind_U2
);
1094 else if (t
== TypeManager
.char_type
)
1095 ig
.Emit (OpCodes
.Ldind_U2
);
1096 else if (t
== TypeManager
.byte_type
)
1097 ig
.Emit (OpCodes
.Ldind_U1
);
1098 else if (t
== TypeManager
.sbyte_type
)
1099 ig
.Emit (OpCodes
.Ldind_I1
);
1100 else if (t
== TypeManager
.uint64_type
)
1101 ig
.Emit (OpCodes
.Ldind_I8
);
1102 else if (t
== TypeManager
.int64_type
)
1103 ig
.Emit (OpCodes
.Ldind_I8
);
1104 else if (t
== TypeManager
.float_type
)
1105 ig
.Emit (OpCodes
.Ldind_R4
);
1106 else if (t
== TypeManager
.double_type
)
1107 ig
.Emit (OpCodes
.Ldind_R8
);
1108 else if (t
== TypeManager
.bool_type
)
1109 ig
.Emit (OpCodes
.Ldind_I1
);
1110 else if (t
== TypeManager
.intptr_type
)
1111 ig
.Emit (OpCodes
.Ldind_I
);
1112 else if (TypeManager
.IsEnumType (t
)) {
1113 if (t
== TypeManager
.enum_type
)
1114 ig
.Emit (OpCodes
.Ldind_Ref
);
1116 LoadFromPtr (ig
, TypeManager
.GetEnumUnderlyingType (t
));
1117 } else if (t
.IsValueType
|| TypeManager
.IsGenericParameter (t
))
1118 ig
.Emit (OpCodes
.Ldobj
, t
);
1119 else if (t
.IsPointer
)
1120 ig
.Emit (OpCodes
.Ldind_I
);
1122 ig
.Emit (OpCodes
.Ldind_Ref
);
1126 // The stack contains the pointer and the value of type `type'
1128 public static void StoreFromPtr (ILGenerator ig
, Type type
)
1130 if (TypeManager
.IsEnumType (type
))
1131 type
= TypeManager
.GetEnumUnderlyingType (type
);
1132 if (type
== TypeManager
.int32_type
|| type
== TypeManager
.uint32_type
)
1133 ig
.Emit (OpCodes
.Stind_I4
);
1134 else if (type
== TypeManager
.int64_type
|| type
== TypeManager
.uint64_type
)
1135 ig
.Emit (OpCodes
.Stind_I8
);
1136 else if (type
== TypeManager
.char_type
|| type
== TypeManager
.short_type
||
1137 type
== TypeManager
.ushort_type
)
1138 ig
.Emit (OpCodes
.Stind_I2
);
1139 else if (type
== TypeManager
.float_type
)
1140 ig
.Emit (OpCodes
.Stind_R4
);
1141 else if (type
== TypeManager
.double_type
)
1142 ig
.Emit (OpCodes
.Stind_R8
);
1143 else if (type
== TypeManager
.byte_type
|| type
== TypeManager
.sbyte_type
||
1144 type
== TypeManager
.bool_type
)
1145 ig
.Emit (OpCodes
.Stind_I1
);
1146 else if (type
== TypeManager
.intptr_type
)
1147 ig
.Emit (OpCodes
.Stind_I
);
1148 else if (type
.IsValueType
|| TypeManager
.IsGenericParameter (type
))
1149 ig
.Emit (OpCodes
.Stobj
, type
);
1151 ig
.Emit (OpCodes
.Stind_Ref
);
1155 // Returns the size of type `t' if known, otherwise, 0
1157 public static int GetTypeSize (Type t
)
1159 t
= TypeManager
.TypeToCoreType (t
);
1160 if (t
== TypeManager
.int32_type
||
1161 t
== TypeManager
.uint32_type
||
1162 t
== TypeManager
.float_type
)
1164 else if (t
== TypeManager
.int64_type
||
1165 t
== TypeManager
.uint64_type
||
1166 t
== TypeManager
.double_type
)
1168 else if (t
== TypeManager
.byte_type
||
1169 t
== TypeManager
.sbyte_type
||
1170 t
== TypeManager
.bool_type
)
1172 else if (t
== TypeManager
.short_type
||
1173 t
== TypeManager
.char_type
||
1174 t
== TypeManager
.ushort_type
)
1176 else if (t
== TypeManager
.decimal_type
)
1182 protected void Error_CannotCallAbstractBase (string name
)
1184 Report
.Error (205, loc
, "Cannot call an abstract base member `{0}'", name
);
1187 protected void Error_CannotModifyIntermediateExpressionValue (EmitContext ec
)
1189 Report
.SymbolRelatedToPreviousError (type
);
1190 if (ec
.CurrentInitializerVariable
!= null) {
1191 Report
.Error (1918, loc
, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
1192 TypeManager
.CSharpName (type
), GetSignatureForError ());
1194 Report
.Error (1612, loc
, "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
1195 GetSignatureForError ());
1200 // Converts `source' to an int, uint, long or ulong.
1202 public Expression
ConvertExpressionToArrayIndex (EmitContext ec
, Expression source
)
1204 Expression converted
;
1206 using (ec
.With (EmitContext
.Flags
.CheckState
, true)) {
1207 converted
= Convert
.ImplicitConversion (ec
, source
, TypeManager
.int32_type
, source
.loc
);
1208 if (converted
== null)
1209 converted
= Convert
.ImplicitConversion (ec
, source
, TypeManager
.uint32_type
, source
.loc
);
1210 if (converted
== null)
1211 converted
= Convert
.ImplicitConversion (ec
, source
, TypeManager
.int64_type
, source
.loc
);
1212 if (converted
== null)
1213 converted
= Convert
.ImplicitConversion (ec
, source
, TypeManager
.uint64_type
, source
.loc
);
1215 if (converted
== null) {
1216 source
.Error_ValueCannotBeConverted (ec
, source
.loc
, TypeManager
.int32_type
, false);
1222 // Only positive constants are allowed at compile time
1224 Constant c
= converted
as Constant
;
1227 Error_NegativeArrayIndex (source
.loc
);
1232 return new ArrayIndexCast (converted
).Resolve (ec
);
1236 // Derived classes implement this method by cloning the fields that
1237 // could become altered during the Resolve stage
1239 // Only expressions that are created for the parser need to implement
1242 protected virtual void CloneTo (CloneContext clonectx
, Expression target
)
1244 throw new NotImplementedException (
1246 "CloneTo not implemented for expression {0}", this.GetType ()));
1250 // Clones an expression created by the parser.
1252 // We only support expressions created by the parser so far, not
1253 // expressions that have been resolved (many more classes would need
1254 // to implement CloneTo).
1256 // This infrastructure is here merely for Lambda expressions which
1257 // compile the same code using different type values for the same
1258 // arguments to find the correct overload
1260 public Expression
Clone (CloneContext clonectx
)
1262 Expression cloned
= (Expression
) MemberwiseClone ();
1263 CloneTo (clonectx
, cloned
);
1269 // Implementation of expression to expression tree conversion
1271 public abstract Expression
CreateExpressionTree (EmitContext ec
);
1273 protected Expression
CreateExpressionFactoryCall (string name
, ArrayList args
)
1275 return CreateExpressionFactoryCall (name
, null, args
, loc
);
1278 protected Expression
CreateExpressionFactoryCall (string name
, TypeArguments typeArguments
, ArrayList args
)
1280 return CreateExpressionFactoryCall (name
, typeArguments
, args
, loc
);
1283 public static Expression
CreateExpressionFactoryCall (string name
, TypeArguments typeArguments
, ArrayList args
, Location loc
)
1285 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (loc
), name
, typeArguments
, loc
), args
);
1288 protected static TypeExpr
CreateExpressionTypeExpression (Location loc
)
1290 TypeExpr texpr
= TypeManager
.expression_type_expr
;
1291 if (texpr
== null) {
1292 Type t
= TypeManager
.CoreLookupType ("System.Linq.Expressions", "Expression", Kind
.Class
, true);
1296 TypeManager
.expression_type_expr
= texpr
= new TypeExpression (t
, Location
.Null
);
1302 public virtual void MutateHoistedGenericType (AnonymousMethodStorey storey
)
1304 // TODO: It should probably be type = storey.MutateType (type);
1309 /// This is just a base class for expressions that can
1310 /// appear on statements (invocations, object creation,
1311 /// assignments, post/pre increment and decrement). The idea
1312 /// being that they would support an extra Emition interface that
1313 /// does not leave a result on the stack.
1315 public abstract class ExpressionStatement
: Expression
{
1317 public virtual ExpressionStatement
ResolveStatement (EmitContext ec
)
1319 Expression e
= Resolve (ec
);
1323 ExpressionStatement es
= e
as ExpressionStatement
;
1325 Error_InvalidExpressionStatement ();
1331 /// Requests the expression to be emitted in a `statement'
1332 /// context. This means that no new value is left on the
1333 /// stack after invoking this method (constrasted with
1334 /// Emit that will always leave a value on the stack).
1336 public abstract void EmitStatement (EmitContext ec
);
1338 public override void EmitSideEffect (EmitContext ec
)
1345 /// This kind of cast is used to encapsulate the child
1346 /// whose type is child.Type into an expression that is
1347 /// reported to return "return_type". This is used to encapsulate
1348 /// expressions which have compatible types, but need to be dealt
1349 /// at higher levels with.
1351 /// For example, a "byte" expression could be encapsulated in one
1352 /// of these as an "unsigned int". The type for the expression
1353 /// would be "unsigned int".
1356 public abstract class TypeCast
: Expression
1358 protected readonly Expression child
;
1360 protected TypeCast (Expression child
, Type return_type
)
1362 eclass
= child
.eclass
;
1363 loc
= child
.Location
;
1368 public override Expression
CreateExpressionTree (EmitContext ec
)
1370 ArrayList args
= new ArrayList (2);
1371 args
.Add (new Argument (child
.CreateExpressionTree (ec
)));
1372 args
.Add (new Argument (new TypeOf (new TypeExpression (type
, loc
), loc
)));
1374 if (type
.IsPointer
|| child
.Type
.IsPointer
)
1375 Error_PointerInsideExpressionTree ();
1377 return CreateExpressionFactoryCall (ec
.CheckState
? "ConvertChecked" : "Convert", args
);
1380 public override Expression
DoResolve (EmitContext ec
)
1382 // This should never be invoked, we are born in fully
1383 // initialized state.
1388 public override void Emit (EmitContext ec
)
1393 public override bool GetAttributableValue (EmitContext ec
, Type value_type
, out object value)
1395 return child
.GetAttributableValue (ec
, value_type
, out value);
1398 public override void MutateHoistedGenericType (AnonymousMethodStorey storey
)
1400 type
= storey
.MutateType (type
);
1401 child
.MutateHoistedGenericType (storey
);
1404 protected override void CloneTo (CloneContext clonectx
, Expression t
)
1409 public override bool IsNull
{
1410 get { return child.IsNull; }
1414 public class EmptyCast
: TypeCast
{
1415 EmptyCast (Expression child
, Type target_type
)
1416 : base (child
, target_type
)
1420 public static Expression
Create (Expression child
, Type type
)
1422 Constant c
= child
as Constant
;
1424 return new EmptyConstantCast (c
, type
);
1426 EmptyCast e
= child
as EmptyCast
;
1428 return new EmptyCast (e
.child
, type
);
1430 return new EmptyCast (child
, type
);
1433 public override void EmitBranchable (EmitContext ec
, Label label
, bool on_true
)
1435 child
.EmitBranchable (ec
, label
, on_true
);
1438 public override void EmitSideEffect (EmitContext ec
)
1440 child
.EmitSideEffect (ec
);
1445 // Used for predefined class library user casts (no obsolete check, etc.)
1447 public class OperatorCast
: TypeCast
{
1448 MethodInfo conversion_operator
;
1450 public OperatorCast (Expression child
, Type target_type
)
1451 : this (child
, target_type
, false)
1455 public OperatorCast (Expression child
, Type target_type
, bool find_explicit
)
1456 : base (child
, target_type
)
1458 conversion_operator
= GetConversionOperator (find_explicit
);
1459 if (conversion_operator
== null)
1460 throw new InternalErrorException ("Outer conversion routine is out of sync");
1463 // Returns the implicit operator that converts from
1464 // 'child.Type' to our target type (type)
1465 MethodInfo
GetConversionOperator (bool find_explicit
)
1467 string operator_name
= find_explicit
? "op_Explicit" : "op_Implicit";
1471 mi
= TypeManager
.MemberLookup (child
.Type
, child
.Type
, child
.Type
, MemberTypes
.Method
,
1472 BindingFlags
.Static
| BindingFlags
.Public
, operator_name
, null);
1475 mi
= TypeManager
.MemberLookup (type
, type
, type
, MemberTypes
.Method
,
1476 BindingFlags
.Static
| BindingFlags
.Public
, operator_name
, null);
1479 foreach (MethodInfo oper
in mi
) {
1480 AParametersCollection pd
= TypeManager
.GetParameterData (oper
);
1482 if (pd
.Types
[0] == child
.Type
&& TypeManager
.TypeToCoreType (oper
.ReturnType
) == type
)
1489 public override void Emit (EmitContext ec
)
1492 ec
.ig
.Emit (OpCodes
.Call
, conversion_operator
);
1497 /// This is a numeric cast to a Decimal
1499 public class CastToDecimal
: OperatorCast
{
1500 public CastToDecimal (Expression child
)
1501 : this (child
, false)
1505 public CastToDecimal (Expression child
, bool find_explicit
)
1506 : base (child
, TypeManager
.decimal_type
, find_explicit
)
1512 /// This is an explicit numeric cast from a Decimal
1514 public class CastFromDecimal
: TypeCast
1516 static IDictionary operators
;
1518 public CastFromDecimal (Expression child
, Type return_type
)
1519 : base (child
, return_type
)
1521 if (child
.Type
!= TypeManager
.decimal_type
)
1522 throw new InternalErrorException (
1523 "The expected type is Decimal, instead it is " + child
.Type
.FullName
);
1526 // Returns the explicit operator that converts from an
1527 // express of type System.Decimal to 'type'.
1528 public Expression
Resolve ()
1530 if (operators
== null) {
1531 MemberInfo
[] all_oper
= TypeManager
.MemberLookup (TypeManager
.decimal_type
,
1532 TypeManager
.decimal_type
, TypeManager
.decimal_type
, MemberTypes
.Method
,
1533 BindingFlags
.Static
| BindingFlags
.Public
, "op_Explicit", null);
1535 operators
= new System
.Collections
.Specialized
.HybridDictionary ();
1536 foreach (MethodInfo oper
in all_oper
) {
1537 AParametersCollection pd
= TypeManager
.GetParameterData (oper
);
1538 if (pd
.Types
[0] == TypeManager
.decimal_type
)
1539 operators
.Add (TypeManager
.TypeToCoreType (oper
.ReturnType
), oper
);
1543 return operators
.Contains (type
) ? this : null;
1546 public override void Emit (EmitContext ec
)
1548 ILGenerator ig
= ec
.ig
;
1551 ig
.Emit (OpCodes
.Call
, (MethodInfo
)operators
[type
]);
1557 // Constant specialization of EmptyCast.
1558 // We need to special case this since an empty cast of
1559 // a constant is still a constant.
1561 public class EmptyConstantCast
: Constant
1563 public readonly Constant child
;
1565 public EmptyConstantCast(Constant child
, Type type
)
1566 : base (child
.Location
)
1568 eclass
= child
.eclass
;
1573 public override string AsString ()
1575 return child
.AsString ();
1578 public override object GetValue ()
1580 return child
.GetValue ();
1583 public override Constant
ConvertExplicitly (bool in_checked_context
, Type target_type
)
1585 // FIXME: check that 'type' can be converted to 'target_type' first
1586 return child
.ConvertExplicitly (in_checked_context
, target_type
);
1589 public override Expression
CreateExpressionTree (EmitContext ec
)
1591 ArrayList args
= new ArrayList (2);
1592 args
.Add (new Argument (child
.CreateExpressionTree (ec
)));
1593 args
.Add (new Argument (new TypeOf (new TypeExpression (type
, loc
), loc
)));
1595 Error_PointerInsideExpressionTree ();
1597 return CreateExpressionFactoryCall ("Convert", args
);
1600 public override Constant
Increment ()
1602 return child
.Increment ();
1605 public override bool IsDefaultValue
{
1606 get { return child.IsDefaultValue; }
1609 public override bool IsNegative
{
1610 get { return child.IsNegative; }
1613 public override bool IsNull
{
1614 get { return child.IsNull; }
1617 public override bool IsZeroInteger
{
1618 get { return child.IsZeroInteger; }
1621 public override void Emit (EmitContext ec
)
1626 public override void EmitBranchable (EmitContext ec
, Label label
, bool on_true
)
1628 child
.EmitBranchable (ec
, label
, on_true
);
1631 public override void EmitSideEffect (EmitContext ec
)
1633 child
.EmitSideEffect (ec
);
1636 public override Constant
ConvertImplicitly (Type target_type
)
1638 // FIXME: Do we need to check user conversions?
1639 if (!Convert
.ImplicitStandardConversionExists (this, target_type
))
1641 return child
.ConvertImplicitly (target_type
);
1644 public override void MutateHoistedGenericType (AnonymousMethodStorey storey
)
1646 child
.MutateHoistedGenericType (storey
);
1652 /// This class is used to wrap literals which belong inside Enums
1654 public class EnumConstant
: Constant
{
1655 public Constant Child
;
1657 public EnumConstant (Constant child
, Type enum_type
):
1658 base (child
.Location
)
1660 eclass
= child
.eclass
;
1665 public override Expression
DoResolve (EmitContext ec
)
1667 // This should never be invoked, we are born in fully
1668 // initialized state.
1673 public override void Emit (EmitContext ec
)
1678 public override void EmitBranchable (EmitContext ec
, Label label
, bool on_true
)
1680 Child
.EmitBranchable (ec
, label
, on_true
);
1683 public override void EmitSideEffect (EmitContext ec
)
1685 Child
.EmitSideEffect (ec
);
1688 public override bool GetAttributableValue (EmitContext ec
, Type value_type
, out object value)
1690 value = GetTypedValue ();
1694 public override string GetSignatureForError()
1696 return TypeManager
.CSharpName (Type
);
1699 public override object GetValue ()
1701 return Child
.GetValue ();
1704 public override object GetTypedValue ()
1706 // FIXME: runtime is not ready to work with just emited enums
1707 if (!RootContext
.StdLib
) {
1708 return Child
.GetValue ();
1712 // Small workaround for big problem
1713 // System.Enum.ToObject cannot be called on dynamic types
1714 // EnumBuilder has to be used, but we cannot use EnumBuilder
1715 // because it does not properly support generics
1717 // This works only sometimes
1719 if (type
.Module
== CodeGen
.Module
.Builder
)
1720 return Child
.GetValue ();
1723 return System
.Enum
.ToObject (type
, Child
.GetValue ());
1726 public override string AsString ()
1728 return Child
.AsString ();
1731 public override Constant
Increment()
1733 return new EnumConstant (Child
.Increment (), type
);
1736 public override bool IsDefaultValue
{
1738 return Child
.IsDefaultValue
;
1742 public override bool IsZeroInteger
{
1743 get { return Child.IsZeroInteger; }
1746 public override bool IsNegative
{
1748 return Child
.IsNegative
;
1752 public override Constant
ConvertExplicitly(bool in_checked_context
, Type target_type
)
1754 if (Child
.Type
== target_type
)
1757 return Child
.ConvertExplicitly (in_checked_context
, target_type
);
1760 public override Constant
ConvertImplicitly (Type type
)
1762 Type this_type
= TypeManager
.DropGenericTypeArguments (Type
);
1763 type
= TypeManager
.DropGenericTypeArguments (type
);
1765 if (this_type
== type
) {
1766 // This is workaround of mono bug. It can be removed when the latest corlib spreads enough
1767 if (TypeManager
.IsEnumType (type
.UnderlyingSystemType
))
1770 Type child_type
= TypeManager
.DropGenericTypeArguments (Child
.Type
);
1771 if (type
.UnderlyingSystemType
!= child_type
)
1772 Child
= Child
.ConvertImplicitly (type
.UnderlyingSystemType
);
1776 if (!Convert
.ImplicitStandardConversionExists (this, type
)){
1780 return Child
.ConvertImplicitly(type
);
1786 /// This kind of cast is used to encapsulate Value Types in objects.
1788 /// The effect of it is to box the value type emitted by the previous
1791 public class BoxedCast
: TypeCast
{
1793 public BoxedCast (Expression expr
, Type target_type
)
1794 : base (expr
, target_type
)
1796 eclass
= ExprClass
.Value
;
1799 public override Expression
DoResolve (EmitContext ec
)
1801 // This should never be invoked, we are born in fully
1802 // initialized state.
1807 public override void Emit (EmitContext ec
)
1811 ec
.ig
.Emit (OpCodes
.Box
, child
.Type
);
1814 public override void EmitSideEffect (EmitContext ec
)
1816 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1817 // so, we need to emit the box+pop instructions in most cases
1818 if (child
.Type
.IsValueType
&&
1819 (type
== TypeManager
.object_type
|| type
== TypeManager
.value_type
))
1820 child
.EmitSideEffect (ec
);
1822 base.EmitSideEffect (ec
);
1826 public class UnboxCast
: TypeCast
{
1827 public UnboxCast (Expression expr
, Type return_type
)
1828 : base (expr
, return_type
)
1832 public override Expression
DoResolve (EmitContext ec
)
1834 // This should never be invoked, we are born in fully
1835 // initialized state.
1840 public override Expression
DoResolveLValue (EmitContext ec
, Expression right_side
)
1842 if (right_side
== EmptyExpression
.LValueMemberAccess
|| right_side
== EmptyExpression
.LValueMemberOutAccess
)
1843 Report
.Error (445, loc
, "Cannot modify the result of an unboxing conversion");
1844 return base.DoResolveLValue (ec
, right_side
);
1847 public override void Emit (EmitContext ec
)
1849 ILGenerator ig
= ec
.ig
;
1853 if (type
.IsGenericParameter
|| type
.IsGenericType
&& type
.IsValueType
)
1854 ig
.Emit (OpCodes
.Unbox_Any
, type
);
1858 ig
.Emit (OpCodes
.Unbox
, type
);
1860 LoadFromPtr (ig
, type
);
1864 public override void MutateHoistedGenericType (AnonymousMethodStorey storey
)
1866 type
= storey
.MutateType (type
);
1867 base.MutateHoistedGenericType (storey
);
1872 /// This is used to perform explicit numeric conversions.
1874 /// Explicit numeric conversions might trigger exceptions in a checked
1875 /// context, so they should generate the conv.ovf opcodes instead of
1878 public class ConvCast
: TypeCast
{
1879 public enum Mode
: byte {
1880 I1_U1
, I1_U2
, I1_U4
, I1_U8
, I1_CH
,
1882 I2_I1
, I2_U1
, I2_U2
, I2_U4
, I2_U8
, I2_CH
,
1883 U2_I1
, U2_U1
, U2_I2
, U2_CH
,
1884 I4_I1
, I4_U1
, I4_I2
, I4_U2
, I4_U4
, I4_U8
, I4_CH
,
1885 U4_I1
, U4_U1
, U4_I2
, U4_U2
, U4_I4
, U4_CH
,
1886 I8_I1
, I8_U1
, I8_I2
, I8_U2
, I8_I4
, I8_U4
, I8_U8
, I8_CH
,
1887 U8_I1
, U8_U1
, U8_I2
, U8_U2
, U8_I4
, U8_U4
, U8_I8
, U8_CH
,
1888 CH_I1
, CH_U1
, CH_I2
,
1889 R4_I1
, R4_U1
, R4_I2
, R4_U2
, R4_I4
, R4_U4
, R4_I8
, R4_U8
, R4_CH
,
1890 R8_I1
, R8_U1
, R8_I2
, R8_U2
, R8_I4
, R8_U4
, R8_I8
, R8_U8
, R8_CH
, R8_R4
1895 public ConvCast (Expression child
, Type return_type
, Mode m
)
1896 : base (child
, return_type
)
1901 public override Expression
DoResolve (EmitContext ec
)
1903 // This should never be invoked, we are born in fully
1904 // initialized state.
1909 public override string ToString ()
1911 return String
.Format ("ConvCast ({0}, {1})", mode
, child
);
1914 public override void Emit (EmitContext ec
)
1916 ILGenerator ig
= ec
.ig
;
1922 case Mode
.I1_U1
: ig
.Emit (OpCodes
.Conv_Ovf_U1
); break;
1923 case Mode
.I1_U2
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
1924 case Mode
.I1_U4
: ig
.Emit (OpCodes
.Conv_Ovf_U4
); break;
1925 case Mode
.I1_U8
: ig
.Emit (OpCodes
.Conv_Ovf_U8
); break;
1926 case Mode
.I1_CH
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
1928 case Mode
.U1_I1
: ig
.Emit (OpCodes
.Conv_Ovf_I1_Un
); break;
1929 case Mode
.U1_CH
: /* nothing */ break;
1931 case Mode
.I2_I1
: ig
.Emit (OpCodes
.Conv_Ovf_I1
); break;
1932 case Mode
.I2_U1
: ig
.Emit (OpCodes
.Conv_Ovf_U1
); break;
1933 case Mode
.I2_U2
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
1934 case Mode
.I2_U4
: ig
.Emit (OpCodes
.Conv_Ovf_U4
); break;
1935 case Mode
.I2_U8
: ig
.Emit (OpCodes
.Conv_Ovf_U8
); break;
1936 case Mode
.I2_CH
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
1938 case Mode
.U2_I1
: ig
.Emit (OpCodes
.Conv_Ovf_I1_Un
); break;
1939 case Mode
.U2_U1
: ig
.Emit (OpCodes
.Conv_Ovf_U1_Un
); break;
1940 case Mode
.U2_I2
: ig
.Emit (OpCodes
.Conv_Ovf_I2_Un
); break;
1941 case Mode
.U2_CH
: /* nothing */ break;
1943 case Mode
.I4_I1
: ig
.Emit (OpCodes
.Conv_Ovf_I1
); break;
1944 case Mode
.I4_U1
: ig
.Emit (OpCodes
.Conv_Ovf_U1
); break;
1945 case Mode
.I4_I2
: ig
.Emit (OpCodes
.Conv_Ovf_I2
); break;
1946 case Mode
.I4_U4
: ig
.Emit (OpCodes
.Conv_Ovf_U4
); break;
1947 case Mode
.I4_U2
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
1948 case Mode
.I4_U8
: ig
.Emit (OpCodes
.Conv_Ovf_U8
); break;
1949 case Mode
.I4_CH
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
1951 case Mode
.U4_I1
: ig
.Emit (OpCodes
.Conv_Ovf_I1_Un
); break;
1952 case Mode
.U4_U1
: ig
.Emit (OpCodes
.Conv_Ovf_U1_Un
); break;
1953 case Mode
.U4_I2
: ig
.Emit (OpCodes
.Conv_Ovf_I2_Un
); break;
1954 case Mode
.U4_U2
: ig
.Emit (OpCodes
.Conv_Ovf_U2_Un
); break;
1955 case Mode
.U4_I4
: ig
.Emit (OpCodes
.Conv_Ovf_I4_Un
); break;
1956 case Mode
.U4_CH
: ig
.Emit (OpCodes
.Conv_Ovf_U2_Un
); break;
1958 case Mode
.I8_I1
: ig
.Emit (OpCodes
.Conv_Ovf_I1
); break;
1959 case Mode
.I8_U1
: ig
.Emit (OpCodes
.Conv_Ovf_U1
); break;
1960 case Mode
.I8_I2
: ig
.Emit (OpCodes
.Conv_Ovf_I2
); break;
1961 case Mode
.I8_U2
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
1962 case Mode
.I8_I4
: ig
.Emit (OpCodes
.Conv_Ovf_I4
); break;
1963 case Mode
.I8_U4
: ig
.Emit (OpCodes
.Conv_Ovf_U4
); break;
1964 case Mode
.I8_U8
: ig
.Emit (OpCodes
.Conv_Ovf_U8
); break;
1965 case Mode
.I8_CH
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
1967 case Mode
.U8_I1
: ig
.Emit (OpCodes
.Conv_Ovf_I1_Un
); break;
1968 case Mode
.U8_U1
: ig
.Emit (OpCodes
.Conv_Ovf_U1_Un
); break;
1969 case Mode
.U8_I2
: ig
.Emit (OpCodes
.Conv_Ovf_I2_Un
); break;
1970 case Mode
.U8_U2
: ig
.Emit (OpCodes
.Conv_Ovf_U2_Un
); break;
1971 case Mode
.U8_I4
: ig
.Emit (OpCodes
.Conv_Ovf_I4_Un
); break;
1972 case Mode
.U8_U4
: ig
.Emit (OpCodes
.Conv_Ovf_U4_Un
); break;
1973 case Mode
.U8_I8
: ig
.Emit (OpCodes
.Conv_Ovf_I8_Un
); break;
1974 case Mode
.U8_CH
: ig
.Emit (OpCodes
.Conv_Ovf_U2_Un
); break;
1976 case Mode
.CH_I1
: ig
.Emit (OpCodes
.Conv_Ovf_I1_Un
); break;
1977 case Mode
.CH_U1
: ig
.Emit (OpCodes
.Conv_Ovf_U1_Un
); break;
1978 case Mode
.CH_I2
: ig
.Emit (OpCodes
.Conv_Ovf_I2_Un
); break;
1980 case Mode
.R4_I1
: ig
.Emit (OpCodes
.Conv_Ovf_I1
); break;
1981 case Mode
.R4_U1
: ig
.Emit (OpCodes
.Conv_Ovf_U1
); break;
1982 case Mode
.R4_I2
: ig
.Emit (OpCodes
.Conv_Ovf_I2
); break;
1983 case Mode
.R4_U2
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
1984 case Mode
.R4_I4
: ig
.Emit (OpCodes
.Conv_Ovf_I4
); break;
1985 case Mode
.R4_U4
: ig
.Emit (OpCodes
.Conv_Ovf_U4
); break;
1986 case Mode
.R4_I8
: ig
.Emit (OpCodes
.Conv_Ovf_I8
); break;
1987 case Mode
.R4_U8
: ig
.Emit (OpCodes
.Conv_Ovf_U8
); break;
1988 case Mode
.R4_CH
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
1990 case Mode
.R8_I1
: ig
.Emit (OpCodes
.Conv_Ovf_I1
); break;
1991 case Mode
.R8_U1
: ig
.Emit (OpCodes
.Conv_Ovf_U1
); break;
1992 case Mode
.R8_I2
: ig
.Emit (OpCodes
.Conv_Ovf_I2
); break;
1993 case Mode
.R8_U2
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
1994 case Mode
.R8_I4
: ig
.Emit (OpCodes
.Conv_Ovf_I4
); break;
1995 case Mode
.R8_U4
: ig
.Emit (OpCodes
.Conv_Ovf_U4
); break;
1996 case Mode
.R8_I8
: ig
.Emit (OpCodes
.Conv_Ovf_I8
); break;
1997 case Mode
.R8_U8
: ig
.Emit (OpCodes
.Conv_Ovf_U8
); break;
1998 case Mode
.R8_CH
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
1999 case Mode
.R8_R4
: ig
.Emit (OpCodes
.Conv_R4
); break;
2003 case Mode
.I1_U1
: ig
.Emit (OpCodes
.Conv_U1
); break;
2004 case Mode
.I1_U2
: ig
.Emit (OpCodes
.Conv_U2
); break;
2005 case Mode
.I1_U4
: ig
.Emit (OpCodes
.Conv_U4
); break;
2006 case Mode
.I1_U8
: ig
.Emit (OpCodes
.Conv_I8
); break;
2007 case Mode
.I1_CH
: ig
.Emit (OpCodes
.Conv_U2
); break;
2009 case Mode
.U1_I1
: ig
.Emit (OpCodes
.Conv_I1
); break;
2010 case Mode
.U1_CH
: ig
.Emit (OpCodes
.Conv_U2
); break;
2012 case Mode
.I2_I1
: ig
.Emit (OpCodes
.Conv_I1
); break;
2013 case Mode
.I2_U1
: ig
.Emit (OpCodes
.Conv_U1
); break;
2014 case Mode
.I2_U2
: ig
.Emit (OpCodes
.Conv_U2
); break;
2015 case Mode
.I2_U4
: ig
.Emit (OpCodes
.Conv_U4
); break;
2016 case Mode
.I2_U8
: ig
.Emit (OpCodes
.Conv_I8
); break;
2017 case Mode
.I2_CH
: ig
.Emit (OpCodes
.Conv_U2
); break;
2019 case Mode
.U2_I1
: ig
.Emit (OpCodes
.Conv_I1
); break;
2020 case Mode
.U2_U1
: ig
.Emit (OpCodes
.Conv_U1
); break;
2021 case Mode
.U2_I2
: ig
.Emit (OpCodes
.Conv_I2
); break;
2022 case Mode
.U2_CH
: /* nothing */ break;
2024 case Mode
.I4_I1
: ig
.Emit (OpCodes
.Conv_I1
); break;
2025 case Mode
.I4_U1
: ig
.Emit (OpCodes
.Conv_U1
); break;
2026 case Mode
.I4_I2
: ig
.Emit (OpCodes
.Conv_I2
); break;
2027 case Mode
.I4_U4
: /* nothing */ break;
2028 case Mode
.I4_U2
: ig
.Emit (OpCodes
.Conv_U2
); break;
2029 case Mode
.I4_U8
: ig
.Emit (OpCodes
.Conv_I8
); break;
2030 case Mode
.I4_CH
: ig
.Emit (OpCodes
.Conv_U2
); break;
2032 case Mode
.U4_I1
: ig
.Emit (OpCodes
.Conv_I1
); break;
2033 case Mode
.U4_U1
: ig
.Emit (OpCodes
.Conv_U1
); break;
2034 case Mode
.U4_I2
: ig
.Emit (OpCodes
.Conv_I2
); break;
2035 case Mode
.U4_U2
: ig
.Emit (OpCodes
.Conv_U2
); break;
2036 case Mode
.U4_I4
: /* nothing */ break;
2037 case Mode
.U4_CH
: ig
.Emit (OpCodes
.Conv_U2
); break;
2039 case Mode
.I8_I1
: ig
.Emit (OpCodes
.Conv_I1
); break;
2040 case Mode
.I8_U1
: ig
.Emit (OpCodes
.Conv_U1
); break;
2041 case Mode
.I8_I2
: ig
.Emit (OpCodes
.Conv_I2
); break;
2042 case Mode
.I8_U2
: ig
.Emit (OpCodes
.Conv_U2
); break;
2043 case Mode
.I8_I4
: ig
.Emit (OpCodes
.Conv_I4
); break;
2044 case Mode
.I8_U4
: ig
.Emit (OpCodes
.Conv_U4
); break;
2045 case Mode
.I8_U8
: /* nothing */ break;
2046 case Mode
.I8_CH
: ig
.Emit (OpCodes
.Conv_U2
); break;
2048 case Mode
.U8_I1
: ig
.Emit (OpCodes
.Conv_I1
); break;
2049 case Mode
.U8_U1
: ig
.Emit (OpCodes
.Conv_U1
); break;
2050 case Mode
.U8_I2
: ig
.Emit (OpCodes
.Conv_I2
); break;
2051 case Mode
.U8_U2
: ig
.Emit (OpCodes
.Conv_U2
); break;
2052 case Mode
.U8_I4
: ig
.Emit (OpCodes
.Conv_I4
); break;
2053 case Mode
.U8_U4
: ig
.Emit (OpCodes
.Conv_U4
); break;
2054 case Mode
.U8_I8
: /* nothing */ break;
2055 case Mode
.U8_CH
: ig
.Emit (OpCodes
.Conv_U2
); break;
2057 case Mode
.CH_I1
: ig
.Emit (OpCodes
.Conv_I1
); break;
2058 case Mode
.CH_U1
: ig
.Emit (OpCodes
.Conv_U1
); break;
2059 case Mode
.CH_I2
: ig
.Emit (OpCodes
.Conv_I2
); break;
2061 case Mode
.R4_I1
: ig
.Emit (OpCodes
.Conv_I1
); break;
2062 case Mode
.R4_U1
: ig
.Emit (OpCodes
.Conv_U1
); break;
2063 case Mode
.R4_I2
: ig
.Emit (OpCodes
.Conv_I2
); break;
2064 case Mode
.R4_U2
: ig
.Emit (OpCodes
.Conv_U2
); break;
2065 case Mode
.R4_I4
: ig
.Emit (OpCodes
.Conv_I4
); break;
2066 case Mode
.R4_U4
: ig
.Emit (OpCodes
.Conv_U4
); break;
2067 case Mode
.R4_I8
: ig
.Emit (OpCodes
.Conv_I8
); break;
2068 case Mode
.R4_U8
: ig
.Emit (OpCodes
.Conv_U8
); break;
2069 case Mode
.R4_CH
: ig
.Emit (OpCodes
.Conv_U2
); break;
2071 case Mode
.R8_I1
: ig
.Emit (OpCodes
.Conv_I1
); break;
2072 case Mode
.R8_U1
: ig
.Emit (OpCodes
.Conv_U1
); break;
2073 case Mode
.R8_I2
: ig
.Emit (OpCodes
.Conv_I2
); break;
2074 case Mode
.R8_U2
: ig
.Emit (OpCodes
.Conv_U2
); break;
2075 case Mode
.R8_I4
: ig
.Emit (OpCodes
.Conv_I4
); break;
2076 case Mode
.R8_U4
: ig
.Emit (OpCodes
.Conv_U4
); break;
2077 case Mode
.R8_I8
: ig
.Emit (OpCodes
.Conv_I8
); break;
2078 case Mode
.R8_U8
: ig
.Emit (OpCodes
.Conv_U8
); break;
2079 case Mode
.R8_CH
: ig
.Emit (OpCodes
.Conv_U2
); break;
2080 case Mode
.R8_R4
: ig
.Emit (OpCodes
.Conv_R4
); break;
2086 public class OpcodeCast
: TypeCast
{
2089 public OpcodeCast (Expression child
, Type return_type
, OpCode op
)
2090 : base (child
, return_type
)
2095 public override Expression
DoResolve (EmitContext ec
)
2097 // This should never be invoked, we are born in fully
2098 // initialized state.
2103 public override void Emit (EmitContext ec
)
2109 public Type UnderlyingType
{
2110 get { return child.Type; }
2115 /// This kind of cast is used to encapsulate a child and cast it
2116 /// to the class requested
2118 public sealed class ClassCast
: TypeCast
{
2119 Type child_generic_parameter
;
2121 public ClassCast (Expression child
, Type return_type
)
2122 : base (child
, return_type
)
2125 if (TypeManager
.IsGenericParameter (child
.Type
))
2126 child_generic_parameter
= child
.Type
;
2129 public override Expression
DoResolve (EmitContext ec
)
2131 // This should never be invoked, we are born in fully
2132 // initialized state.
2137 public override void Emit (EmitContext ec
)
2141 if (child_generic_parameter
!= null)
2142 ec
.ig
.Emit (OpCodes
.Box
, child_generic_parameter
);
2145 if (type
.IsGenericParameter
)
2146 ec
.ig
.Emit (OpCodes
.Unbox_Any
, type
);
2149 ec
.ig
.Emit (OpCodes
.Castclass
, type
);
2152 public override void MutateHoistedGenericType (AnonymousMethodStorey storey
)
2154 type
= storey
.MutateType (type
);
2155 if (child_generic_parameter
!= null)
2156 child_generic_parameter
= storey
.MutateGenericArgument (child_generic_parameter
);
2158 base.MutateHoistedGenericType (storey
);
2163 // Created during resolving pahse when an expression is wrapped or constantified
2164 // and original expression can be used later (e.g. for expression trees)
2166 public class ReducedExpression
: Expression
2168 sealed class ReducedConstantExpression
: EmptyConstantCast
2170 readonly Expression orig_expr
;
2172 public ReducedConstantExpression (Constant expr
, Expression orig_expr
)
2173 : base (expr
, expr
.Type
)
2175 this.orig_expr
= orig_expr
;
2178 public override Constant
ConvertImplicitly (Type target_type
)
2180 Constant c
= base.ConvertImplicitly (target_type
);
2182 c
= new ReducedConstantExpression (c
, orig_expr
);
2186 public override Expression
CreateExpressionTree (EmitContext ec
)
2188 return orig_expr
.CreateExpressionTree (ec
);
2191 public override bool GetAttributableValue (EmitContext ec
, Type value_type
, out object value)
2194 // Even if resolved result is a constant original expression was not
2195 // and attribute accepts constants only
2197 Attribute
.Error_AttributeArgumentNotValid (orig_expr
.Location
);
2202 public override Constant
ConvertExplicitly (bool in_checked_context
, Type target_type
)
2204 Constant c
= base.ConvertExplicitly (in_checked_context
, target_type
);
2206 c
= new ReducedConstantExpression (c
, orig_expr
);
2211 sealed class ReducedExpressionStatement
: ExpressionStatement
2213 readonly Expression orig_expr
;
2214 readonly ExpressionStatement stm
;
2216 public ReducedExpressionStatement (ExpressionStatement stm
, Expression orig
)
2218 this.orig_expr
= orig
;
2220 this.loc
= orig
.Location
;
2223 public override Expression
CreateExpressionTree (EmitContext ec
)
2225 return orig_expr
.CreateExpressionTree (ec
);
2228 public override Expression
DoResolve (EmitContext ec
)
2230 eclass
= stm
.eclass
;
2235 public override void Emit (EmitContext ec
)
2240 public override void EmitStatement (EmitContext ec
)
2242 stm
.EmitStatement (ec
);
2245 public override void MutateHoistedGenericType (AnonymousMethodStorey storey
)
2247 stm
.MutateHoistedGenericType (storey
);
2251 readonly Expression expr
, orig_expr
;
2253 private ReducedExpression (Expression expr
, Expression orig_expr
)
2256 this.orig_expr
= orig_expr
;
2257 this.loc
= orig_expr
.Location
;
2260 public static Constant
Create (Constant expr
, Expression original_expr
)
2262 return new ReducedConstantExpression (expr
, original_expr
);
2265 public static ExpressionStatement
Create (ExpressionStatement s
, Expression orig
)
2267 return new ReducedExpressionStatement (s
, orig
);
2270 public static Expression
Create (Expression expr
, Expression original_expr
)
2272 Constant c
= expr
as Constant
;
2274 return Create (c
, original_expr
);
2276 ExpressionStatement s
= expr
as ExpressionStatement
;
2278 return Create (s
, original_expr
);
2280 return new ReducedExpression (expr
, original_expr
);
2283 public override Expression
CreateExpressionTree (EmitContext ec
)
2285 return orig_expr
.CreateExpressionTree (ec
);
2288 public override Expression
DoResolve (EmitContext ec
)
2290 eclass
= expr
.eclass
;
2295 public override void Emit (EmitContext ec
)
2300 public override void EmitBranchable (EmitContext ec
, Label target
, bool on_true
)
2302 expr
.EmitBranchable (ec
, target
, on_true
);
2305 public override void MutateHoistedGenericType (AnonymousMethodStorey storey
)
2307 expr
.MutateHoistedGenericType (storey
);
2312 // Unresolved type name expressions
2314 public abstract class ATypeNameExpression
: FullNamedExpression
2316 public readonly string Name
;
2317 protected TypeArguments targs
;
2319 protected ATypeNameExpression (string name
, Location l
)
2325 protected ATypeNameExpression (string name
, TypeArguments targs
, Location l
)
2332 public bool HasTypeArguments
{
2334 return targs
!= null;
2338 public override string GetSignatureForError ()
2340 if (targs
!= null) {
2341 return TypeManager
.RemoveGenericArity (Name
) + "<" +
2342 targs
.GetSignatureForError () + ">";
2350 /// SimpleName expressions are formed of a single word and only happen at the beginning
2351 /// of a dotted-name.
2353 public class SimpleName
: ATypeNameExpression
{
2356 public SimpleName (string name
, Location l
)
2361 public SimpleName (string name
, TypeArguments args
, Location l
)
2362 : base (name
, args
, l
)
2366 public SimpleName (string name
, TypeParameter
[] type_params
, Location l
)
2369 targs
= new TypeArguments (l
);
2370 foreach (TypeParameter type_param
in type_params
)
2371 targs
.Add (new TypeParameterExpr (type_param
, l
));
2374 public static string RemoveGenericArity (string name
)
2377 StringBuilder sb
= null;
2379 int pos
= name
.IndexOf ('`', start
);
2384 sb
.Append (name
.Substring (start
));
2389 sb
= new StringBuilder ();
2390 sb
.Append (name
.Substring (start
, pos
-start
));
2393 while ((pos
< name
.Length
) && Char
.IsNumber (name
[pos
]))
2397 } while (start
< name
.Length
);
2399 return sb
.ToString ();
2402 public SimpleName
GetMethodGroup ()
2404 return new SimpleName (RemoveGenericArity (Name
), targs
, loc
);
2407 public static void Error_ObjectRefRequired (EmitContext ec
, Location l
, string name
)
2409 if (ec
.IsInFieldInitializer
)
2410 Report
.Error (236, l
,
2411 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2414 Report
.Error (120, l
,
2415 "An object reference is required to access non-static member `{0}'",
2419 public bool IdenticalNameAndTypeName (EmitContext ec
, Expression resolved_to
, Location loc
)
2421 return resolved_to
!= null && resolved_to
.Type
!= null &&
2422 resolved_to
.Type
.Name
== Name
&&
2423 (ec
.DeclContainer
.LookupNamespaceOrType (Name
, loc
, /* ignore_cs0104 = */ true) != null);
2426 public override Expression
DoResolve (EmitContext ec
)
2428 return SimpleNameResolve (ec
, null, false);
2431 public override Expression
DoResolveLValue (EmitContext ec
, Expression right_side
)
2433 return SimpleNameResolve (ec
, right_side
, false);
2437 public Expression
DoResolve (EmitContext ec
, bool intermediate
)
2439 return SimpleNameResolve (ec
, null, intermediate
);
2442 static bool IsNestedChild (Type t
, Type parent
)
2444 while (parent
!= null) {
2445 if (TypeManager
.IsNestedChildOf (t
, TypeManager
.DropGenericTypeArguments (parent
)))
2448 parent
= parent
.BaseType
;
2454 FullNamedExpression
ResolveNested (IResolveContext ec
, Type t
)
2456 if (!TypeManager
.IsGenericTypeDefinition (t
) && !TypeManager
.IsGenericType (t
))
2459 DeclSpace ds
= ec
.DeclContainer
;
2460 while (ds
!= null && !IsNestedChild (t
, ds
.TypeBuilder
))
2466 Type
[] gen_params
= TypeManager
.GetTypeArguments (t
);
2468 int arg_count
= targs
!= null ? targs
.Count
: 0;
2470 for (; (ds
!= null) && ds
.IsGeneric
; ds
= ds
.Parent
) {
2471 if (arg_count
+ ds
.CountTypeParameters
== gen_params
.Length
) {
2472 TypeArguments new_args
= new TypeArguments (loc
);
2473 foreach (TypeParameter param
in ds
.TypeParameters
)
2474 new_args
.Add (new TypeParameterExpr (param
, loc
));
2477 new_args
.Add (targs
);
2479 return new ConstructedType (t
, new_args
, loc
);
2486 public override FullNamedExpression
ResolveAsTypeStep (IResolveContext ec
, bool silent
)
2488 FullNamedExpression fne
= ec
.GenericDeclContainer
.LookupGeneric (Name
, loc
);
2490 return fne
.ResolveAsTypeStep (ec
, silent
);
2492 int errors
= Report
.Errors
;
2493 fne
= ec
.DeclContainer
.LookupNamespaceOrType (Name
, loc
, /*ignore_cs0104=*/ false);
2496 if (fne
.Type
== null)
2499 FullNamedExpression nested
= ResolveNested (ec
, fne
.Type
);
2501 return nested
.ResolveAsTypeStep (ec
, false);
2503 if (targs
!= null) {
2504 ConstructedType ct
= new ConstructedType (fne
, targs
, loc
);
2505 return ct
.ResolveAsTypeStep (ec
, false);
2511 if (silent
|| errors
!= Report
.Errors
)
2514 Error_TypeOrNamespaceNotFound (ec
);
2518 protected virtual void Error_TypeOrNamespaceNotFound (IResolveContext ec
)
2520 MemberCore mc
= ec
.DeclContainer
.GetDefinition (Name
);
2522 Error_UnexpectedKind (ec
.DeclContainer
, "type", GetMemberType (mc
), loc
);
2526 string ns
= ec
.DeclContainer
.NamespaceEntry
.NS
.Name
;
2527 string fullname
= (ns
.Length
> 0) ? ns
+ "." + Name
: Name
;
2528 foreach (Assembly a
in RootNamespace
.Global
.Assemblies
) {
2529 Type type
= a
.GetType (fullname
);
2531 Report
.SymbolRelatedToPreviousError (type
);
2532 Expression
.ErrorIsInaccesible (loc
, TypeManager
.CSharpName (type
));
2537 Type t
= ec
.DeclContainer
.LookupAnyGeneric (Name
);
2539 Namespace
.Error_InvalidNumberOfTypeArguments (t
, loc
);
2543 if (targs
!= null) {
2544 FullNamedExpression retval
= ec
.DeclContainer
.LookupNamespaceOrType (SimpleName
.RemoveGenericArity (Name
), loc
, true);
2545 if (retval
!= null) {
2546 Namespace
.Error_TypeArgumentsCannotBeUsed (retval
.Type
, loc
);
2551 NamespaceEntry
.Error_NamespaceNotFound (loc
, Name
);
2554 // TODO: I am still not convinced about this. If someone else will need it
2555 // implement this as virtual property in MemberCore hierarchy
2556 public static string GetMemberType (MemberCore mc
)
2562 if (mc
is FieldBase
)
2564 if (mc
is MethodCore
)
2566 if (mc
is EnumMember
)
2574 Expression
SimpleNameResolve (EmitContext ec
, Expression right_side
, bool intermediate
)
2580 Expression e
= DoSimpleNameResolve (ec
, right_side
, intermediate
);
2586 if (ec
.CurrentBlock
== null || ec
.CurrentBlock
.CheckInvariantMeaningInBlock (Name
, e
, Location
))
2593 /// 7.5.2: Simple Names.
2595 /// Local Variables and Parameters are handled at
2596 /// parse time, so they never occur as SimpleNames.
2598 /// The `intermediate' flag is used by MemberAccess only
2599 /// and it is used to inform us that it is ok for us to
2600 /// avoid the static check, because MemberAccess might end
2601 /// up resolving the Name as a Type name and the access as
2602 /// a static type access.
2604 /// ie: Type Type; .... { Type.GetType (""); }
2606 /// Type is both an instance variable and a Type; Type.GetType
2607 /// is the static method not an instance method of type.
2609 Expression
DoSimpleNameResolve (EmitContext ec
, Expression right_side
, bool intermediate
)
2611 Expression e
= null;
2614 // Stage 1: Performed by the parser (binding to locals or parameters).
2616 Block current_block
= ec
.CurrentBlock
;
2617 if (current_block
!= null){
2618 LocalInfo vi
= current_block
.GetLocalInfo (Name
);
2620 if (targs
!= null) {
2621 Report
.Error (307, loc
,
2622 "The variable `{0}' cannot be used with type arguments",
2627 LocalVariableReference
var = new LocalVariableReference (ec
.CurrentBlock
, Name
, loc
);
2628 if (right_side
!= null) {
2629 return var.ResolveLValue (ec
, right_side
, loc
);
2631 ResolveFlags rf
= ResolveFlags
.VariableOrValue
;
2633 rf
|= ResolveFlags
.DisableFlowAnalysis
;
2634 return var.Resolve (ec
, rf
);
2638 ParameterReference pref
= current_block
.Toplevel
.GetParameterReference (Name
, loc
);
2640 if (targs
!= null) {
2641 Report
.Error (307, loc
,
2642 "The variable `{0}' cannot be used with type arguments",
2647 if (right_side
!= null)
2648 return pref
.ResolveLValue (ec
, right_side
, loc
);
2650 return pref
.Resolve (ec
);
2653 Expression expr
= current_block
.Toplevel
.GetTransparentIdentifier (Name
);
2655 if (right_side
!= null)
2656 return expr
.ResolveLValue (ec
, right_side
, loc
);
2657 return expr
.Resolve (ec
);
2662 // Stage 2: Lookup members
2665 Type almost_matched_type
= null;
2666 ArrayList almost_matched
= null;
2667 for (DeclSpace lookup_ds
= ec
.DeclContainer
; lookup_ds
!= null; lookup_ds
= lookup_ds
.Parent
) {
2668 // either RootDeclSpace or GenericMethod
2669 if (lookup_ds
.TypeBuilder
== null)
2672 e
= MemberLookup (ec
.ContainerType
, lookup_ds
.TypeBuilder
, Name
, loc
);
2674 PropertyExpr pe
= e
as PropertyExpr
;
2676 AParametersCollection param
= TypeManager
.GetParameterData (pe
.PropertyInfo
);
2678 // since TypeManager.MemberLookup doesn't know if we're doing a lvalue access or not,
2679 // it doesn't know which accessor to check permissions against
2680 if (param
.IsEmpty
&& pe
.IsAccessibleFrom (ec
.ContainerType
, right_side
!= null))
2682 } else if (e
is EventExpr
) {
2683 if (((EventExpr
) e
).IsAccessibleFrom (ec
.ContainerType
))
2691 if (almost_matched
== null && almost_matched_members
.Count
> 0) {
2692 almost_matched_type
= lookup_ds
.TypeBuilder
;
2693 almost_matched
= (ArrayList
) almost_matched_members
.Clone ();
2698 if (almost_matched
== null && almost_matched_members
.Count
> 0) {
2699 almost_matched_type
= ec
.ContainerType
;
2700 almost_matched
= (ArrayList
) almost_matched_members
.Clone ();
2702 e
= ResolveAsTypeStep (ec
, true);
2706 if (current_block
!= null) {
2707 IKnownVariable ikv
= current_block
.Explicit
.GetKnownVariable (Name
);
2709 LocalInfo li
= ikv
as LocalInfo
;
2710 // Supress CS0219 warning
2714 Error_VariableIsUsedBeforeItIsDeclared (Name
);
2719 if (RootContext
.EvalMode
){
2720 FieldInfo fi
= Evaluator
.LookupField (Name
);
2722 return new FieldExpr (fi
, loc
).Resolve (ec
);
2725 if (almost_matched
!= null)
2726 almost_matched_members
= almost_matched
;
2727 if (almost_matched_type
== null)
2728 almost_matched_type
= ec
.ContainerType
;
2729 Error_MemberLookupFailed (ec
.ContainerType
, null, almost_matched_type
, Name
,
2730 ec
.DeclContainer
.Name
, AllMemberTypes
, AllBindingFlags
);
2734 if (e
is TypeExpr
) {
2738 ConstructedType ct
= new ConstructedType (
2739 e
.Type
, targs
, loc
);
2740 return ct
.ResolveAsTypeStep (ec
, false);
2743 if (e
is MemberExpr
) {
2744 MemberExpr me
= (MemberExpr
) e
;
2747 if (me
.IsInstance
) {
2748 if (ec
.IsStatic
|| ec
.IsInFieldInitializer
) {
2750 // Note that an MemberExpr can be both IsInstance and IsStatic.
2751 // An unresolved MethodGroupExpr can contain both kinds of methods
2752 // and each predicate is true if the MethodGroupExpr contains
2753 // at least one of that kind of method.
2757 (!intermediate
|| !IdenticalNameAndTypeName (ec
, me
, loc
))) {
2758 Error_ObjectRefRequired (ec
, loc
, me
.GetSignatureForError ());
2763 // Pass the buck to MemberAccess and Invocation.
2765 left
= EmptyExpression
.Null
;
2767 left
= ec
.GetThis (loc
);
2770 left
= new TypeExpression (ec
.ContainerType
, loc
);
2773 me
= me
.ResolveMemberAccess (ec
, left
, loc
, null);
2777 if (targs
!= null) {
2779 me
.SetTypeArguments (targs
);
2782 if (!me
.IsStatic
&& (me
.InstanceExpression
!= null) &&
2783 TypeManager
.IsNestedFamilyAccessible (me
.InstanceExpression
.Type
, me
.DeclaringType
) &&
2784 me
.InstanceExpression
.Type
!= me
.DeclaringType
&&
2785 !TypeManager
.IsFamilyAccessible (me
.InstanceExpression
.Type
, me
.DeclaringType
) &&
2786 (!intermediate
|| !IdenticalNameAndTypeName (ec
, e
, loc
))) {
2787 Report
.Error (38, loc
, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2788 TypeManager
.CSharpName (me
.DeclaringType
), TypeManager
.CSharpName (me
.InstanceExpression
.Type
));
2792 return (right_side
!= null)
2793 ? me
.DoResolveLValue (ec
, right_side
)
2794 : me
.DoResolve (ec
);
2800 protected override void CloneTo (CloneContext clonectx
, Expression target
)
2802 // CloneTo: Nothing, we do not keep any state on this expression
2807 /// Represents a namespace or a type. The name of the class was inspired by
2808 /// section 10.8.1 (Fully Qualified Names).
2810 public abstract class FullNamedExpression
: Expression
{
2812 public override Expression
CreateExpressionTree (EmitContext ec
)
2814 throw new NotSupportedException ("ET");
2817 public override void MutateHoistedGenericType (AnonymousMethodStorey storey
)
2819 throw new NotSupportedException ();
2822 public override FullNamedExpression
ResolveAsTypeStep (IResolveContext ec
, bool silent
)
2827 public override void Emit (EmitContext ec
)
2829 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2830 GetSignatureForError ());
2835 /// Expression that evaluates to a type
2837 public abstract class TypeExpr
: FullNamedExpression
{
2838 public override FullNamedExpression
ResolveAsTypeStep (IResolveContext ec
, bool silent
)
2840 TypeExpr t
= DoResolveAsTypeStep (ec
);
2844 eclass
= ExprClass
.Type
;
2848 override public Expression
DoResolve (EmitContext ec
)
2850 return ResolveAsTypeTerminal (ec
, false);
2853 public virtual bool CheckAccessLevel (DeclSpace ds
)
2855 return ds
.CheckAccessLevel (Type
);
2858 public virtual bool AsAccessible (DeclSpace ds
)
2860 return ds
.IsAccessibleAs (Type
);
2863 public virtual bool IsClass
{
2864 get { return Type.IsClass; }
2867 public virtual bool IsValueType
{
2868 get { return Type.IsValueType; }
2871 public virtual bool IsInterface
{
2872 get { return Type.IsInterface; }
2875 public virtual bool IsSealed
{
2876 get { return Type.IsSealed; }
2879 public virtual bool CanInheritFrom ()
2881 if (Type
== TypeManager
.enum_type
||
2882 (Type
== TypeManager
.value_type
&& RootContext
.StdLib
) ||
2883 Type
== TypeManager
.multicast_delegate_type
||
2884 Type
== TypeManager
.delegate_type
||
2885 Type
== TypeManager
.array_type
)
2891 protected abstract TypeExpr
DoResolveAsTypeStep (IResolveContext ec
);
2893 public override bool Equals (object obj
)
2895 TypeExpr tobj
= obj
as TypeExpr
;
2899 return Type
== tobj
.Type
;
2902 public override int GetHashCode ()
2904 return Type
.GetHashCode ();
2907 public override void MutateHoistedGenericType (AnonymousMethodStorey storey
)
2909 type
= storey
.MutateType (type
);
2914 /// Fully resolved Expression that already evaluated to a type
2916 public class TypeExpression
: TypeExpr
{
2917 public TypeExpression (Type t
, Location l
)
2920 eclass
= ExprClass
.Type
;
2924 protected override TypeExpr
DoResolveAsTypeStep (IResolveContext ec
)
2929 public override TypeExpr
ResolveAsTypeTerminal (IResolveContext ec
, bool silent
)
2936 /// Used to create types from a fully qualified name. These are just used
2937 /// by the parser to setup the core types. A TypeLookupExpression is always
2938 /// classified as a type.
2940 public sealed class TypeLookupExpression
: TypeExpr
{
2941 readonly string name
;
2943 public TypeLookupExpression (string name
)
2946 eclass
= ExprClass
.Type
;
2949 public override TypeExpr
ResolveAsTypeTerminal (IResolveContext ec
, bool silent
)
2951 // It's null for corlib compilation only
2953 return DoResolveAsTypeStep (ec
);
2958 private class UnexpectedType
2962 // This performes recursive type lookup, providing support for generic types.
2963 // For example, given the type:
2965 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]]
2967 // The types will be checked in the following order:
2970 // System.Collections |
2971 // System.Collections.Generic |
2973 // System | recursive call 1 |
2974 // System.Int32 _| | main method call
2976 // System | recursive call 2 |
2977 // System.String _| |
2979 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]] _|
2981 private Type
TypeLookup (IResolveContext ec
, string name
)
2986 FullNamedExpression resolved
= null;
2988 Type recursive_type
= null;
2989 while (index
< name
.Length
) {
2990 if (name
[index
] == '[') {
2995 if (name
[index
] == '[')
2997 else if (name
[index
] == ']')
2999 } while (braces
> 0);
3000 recursive_type
= TypeLookup (ec
, name
.Substring (open
+ 1, index
- open
- 1));
3001 if (recursive_type
== null || (recursive_type
== typeof(UnexpectedType
)))
3002 return recursive_type
;
3005 if (name
[index
] == ',')
3007 else if ((name
[index
] == '.' && !done
) || (index
== name
.Length
&& name
[0] != '[')) {
3008 string substring
= name
.Substring(dot
, index
- dot
);
3010 if (resolved
== null)
3011 resolved
= RootNamespace
.Global
.Lookup (ec
.DeclContainer
, substring
, Location
.Null
);
3012 else if (resolved
is Namespace
)
3013 resolved
= (resolved
as Namespace
).Lookup (ec
.DeclContainer
, substring
, Location
.Null
);
3014 else if (type
!= null)
3015 type
= TypeManager
.GetNestedType (type
, substring
);
3019 if (resolved
== null)
3021 else if (type
== null && resolved
is TypeExpr
)
3022 type
= resolved
.Type
;
3029 if (name
[0] != '[') {
3030 string substring
= name
.Substring(dot
, index
- dot
);
3033 return TypeManager
.GetNestedType (type
, substring
);
3035 if (resolved
!= null) {
3036 resolved
= (resolved
as Namespace
).Lookup (ec
.DeclContainer
, substring
, Location
.Null
);
3037 if (resolved
is TypeExpr
)
3038 return resolved
.Type
;
3040 if (resolved
== null)
3043 resolved
.Error_UnexpectedKind (ec
.DeclContainer
, "type", loc
);
3044 return typeof (UnexpectedType
);
3050 return recursive_type
;
3053 protected override TypeExpr
DoResolveAsTypeStep (IResolveContext ec
)
3055 Type t
= TypeLookup (ec
, name
);
3057 NamespaceEntry
.Error_NamespaceNotFound (loc
, name
);
3060 if (t
== typeof(UnexpectedType
))
3066 protected override void CloneTo (CloneContext clonectx
, Expression target
)
3068 // CloneTo: Nothing, we do not keep any state on this expression
3071 public override string GetSignatureForError ()
3074 return TypeManager
.CSharpName (name
, null);
3076 return base.GetSignatureForError ();
3081 /// Represents an "unbound generic type", ie. typeof (Foo<>).
3084 public class UnboundTypeExpression
: TypeExpr
3088 public UnboundTypeExpression (MemberName name
, Location l
)
3094 protected override void CloneTo (CloneContext clonectx
, Expression target
)
3099 protected override TypeExpr
DoResolveAsTypeStep (IResolveContext ec
)
3102 if (name
.Left
!= null) {
3103 Expression lexpr
= name
.Left
.GetTypeExpression ();
3104 expr
= new MemberAccess (lexpr
, name
.Basename
);
3106 expr
= new SimpleName (name
.Basename
, loc
);
3109 FullNamedExpression fne
= expr
.ResolveAsTypeStep (ec
, false);
3114 return new TypeExpression (type
, loc
);
3119 /// This class denotes an expression which evaluates to a member
3120 /// of a struct or a class.
3122 public abstract class MemberExpr
: Expression
3124 protected bool is_base
;
3127 /// The name of this member.
3129 public abstract string Name
{
3134 // When base.member is used
3136 public bool IsBase
{
3137 get { return is_base; }
3138 set { is_base = value; }
3142 /// Whether this is an instance member.
3144 public abstract bool IsInstance
{
3149 /// Whether this is a static member.
3151 public abstract bool IsStatic
{
3156 /// The type which declares this member.
3158 public abstract Type DeclaringType
{
3163 /// The instance expression associated with this member, if it's a
3164 /// non-static member.
3166 public Expression InstanceExpression
;
3168 public static void error176 (Location loc
, string name
)
3170 Report
.Error (176, loc
, "Static member `{0}' cannot be accessed " +
3171 "with an instance reference, qualify it with a type name instead", name
);
3174 public static void Error_BaseAccessInExpressionTree (Location loc
)
3176 Report
.Error (831, loc
, "An expression tree may not contain a base access");
3179 public override void MutateHoistedGenericType (AnonymousMethodStorey storey
)
3181 if (InstanceExpression
!= null)
3182 InstanceExpression
.MutateHoistedGenericType (storey
);
3185 // TODO: possible optimalization
3186 // Cache resolved constant result in FieldBuilder <-> expression map
3187 public virtual MemberExpr
ResolveMemberAccess (EmitContext ec
, Expression left
, Location loc
,
3188 SimpleName original
)
3192 // original == null || original.Resolve (...) ==> left
3195 if (left
is TypeExpr
) {
3196 left
= left
.ResolveAsBaseTerminal (ec
, false);
3200 // TODO: Same problem as in class.cs, TypeTerminal does not
3201 // always do all necessary checks
3202 ObsoleteAttribute oa
= AttributeTester
.GetObsoleteAttribute (left
.Type
);
3203 if (oa
!= null && !ec
.IsInObsoleteScope
) {
3204 AttributeTester
.Report_ObsoleteMessage (oa
, left
.GetSignatureForError (), loc
);
3207 ConstructedType ct
= left
as ConstructedType
;
3208 if (ct
!= null && !ct
.CheckConstraints (ec
))
3213 SimpleName
.Error_ObjectRefRequired (ec
, loc
, GetSignatureForError ());
3221 if (original
!= null && original
.IdenticalNameAndTypeName (ec
, left
, loc
))
3224 return ResolveExtensionMemberAccess (left
);
3227 InstanceExpression
= left
;
3231 protected virtual MemberExpr
ResolveExtensionMemberAccess (Expression left
)
3233 error176 (loc
, GetSignatureForError ());
3237 protected void EmitInstance (EmitContext ec
, bool prepare_for_load
)
3242 if (InstanceExpression
== EmptyExpression
.Null
) {
3243 SimpleName
.Error_ObjectRefRequired (ec
, loc
, GetSignatureForError ());
3247 if (InstanceExpression
.Type
.IsValueType
) {
3248 if (InstanceExpression
is IMemoryLocation
) {
3249 ((IMemoryLocation
) InstanceExpression
).AddressOf (ec
, AddressOp
.LoadStore
);
3251 LocalTemporary t
= new LocalTemporary (InstanceExpression
.Type
);
3252 InstanceExpression
.Emit (ec
);
3254 t
.AddressOf (ec
, AddressOp
.Store
);
3257 InstanceExpression
.Emit (ec
);
3259 if (prepare_for_load
)
3260 ec
.ig
.Emit (OpCodes
.Dup
);
3263 public virtual void SetTypeArguments (TypeArguments ta
)
3265 // TODO: need to get correct member type
3266 Report
.Error (307, loc
, "The property `{0}' cannot be used with type arguments",
3267 GetSignatureForError ());
3272 /// Represents group of extension methods
3274 public class ExtensionMethodGroupExpr
: MethodGroupExpr
3276 readonly NamespaceEntry namespace_entry
;
3277 public Expression ExtensionExpression
;
3278 Argument extension_argument
;
3280 public ExtensionMethodGroupExpr (ArrayList list
, NamespaceEntry n
, Type extensionType
, Location l
)
3281 : base (list
, extensionType
, l
)
3283 this.namespace_entry
= n
;
3286 public override bool IsStatic
{
3287 get { return true; }
3290 public bool IsTopLevel
{
3291 get { return namespace_entry == null; }
3294 public override void EmitArguments (EmitContext ec
, ArrayList arguments
)
3296 if (arguments
== null)
3297 arguments
= new ArrayList (1);
3298 arguments
.Insert (0, extension_argument
);
3299 base.EmitArguments (ec
, arguments
);
3302 public override void EmitCall (EmitContext ec
, ArrayList arguments
)
3304 if (arguments
== null)
3305 arguments
= new ArrayList (1);
3306 arguments
.Insert (0, extension_argument
);
3307 base.EmitCall (ec
, arguments
);
3310 public override void MutateHoistedGenericType (AnonymousMethodStorey storey
)
3312 extension_argument
.Expr
.MutateHoistedGenericType (storey
);
3313 base.MutateHoistedGenericType (storey
);
3316 public override MethodGroupExpr
OverloadResolve (EmitContext ec
, ref ArrayList arguments
, bool may_fail
, Location loc
)
3318 if (arguments
== null)
3319 arguments
= new ArrayList (1);
3321 arguments
.Insert (0, new Argument (ExtensionExpression
));
3322 MethodGroupExpr mg
= ResolveOverloadExtensions (ec
, arguments
, namespace_entry
, loc
);
3324 // Store resolved argument and restore original arguments
3326 ((ExtensionMethodGroupExpr
)mg
).extension_argument
= (Argument
)arguments
[0];
3327 arguments
.RemoveAt (0);
3332 MethodGroupExpr
ResolveOverloadExtensions (EmitContext ec
, ArrayList arguments
, NamespaceEntry ns
, Location loc
)
3334 // Use normal resolve rules
3335 MethodGroupExpr mg
= base.OverloadResolve (ec
, ref arguments
, ns
!= null, loc
);
3343 ExtensionMethodGroupExpr e
= ns
.LookupExtensionMethod (type
, null, Name
, loc
);
3345 return base.OverloadResolve (ec
, ref arguments
, false, loc
);
3347 e
.ExtensionExpression
= ExtensionExpression
;
3348 e
.SetTypeArguments (type_arguments
);
3349 return e
.ResolveOverloadExtensions (ec
, arguments
, e
.namespace_entry
, loc
);
3354 /// MethodGroupExpr represents a group of method candidates which
3355 /// can be resolved to the best method overload
3357 public class MethodGroupExpr
: MemberExpr
3359 public interface IErrorHandler
3361 bool NoExactMatch (EmitContext ec
, MethodBase method
);
3364 public IErrorHandler CustomErrorHandler
;
3365 public MethodBase
[] Methods
;
3366 MethodBase best_candidate
;
3367 // TODO: make private
3368 public TypeArguments type_arguments
;
3369 bool identical_type_name
;
3372 public MethodGroupExpr (MemberInfo
[] mi
, Type type
, Location l
)
3375 Methods
= new MethodBase
[mi
.Length
];
3376 mi
.CopyTo (Methods
, 0);
3379 public MethodGroupExpr (ArrayList list
, Type type
, Location l
)
3383 Methods
= (MethodBase
[])list
.ToArray (typeof (MethodBase
));
3385 foreach (MemberInfo m
in list
){
3386 if (!(m
is MethodBase
)){
3387 Console
.WriteLine ("Name " + m
.Name
);
3388 Console
.WriteLine ("Found a: " + m
.GetType ().FullName
);
3397 protected MethodGroupExpr (Type type
, Location loc
)
3400 eclass
= ExprClass
.MethodGroup
;
3404 public override Type DeclaringType
{
3407 // We assume that the top-level type is in the end
3409 return Methods
[Methods
.Length
- 1].DeclaringType
;
3410 //return Methods [0].DeclaringType;
3414 public Type DelegateType
{
3416 delegate_type
= value;
3420 public bool IdenticalTypeName
{
3422 return identical_type_name
;
3426 public override string GetSignatureForError ()
3428 if (best_candidate
!= null)
3429 return TypeManager
.CSharpSignature (best_candidate
);
3431 return TypeManager
.CSharpSignature (Methods
[0]);
3434 public override string Name
{
3436 return Methods
[0].Name
;
3440 public override bool IsInstance
{
3442 if (best_candidate
!= null)
3443 return !best_candidate
.IsStatic
;
3445 foreach (MethodBase mb
in Methods
)
3453 public override bool IsStatic
{
3455 if (best_candidate
!= null)
3456 return best_candidate
.IsStatic
;
3458 foreach (MethodBase mb
in Methods
)
3466 public static explicit operator ConstructorInfo (MethodGroupExpr mg
)
3468 return (ConstructorInfo
)mg
.best_candidate
;
3471 public static explicit operator MethodInfo (MethodGroupExpr mg
)
3473 return (MethodInfo
)mg
.best_candidate
;
3477 // 7.4.3.3 Better conversion from expression
3478 // Returns : 1 if a->p is better,
3479 // 2 if a->q is better,
3480 // 0 if neither is better
3482 static int BetterExpressionConversion (EmitContext ec
, Argument a
, Type p
, Type q
)
3484 Type argument_type
= TypeManager
.TypeToCoreType (a
.Type
);
3485 if (argument_type
== TypeManager
.anonymous_method_type
&& RootContext
.Version
> LanguageVersion
.ISO_2
) {
3487 // Uwrap delegate from Expression<T>
3489 if (TypeManager
.DropGenericTypeArguments (p
) == TypeManager
.expression_type
) {
3490 p
= TypeManager
.GetTypeArguments (p
) [0];
3492 if (TypeManager
.DropGenericTypeArguments (q
) == TypeManager
.expression_type
) {
3493 q
= TypeManager
.GetTypeArguments (q
) [0];
3496 p
= Delegate
.GetInvokeMethod (null, p
).ReturnType
;
3497 q
= Delegate
.GetInvokeMethod (null, q
).ReturnType
;
3498 if (p
== TypeManager
.void_type
&& q
!= TypeManager
.void_type
)
3500 if (q
== TypeManager
.void_type
&& p
!= TypeManager
.void_type
)
3503 if (argument_type
== p
)
3506 if (argument_type
== q
)
3510 return BetterTypeConversion (ec
, p
, q
);
3514 // 7.4.3.4 Better conversion from type
3516 public static int BetterTypeConversion (EmitContext ec
, Type p
, Type q
)
3518 if (p
== null || q
== null)
3519 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3521 if (p
== TypeManager
.int32_type
) {
3522 if (q
== TypeManager
.uint32_type
|| q
== TypeManager
.uint64_type
)
3524 } else if (p
== TypeManager
.int64_type
) {
3525 if (q
== TypeManager
.uint64_type
)
3527 } else if (p
== TypeManager
.sbyte_type
) {
3528 if (q
== TypeManager
.byte_type
|| q
== TypeManager
.ushort_type
||
3529 q
== TypeManager
.uint32_type
|| q
== TypeManager
.uint64_type
)
3531 } else if (p
== TypeManager
.short_type
) {
3532 if (q
== TypeManager
.ushort_type
|| q
== TypeManager
.uint32_type
||
3533 q
== TypeManager
.uint64_type
)
3537 if (q
== TypeManager
.int32_type
) {
3538 if (p
== TypeManager
.uint32_type
|| p
== TypeManager
.uint64_type
)
3540 } if (q
== TypeManager
.int64_type
) {
3541 if (p
== TypeManager
.uint64_type
)
3543 } else if (q
== TypeManager
.sbyte_type
) {
3544 if (p
== TypeManager
.byte_type
|| p
== TypeManager
.ushort_type
||
3545 p
== TypeManager
.uint32_type
|| p
== TypeManager
.uint64_type
)
3547 } if (q
== TypeManager
.short_type
) {
3548 if (p
== TypeManager
.ushort_type
|| p
== TypeManager
.uint32_type
||
3549 p
== TypeManager
.uint64_type
)
3553 // TODO: this is expensive
3554 Expression p_tmp
= new EmptyExpression (p
);
3555 Expression q_tmp
= new EmptyExpression (q
);
3557 bool p_to_q
= Convert
.ImplicitConversionExists (ec
, p_tmp
, q
);
3558 bool q_to_p
= Convert
.ImplicitConversionExists (ec
, q_tmp
, p
);
3560 if (p_to_q
&& !q_to_p
)
3563 if (q_to_p
&& !p_to_q
)
3570 /// Determines "Better function" between candidate
3571 /// and the current best match
3574 /// Returns a boolean indicating :
3575 /// false if candidate ain't better
3576 /// true if candidate is better than the current best match
3578 static bool BetterFunction (EmitContext ec
, ArrayList args
, int argument_count
,
3579 MethodBase candidate
, bool candidate_params
,
3580 MethodBase best
, bool best_params
)
3582 AParametersCollection candidate_pd
= TypeManager
.GetParameterData (candidate
);
3583 AParametersCollection best_pd
= TypeManager
.GetParameterData (best
);
3585 bool better_at_least_one
= false;
3587 for (int j
= 0, c_idx
= 0, b_idx
= 0; j
< argument_count
; ++j
, ++c_idx
, ++b_idx
)
3589 Argument a
= (Argument
) args
[j
];
3591 Type ct
= candidate_pd
.Types
[c_idx
];
3592 Type bt
= best_pd
.Types
[b_idx
];
3594 if (candidate_params
&& candidate_pd
.FixedParameters
[c_idx
].ModFlags
== Parameter
.Modifier
.PARAMS
)
3596 ct
= TypeManager
.GetElementType (ct
);
3600 if (best_params
&& best_pd
.FixedParameters
[b_idx
].ModFlags
== Parameter
.Modifier
.PARAMS
)
3602 bt
= TypeManager
.GetElementType (bt
);
3610 int result
= BetterExpressionConversion (ec
, a
, ct
, bt
);
3612 // for each argument, the conversion to 'ct' should be no worse than
3613 // the conversion to 'bt'.
3617 // for at least one argument, the conversion to 'ct' should be better than
3618 // the conversion to 'bt'.
3620 better_at_least_one
= true;
3623 if (better_at_least_one
)
3627 // This handles the case
3629 // Add (float f1, float f2, float f3);
3630 // Add (params decimal [] foo);
3632 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3633 // first candidate would've chosen as better.
3639 // The two methods have equal parameter types. Now apply tie-breaking rules
3641 if (TypeManager
.IsGenericMethod (best
) && !TypeManager
.IsGenericMethod (candidate
))
3643 if (!TypeManager
.IsGenericMethod (best
) && TypeManager
.IsGenericMethod (candidate
))
3647 // This handles the following cases:
3649 // Trim () is better than Trim (params char[] chars)
3650 // Concat (string s1, string s2, string s3) is better than
3651 // Concat (string s1, params string [] srest)
3652 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3654 if (!candidate_params
&& best_params
)
3656 if (candidate_params
&& !best_params
)
3659 int candidate_param_count
= candidate_pd
.Count
;
3660 int best_param_count
= best_pd
.Count
;
3662 if (candidate_param_count
!= best_param_count
)
3663 // can only happen if (candidate_params && best_params)
3664 return candidate_param_count
> best_param_count
;
3667 // now, both methods have the same number of parameters, and the parameters have the same types
3668 // Pick the "more specific" signature
3671 MethodBase orig_candidate
= TypeManager
.DropGenericMethodArguments (candidate
);
3672 MethodBase orig_best
= TypeManager
.DropGenericMethodArguments (best
);
3674 AParametersCollection orig_candidate_pd
= TypeManager
.GetParameterData (orig_candidate
);
3675 AParametersCollection orig_best_pd
= TypeManager
.GetParameterData (orig_best
);
3677 bool specific_at_least_once
= false;
3678 for (int j
= 0; j
< candidate_param_count
; ++j
)
3680 Type ct
= orig_candidate_pd
.Types
[j
];
3681 Type bt
= orig_best_pd
.Types
[j
];
3684 Type specific
= MoreSpecific (ct
, bt
);
3688 specific_at_least_once
= true;
3691 if (specific_at_least_once
)
3694 // FIXME: handle lifted operators
3700 protected override MemberExpr
ResolveExtensionMemberAccess (Expression left
)
3703 return base.ResolveExtensionMemberAccess (left
);
3706 // When left side is an expression and at least one candidate method is
3707 // static, it can be extension method
3709 InstanceExpression
= left
;
3713 public override MemberExpr
ResolveMemberAccess (EmitContext ec
, Expression left
, Location loc
,
3714 SimpleName original
)
3716 if (!(left
is TypeExpr
) &&
3717 original
!= null && original
.IdenticalNameAndTypeName (ec
, left
, loc
))
3718 identical_type_name
= true;
3720 return base.ResolveMemberAccess (ec
, left
, loc
, original
);
3723 public override Expression
CreateExpressionTree (EmitContext ec
)
3725 if (best_candidate
== null) {
3726 Report
.Error (1953, loc
, "An expression tree cannot contain an expression with method group");
3730 if (best_candidate
.IsConstructor
)
3731 return new TypeOfConstructorInfo (best_candidate
, loc
);
3733 IMethodData md
= TypeManager
.GetMethod (best_candidate
);
3734 if (md
!= null && md
.IsExcluded ())
3735 Report
.Error (765, loc
,
3736 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3738 return new TypeOfMethodInfo (best_candidate
, loc
);
3741 override public Expression
DoResolve (EmitContext ec
)
3743 if (InstanceExpression
!= null) {
3744 InstanceExpression
= InstanceExpression
.DoResolve (ec
);
3745 if (InstanceExpression
== null)
3752 public void ReportUsageError ()
3754 Report
.Error (654, loc
, "Method `" + DeclaringType
+ "." +
3755 Name
+ "()' is referenced without parentheses");
3758 override public void Emit (EmitContext ec
)
3760 ReportUsageError ();
3763 public virtual void EmitArguments (EmitContext ec
, ArrayList arguments
)
3765 Invocation
.EmitArguments (ec
, arguments
, false, null);
3768 public virtual void EmitCall (EmitContext ec
, ArrayList arguments
)
3770 Invocation
.EmitCall (ec
, IsBase
, InstanceExpression
, best_candidate
, arguments
, loc
);
3773 protected virtual void Error_InvalidArguments (EmitContext ec
, Location loc
, int idx
, MethodBase method
,
3774 Argument a
, AParametersCollection expected_par
, Type paramType
)
3776 ExtensionMethodGroupExpr emg
= this as ExtensionMethodGroupExpr
;
3778 if (a
is CollectionElementInitializer
.ElementInitializerArgument
) {
3779 Report
.SymbolRelatedToPreviousError (method
);
3780 if ((expected_par
.FixedParameters
[idx
].ModFlags
& Parameter
.Modifier
.ISBYREF
) != 0) {
3781 Report
.Error (1954, loc
, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
3782 TypeManager
.CSharpSignature (method
));
3785 Report
.Error (1950, loc
, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
3786 TypeManager
.CSharpSignature (method
));
3787 } else if (delegate_type
== null) {
3788 Report
.SymbolRelatedToPreviousError (method
);
3790 Report
.Error (1928, loc
,
3791 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3792 emg
.ExtensionExpression
.GetSignatureForError (),
3793 emg
.Name
, TypeManager
.CSharpSignature (method
));
3795 Report
.Error (1502, loc
, "The best overloaded method match for `{0}' has some invalid arguments",
3796 TypeManager
.CSharpSignature (method
));
3799 Report
.Error (1594, loc
, "Delegate `{0}' has some invalid arguments",
3800 TypeManager
.CSharpName (delegate_type
));
3802 Parameter
.Modifier mod
= idx
>= expected_par
.Count
? 0 : expected_par
.FixedParameters
[idx
].ModFlags
;
3804 string index
= (idx
+ 1).ToString ();
3805 if (((mod
& (Parameter
.Modifier
.REF
| Parameter
.Modifier
.OUT
)) ^
3806 (a
.Modifier
& (Parameter
.Modifier
.REF
| Parameter
.Modifier
.OUT
))) != 0) {
3807 if ((mod
& Parameter
.Modifier
.ISBYREF
) == 0)
3808 Report
.Error (1615, loc
, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
3809 index
, Parameter
.GetModifierSignature (a
.Modifier
));
3811 Report
.Error (1620, loc
, "Argument `#{0}' is missing `{1}' modifier",
3812 index
, Parameter
.GetModifierSignature (mod
));
3814 string p1
= a
.GetSignatureForError ();
3815 string p2
= TypeManager
.CSharpName (paramType
);
3818 Report
.ExtraInformation (loc
, "(equally named types possibly from different assemblies in previous ");
3819 Report
.SymbolRelatedToPreviousError (a
.Expr
.Type
);
3820 Report
.SymbolRelatedToPreviousError (paramType
);
3823 if (idx
== 0 && emg
!= null) {
3824 Report
.Error (1929, loc
,
3825 "Extension method instance type `{0}' cannot be converted to `{1}'", p1
, p2
);
3827 Report
.Error (1503, loc
,
3828 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index
, p1
, p2
);
3833 public override void Error_ValueCannotBeConverted (EmitContext ec
, Location loc
, Type target
, bool expl
)
3835 Report
.Error (428, loc
, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3836 Name
, TypeManager
.CSharpName (target
));
3839 protected virtual int GetApplicableParametersCount (MethodBase method
, AParametersCollection parameters
)
3841 return parameters
.Count
;
3844 public static bool IsAncestralType (Type first_type
, Type second_type
)
3846 return first_type
!= second_type
&&
3847 (TypeManager
.IsSubclassOf (second_type
, first_type
) ||
3848 TypeManager
.ImplementsInterface (second_type
, first_type
));
3852 /// Determines if the candidate method is applicable (section 14.4.2.1)
3853 /// to the given set of arguments
3854 /// A return value rates candidate method compatibility,
3855 /// 0 = the best, int.MaxValue = the worst
3857 public int IsApplicable (EmitContext ec
,
3858 ArrayList arguments
, int arg_count
, ref MethodBase method
, ref bool params_expanded_form
)
3860 MethodBase candidate
= method
;
3862 AParametersCollection pd
= TypeManager
.GetParameterData (candidate
);
3863 int param_count
= GetApplicableParametersCount (candidate
, pd
);
3865 if (arg_count
!= param_count
) {
3867 return int.MaxValue
- 10000 + Math
.Abs (arg_count
- param_count
);
3868 if (arg_count
< param_count
- 1)
3869 return int.MaxValue
- 10000 + Math
.Abs (arg_count
- param_count
);
3874 // 1. Handle generic method using type arguments when specified or type inference
3876 if (TypeManager
.IsGenericMethod (candidate
)) {
3877 if (type_arguments
!= null) {
3878 Type
[] g_args
= candidate
.GetGenericArguments ();
3879 if (g_args
.Length
!= type_arguments
.Count
)
3880 return int.MaxValue
- 20000 + Math
.Abs (type_arguments
.Count
- g_args
.Length
);
3882 // TODO: Don't create new method, create Parameters only
3883 method
= ((MethodInfo
) candidate
).MakeGenericMethod (type_arguments
.Arguments
);
3885 pd
= TypeManager
.GetParameterData (candidate
);
3887 int score
= TypeManager
.InferTypeArguments (ec
, arguments
, ref candidate
);
3889 return score
- 20000;
3891 if (TypeManager
.IsGenericMethodDefinition (candidate
))
3892 throw new InternalErrorException ("A generic method `{0}' definition took part in overload resolution",
3893 TypeManager
.CSharpSignature (candidate
));
3895 pd
= TypeManager
.GetParameterData (candidate
);
3898 if (type_arguments
!= null)
3899 return int.MaxValue
- 15000;
3904 // 2. Each argument has to be implicitly convertible to method parameter
3907 Parameter
.Modifier p_mod
= 0;
3909 for (int i
= 0; i
< arg_count
; i
++) {
3910 Argument a
= (Argument
) arguments
[i
];
3911 Parameter
.Modifier a_mod
= a
.Modifier
&
3912 ~
(Parameter
.Modifier
.OUTMASK
| Parameter
.Modifier
.REFMASK
);
3914 if (p_mod
!= Parameter
.Modifier
.PARAMS
) {
3915 p_mod
= pd
.FixedParameters
[i
].ModFlags
& ~
(Parameter
.Modifier
.OUTMASK
| Parameter
.Modifier
.REFMASK
);
3917 if (p_mod
== Parameter
.Modifier
.ARGLIST
) {
3918 if (a
.Type
== TypeManager
.runtime_argument_handle_type
)
3926 params_expanded_form
= true;
3930 if (!params_expanded_form
)
3931 score
= IsArgumentCompatible (ec
, a_mod
, a
, p_mod
& ~Parameter
.Modifier
.PARAMS
, pt
);
3933 if (score
!= 0 && (p_mod
& Parameter
.Modifier
.PARAMS
) != 0) {
3934 // It can be applicable in expanded form
3935 score
= IsArgumentCompatible (ec
, a_mod
, a
, 0, pt
.GetElementType ());
3937 params_expanded_form
= true;
3941 if (params_expanded_form
)
3943 return (arg_count
- i
) * 2 + score
;
3947 if (arg_count
!= param_count
)
3948 params_expanded_form
= true;
3953 int IsArgumentCompatible (EmitContext ec
, Parameter
.Modifier arg_mod
, Argument argument
, Parameter
.Modifier param_mod
, Type parameter
)
3956 // Types have to be identical when ref or out modifer is used
3958 if (arg_mod
!= 0 || param_mod
!= 0) {
3959 if (TypeManager
.HasElementType (parameter
))
3960 parameter
= parameter
.GetElementType ();
3962 Type a_type
= argument
.Type
;
3963 if (TypeManager
.HasElementType (a_type
))
3964 a_type
= a_type
.GetElementType ();
3966 if (a_type
!= parameter
)
3969 if (delegate_type
!= null ?
3970 !Delegate
.IsTypeCovariant (argument
.Expr
, parameter
) :
3971 !Convert
.ImplicitConversionExists (ec
, argument
.Expr
, parameter
))
3975 if (arg_mod
!= param_mod
)
3981 public static bool IsOverride (MethodBase cand_method
, MethodBase base_method
)
3983 if (!IsAncestralType (base_method
.DeclaringType
, cand_method
.DeclaringType
))
3986 AParametersCollection cand_pd
= TypeManager
.GetParameterData (cand_method
);
3987 AParametersCollection base_pd
= TypeManager
.GetParameterData (base_method
);
3989 if (cand_pd
.Count
!= base_pd
.Count
)
3992 for (int j
= 0; j
< cand_pd
.Count
; ++j
)
3994 Parameter
.Modifier cm
= cand_pd
.FixedParameters
[j
].ModFlags
;
3995 Parameter
.Modifier bm
= base_pd
.FixedParameters
[j
].ModFlags
;
3996 Type ct
= cand_pd
.Types
[j
];
3997 Type bt
= base_pd
.Types
[j
];
3999 if (cm
!= bm
|| ct
!= bt
)
4006 public static MethodGroupExpr
MakeUnionSet (MethodGroupExpr mg1
, MethodGroupExpr mg2
, Location loc
)
4017 ArrayList all
= new ArrayList (mg1
.Methods
);
4018 foreach (MethodBase m
in mg2
.Methods
){
4019 if (!TypeManager
.ArrayContainsMethod (mg1
.Methods
, m
, false))
4023 return new MethodGroupExpr (all
, null, loc
);
4026 static Type
MoreSpecific (Type p
, Type q
)
4028 if (TypeManager
.IsGenericParameter (p
) && !TypeManager
.IsGenericParameter (q
))
4030 if (!TypeManager
.IsGenericParameter (p
) && TypeManager
.IsGenericParameter (q
))
4033 if (TypeManager
.HasElementType (p
))
4035 Type pe
= TypeManager
.GetElementType (p
);
4036 Type qe
= TypeManager
.GetElementType (q
);
4037 Type specific
= MoreSpecific (pe
, qe
);
4043 else if (TypeManager
.IsGenericType (p
))
4045 Type
[] pargs
= TypeManager
.GetTypeArguments (p
);
4046 Type
[] qargs
= TypeManager
.GetTypeArguments (q
);
4048 bool p_specific_at_least_once
= false;
4049 bool q_specific_at_least_once
= false;
4051 for (int i
= 0; i
< pargs
.Length
; i
++)
4053 Type specific
= MoreSpecific (pargs
[i
], qargs
[i
]);
4054 if (specific
== pargs
[i
])
4055 p_specific_at_least_once
= true;
4056 if (specific
== qargs
[i
])
4057 q_specific_at_least_once
= true;
4060 if (p_specific_at_least_once
&& !q_specific_at_least_once
)
4062 if (!p_specific_at_least_once
&& q_specific_at_least_once
)
4069 public override void MutateHoistedGenericType (AnonymousMethodStorey storey
)
4071 base.MutateHoistedGenericType (storey
);
4073 MethodInfo mi
= best_candidate
as MethodInfo
;
4075 best_candidate
= storey
.MutateGenericMethod (mi
);
4079 best_candidate
= storey
.MutateConstructor ((ConstructorInfo
) this);
4083 /// Find the Applicable Function Members (7.4.2.1)
4085 /// me: Method Group expression with the members to select.
4086 /// it might contain constructors or methods (or anything
4087 /// that maps to a method).
4089 /// Arguments: ArrayList containing resolved Argument objects.
4091 /// loc: The location if we want an error to be reported, or a Null
4092 /// location for "probing" purposes.
4094 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4095 /// that is the best match of me on Arguments.
4098 public virtual MethodGroupExpr
OverloadResolve (EmitContext ec
, ref ArrayList Arguments
,
4099 bool may_fail
, Location loc
)
4101 bool method_params
= false;
4102 Type applicable_type
= null;
4104 ArrayList candidates
= new ArrayList (2);
4105 ArrayList candidate_overrides
= null;
4108 // Used to keep a map between the candidate
4109 // and whether it is being considered in its
4110 // normal or expanded form
4112 // false is normal form, true is expanded form
4114 Hashtable candidate_to_form
= null;
4116 if (Arguments
!= null)
4117 arg_count
= Arguments
.Count
;
4119 if (RootContext
.Version
== LanguageVersion
.ISO_1
&& Name
== "Invoke" && TypeManager
.IsDelegateType (DeclaringType
)) {
4121 Report
.Error (1533, loc
, "Invoke cannot be called directly on a delegate");
4125 int nmethods
= Methods
.Length
;
4129 // Methods marked 'override' don't take part in 'applicable_type'
4130 // computation, nor in the actual overload resolution.
4131 // However, they still need to be emitted instead of a base virtual method.
4132 // So, we salt them away into the 'candidate_overrides' array.
4134 // In case of reflected methods, we replace each overriding method with
4135 // its corresponding base virtual method. This is to improve compatibility
4136 // with non-C# libraries which change the visibility of overrides (#75636)
4139 for (int i
= 0; i
< Methods
.Length
; ++i
) {
4140 MethodBase m
= Methods
[i
];
4141 if (TypeManager
.IsOverride (m
)) {
4142 if (candidate_overrides
== null)
4143 candidate_overrides
= new ArrayList ();
4144 candidate_overrides
.Add (m
);
4145 m
= TypeManager
.TryGetBaseDefinition (m
);
4154 // Enable message recording, it's used mainly by lambda expressions
4156 Report
.IMessageRecorder msg_recorder
= new Report
.MessageRecorder ();
4157 Report
.IMessageRecorder prev_recorder
= Report
.SetMessageRecorder (msg_recorder
);
4160 // First we construct the set of applicable methods
4162 bool is_sorted
= true;
4163 int best_candidate_rate
= int.MaxValue
;
4164 for (int i
= 0; i
< nmethods
; i
++) {
4165 Type decl_type
= Methods
[i
].DeclaringType
;
4168 // If we have already found an applicable method
4169 // we eliminate all base types (Section 14.5.5.1)
4171 if (applicable_type
!= null && IsAncestralType (decl_type
, applicable_type
))
4175 // Check if candidate is applicable (section 14.4.2.1)
4177 bool params_expanded_form
= false;
4178 int candidate_rate
= IsApplicable (ec
, Arguments
, arg_count
, ref Methods
[i
], ref params_expanded_form
);
4180 if (candidate_rate
< best_candidate_rate
) {
4181 best_candidate_rate
= candidate_rate
;
4182 best_candidate
= Methods
[i
];
4185 if (params_expanded_form
) {
4186 if (candidate_to_form
== null)
4187 candidate_to_form
= new PtrHashtable ();
4188 MethodBase candidate
= Methods
[i
];
4189 candidate_to_form
[candidate
] = candidate
;
4192 if (candidate_rate
!= 0) {
4193 if (msg_recorder
!= null)
4194 msg_recorder
.EndSession ();
4198 msg_recorder
= null;
4199 candidates
.Add (Methods
[i
]);
4201 if (applicable_type
== null)
4202 applicable_type
= decl_type
;
4203 else if (applicable_type
!= decl_type
) {
4205 if (IsAncestralType (applicable_type
, decl_type
))
4206 applicable_type
= decl_type
;
4210 Report
.SetMessageRecorder (prev_recorder
);
4211 if (msg_recorder
!= null && !msg_recorder
.IsEmpty
) {
4213 msg_recorder
.PrintMessages ();
4218 int candidate_top
= candidates
.Count
;
4220 if (applicable_type
== null) {
4222 // When we found a top level method which does not match and it's
4223 // not an extension method. We start extension methods lookup from here
4225 if (InstanceExpression
!= null) {
4226 ExtensionMethodGroupExpr ex_method_lookup
= ec
.TypeContainer
.LookupExtensionMethod (type
, Name
, loc
);
4227 if (ex_method_lookup
!= null) {
4228 ex_method_lookup
.ExtensionExpression
= InstanceExpression
;
4229 ex_method_lookup
.SetTypeArguments (type_arguments
);
4230 return ex_method_lookup
.OverloadResolve (ec
, ref Arguments
, may_fail
, loc
);
4238 // Okay so we have failed to find exact match so we
4239 // return error info about the closest match
4241 if (best_candidate
!= null) {
4242 if (CustomErrorHandler
!= null) {
4243 if (CustomErrorHandler
.NoExactMatch (ec
, best_candidate
))
4247 AParametersCollection pd
= TypeManager
.GetParameterData (best_candidate
);
4248 bool cand_params
= candidate_to_form
!= null && candidate_to_form
.Contains (best_candidate
);
4249 if (arg_count
== pd
.Count
|| pd
.HasParams
) {
4250 if (TypeManager
.IsGenericMethodDefinition (best_candidate
)) {
4251 if (type_arguments
== null) {
4252 Report
.Error (411, loc
,
4253 "The type arguments for method `{0}' cannot be inferred from " +
4254 "the usage. Try specifying the type arguments explicitly",
4255 TypeManager
.CSharpSignature (best_candidate
));
4259 Type
[] g_args
= TypeManager
.GetGenericArguments (best_candidate
);
4260 if (type_arguments
.Count
!= g_args
.Length
) {
4261 Report
.SymbolRelatedToPreviousError (best_candidate
);
4262 Report
.Error (305, loc
, "Using the generic method `{0}' requires `{1}' type argument(s)",
4263 TypeManager
.CSharpSignature (best_candidate
),
4264 g_args
.Length
.ToString ());
4268 if (type_arguments
!= null && !TypeManager
.IsGenericMethod (best_candidate
)) {
4269 Namespace
.Error_TypeArgumentsCannotBeUsed (best_candidate
, loc
);
4274 if (!VerifyArgumentsCompat (ec
, ref Arguments
, arg_count
, best_candidate
, cand_params
, may_fail
, loc
))
4279 if (almost_matched_members
.Count
!= 0) {
4280 Error_MemberLookupFailed (ec
.ContainerType
, type
, type
, ".ctor",
4281 null, MemberTypes
.Constructor
, AllBindingFlags
);
4286 // We failed to find any method with correct argument count
4288 if (Name
== ConstructorInfo
.ConstructorName
) {
4289 Report
.SymbolRelatedToPreviousError (type
);
4290 Report
.Error (1729, loc
,
4291 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4292 TypeManager
.CSharpName (type
), arg_count
);
4294 Report
.Error (1501, loc
, "No overload for method `{0}' takes `{1}' arguments",
4295 Name
, arg_count
.ToString ());
4303 // At this point, applicable_type is _one_ of the most derived types
4304 // in the set of types containing the methods in this MethodGroup.
4305 // Filter the candidates so that they only contain methods from the
4306 // most derived types.
4309 int finalized
= 0; // Number of finalized candidates
4312 // Invariant: applicable_type is a most derived type
4314 // We'll try to complete Section 14.5.5.1 for 'applicable_type' by
4315 // eliminating all it's base types. At the same time, we'll also move
4316 // every unrelated type to the end of the array, and pick the next
4317 // 'applicable_type'.
4319 Type next_applicable_type
= null;
4320 int j
= finalized
; // where to put the next finalized candidate
4321 int k
= finalized
; // where to put the next undiscarded candidate
4322 for (int i
= finalized
; i
< candidate_top
; ++i
) {
4323 MethodBase candidate
= (MethodBase
) candidates
[i
];
4324 Type decl_type
= candidate
.DeclaringType
;
4326 if (decl_type
== applicable_type
) {
4327 candidates
[k
++] = candidates
[j
];
4328 candidates
[j
++] = candidates
[i
];
4332 if (IsAncestralType (decl_type
, applicable_type
))
4335 if (next_applicable_type
!= null &&
4336 IsAncestralType (decl_type
, next_applicable_type
))
4339 candidates
[k
++] = candidates
[i
];
4341 if (next_applicable_type
== null ||
4342 IsAncestralType (next_applicable_type
, decl_type
))
4343 next_applicable_type
= decl_type
;
4346 applicable_type
= next_applicable_type
;
4349 } while (applicable_type
!= null);
4353 // Now we actually find the best method
4356 best_candidate
= (MethodBase
) candidates
[0];
4357 if (delegate_type
== null)
4358 method_params
= candidate_to_form
!= null && candidate_to_form
.Contains (best_candidate
);
4360 for (int ix
= 1; ix
< candidate_top
; ix
++) {
4361 MethodBase candidate
= (MethodBase
) candidates
[ix
];
4363 if (candidate
== best_candidate
)
4366 bool cand_params
= candidate_to_form
!= null && candidate_to_form
.Contains (candidate
);
4368 if (BetterFunction (ec
, Arguments
, arg_count
,
4369 candidate
, cand_params
,
4370 best_candidate
, method_params
)) {
4371 best_candidate
= candidate
;
4372 method_params
= cand_params
;
4376 // Now check that there are no ambiguities i.e the selected method
4377 // should be better than all the others
4379 MethodBase ambiguous
= null;
4380 for (int ix
= 1; ix
< candidate_top
; ix
++) {
4381 MethodBase candidate
= (MethodBase
) candidates
[ix
];
4383 if (candidate
== best_candidate
)
4386 bool cand_params
= candidate_to_form
!= null && candidate_to_form
.Contains (candidate
);
4387 if (!BetterFunction (ec
, Arguments
, arg_count
,
4388 best_candidate
, method_params
,
4389 candidate
, cand_params
))
4392 Report
.SymbolRelatedToPreviousError (candidate
);
4393 ambiguous
= candidate
;
4397 if (ambiguous
!= null) {
4398 Report
.SymbolRelatedToPreviousError (best_candidate
);
4399 Report
.Error (121, loc
, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4400 TypeManager
.CSharpSignature (ambiguous
), TypeManager
.CSharpSignature (best_candidate
));
4405 // If the method is a virtual function, pick an override closer to the LHS type.
4407 if (!IsBase
&& best_candidate
.IsVirtual
) {
4408 if (TypeManager
.IsOverride (best_candidate
))
4409 throw new InternalErrorException (
4410 "Should not happen. An 'override' method took part in overload resolution: " + best_candidate
);
4412 if (candidate_overrides
!= null) {
4413 Type
[] gen_args
= null;
4414 bool gen_override
= false;
4415 if (TypeManager
.IsGenericMethod (best_candidate
))
4416 gen_args
= TypeManager
.GetGenericArguments (best_candidate
);
4418 foreach (MethodBase candidate
in candidate_overrides
) {
4419 if (TypeManager
.IsGenericMethod (candidate
)) {
4420 if (gen_args
== null)
4423 if (gen_args
.Length
!= TypeManager
.GetGenericArguments (candidate
).Length
)
4426 if (gen_args
!= null)
4430 if (IsOverride (candidate
, best_candidate
)) {
4431 gen_override
= true;
4432 best_candidate
= candidate
;
4436 if (gen_override
&& gen_args
!= null) {
4438 best_candidate
= ((MethodInfo
) best_candidate
).MakeGenericMethod (gen_args
);
4445 // And now check if the arguments are all
4446 // compatible, perform conversions if
4447 // necessary etc. and return if everything is
4450 if (!VerifyArgumentsCompat (ec
, ref Arguments
, arg_count
, best_candidate
,
4451 method_params
, may_fail
, loc
))
4454 if (best_candidate
== null)
4457 MethodBase the_method
= TypeManager
.DropGenericMethodArguments (best_candidate
);
4459 if (the_method
.IsGenericMethodDefinition
&&
4460 !ConstraintChecker
.CheckConstraints (ec
, the_method
, best_candidate
, loc
))
4465 // Check ObsoleteAttribute on the best method
4467 ObsoleteAttribute oa
= AttributeTester
.GetMethodObsoleteAttribute (the_method
);
4468 if (oa
!= null && !ec
.IsInObsoleteScope
)
4469 AttributeTester
.Report_ObsoleteMessage (oa
, GetSignatureForError (), loc
);
4471 IMethodData data
= TypeManager
.GetMethod (the_method
);
4473 data
.SetMemberIsUsed ();
4478 public override void SetTypeArguments (TypeArguments ta
)
4480 type_arguments
= ta
;
4483 public bool VerifyArgumentsCompat (EmitContext ec
, ref ArrayList arguments
,
4484 int arg_count
, MethodBase method
,
4485 bool chose_params_expanded
,
4486 bool may_fail
, Location loc
)
4488 AParametersCollection pd
= TypeManager
.GetParameterData (method
);
4490 int errors
= Report
.Errors
;
4491 Parameter
.Modifier p_mod
= 0;
4493 int a_idx
= 0, a_pos
= 0;
4495 ArrayList params_initializers
= null;
4496 bool has_unsafe_arg
= false;
4498 for (; a_idx
< arg_count
; a_idx
++, ++a_pos
) {
4499 a
= (Argument
) arguments
[a_idx
];
4500 if (p_mod
!= Parameter
.Modifier
.PARAMS
) {
4501 p_mod
= pd
.FixedParameters
[a_idx
].ModFlags
;
4502 pt
= pd
.Types
[a_idx
];
4503 has_unsafe_arg
|= pt
.IsPointer
;
4505 if (p_mod
== Parameter
.Modifier
.ARGLIST
) {
4506 if (a
.Type
!= TypeManager
.runtime_argument_handle_type
)
4511 if (p_mod
== Parameter
.Modifier
.PARAMS
) {
4512 if (chose_params_expanded
) {
4513 params_initializers
= new ArrayList (arg_count
- a_idx
);
4514 pt
= TypeManager
.GetElementType (pt
);
4520 // Types have to be identical when ref or out modifer is used
4522 if (a
.Modifier
!= 0 || (p_mod
& ~Parameter
.Modifier
.PARAMS
) != 0) {
4523 if ((p_mod
& ~Parameter
.Modifier
.PARAMS
) != a
.Modifier
)
4526 if (!TypeManager
.IsEqual (a
.Expr
.Type
, pt
))
4532 Expression conv
= Convert
.ImplicitConversion (ec
, a
.Expr
, pt
, loc
);
4537 // Convert params arguments to an array initializer
4539 if (params_initializers
!= null) {
4540 // we choose to use 'a.Expr' rather than 'conv' so that
4541 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
4542 params_initializers
.Add (a
.Expr
);
4543 arguments
.RemoveAt (a_idx
--);
4548 // Update the argument with the implicit conversion
4553 // Fill not provided arguments required by params modifier
4555 if (params_initializers
== null && pd
.HasParams
&& arg_count
< pd
.Count
&& a_idx
+ 1 == pd
.Count
) {
4556 if (arguments
== null)
4557 arguments
= new ArrayList (1);
4559 pt
= pd
.Types
[GetApplicableParametersCount (method
, pd
) - 1];
4560 pt
= TypeManager
.GetElementType (pt
);
4561 has_unsafe_arg
|= pt
.IsPointer
;
4562 params_initializers
= new ArrayList (0);
4565 if (a_idx
== arg_count
) {
4567 // Append an array argument with all params arguments
4569 if (params_initializers
!= null) {
4570 arguments
.Add (new Argument (
4571 new ArrayCreation (new TypeExpression (pt
, loc
), "[]",
4572 params_initializers
, loc
).Resolve (ec
)));
4575 if (has_unsafe_arg
&& !ec
.InUnsafe
) {
4584 if (!may_fail
&& Report
.Errors
== errors
) {
4585 if (CustomErrorHandler
!= null)
4586 CustomErrorHandler
.NoExactMatch (ec
, best_candidate
);
4588 Error_InvalidArguments (ec
, loc
, a_pos
, method
, a
, pd
, pt
);
4594 public class ConstantExpr
: MemberExpr
4598 public ConstantExpr (FieldInfo constant
, Location loc
)
4600 this.constant
= constant
;
4604 public override string Name
{
4605 get { throw new NotImplementedException (); }
4608 public override bool IsInstance
{
4609 get { return !IsStatic; }
4612 public override bool IsStatic
{
4613 get { return constant.IsStatic; }
4616 public override Type DeclaringType
{
4617 get { return constant.DeclaringType; }
4620 public override MemberExpr
ResolveMemberAccess (EmitContext ec
, Expression left
, Location loc
, SimpleName original
)
4622 constant
= TypeManager
.GetGenericFieldDefinition (constant
);
4624 IConstant ic
= TypeManager
.GetConstant (constant
);
4626 if (constant
.IsLiteral
) {
4627 ic
= new ExternalConstant (constant
);
4629 ic
= ExternalConstant
.CreateDecimal (constant
);
4630 // HACK: decimal field was not resolved as constant
4632 return new FieldExpr (constant
, loc
).ResolveMemberAccess (ec
, left
, loc
, original
);
4634 TypeManager
.RegisterConstant (constant
, ic
);
4637 return base.ResolveMemberAccess (ec
, left
, loc
, original
);
4640 public override Expression
CreateExpressionTree (EmitContext ec
)
4642 throw new NotSupportedException ("ET");
4645 public override Expression
DoResolve (EmitContext ec
)
4647 IConstant ic
= TypeManager
.GetConstant (constant
);
4648 if (ic
.ResolveValue ()) {
4649 if (!ec
.IsInObsoleteScope
)
4650 ic
.CheckObsoleteness (loc
);
4653 return ic
.CreateConstantReference (loc
);
4656 public override void Emit (EmitContext ec
)
4658 throw new NotSupportedException ();
4661 public override string GetSignatureForError ()
4663 return TypeManager
.GetFullNameSignature (constant
);
4668 /// Fully resolved expression that evaluates to a Field
4670 public class FieldExpr
: MemberExpr
, IAssignMethod
, IMemoryLocation
, IVariableReference
{
4671 public FieldInfo FieldInfo
;
4672 readonly Type constructed_generic_type
;
4673 VariableInfo variable_info
;
4675 LocalTemporary temp
;
4678 public FieldExpr (FieldInfo fi
, Location l
)
4681 type
= TypeManager
.TypeToCoreType (fi
.FieldType
);
4685 public FieldExpr (FieldInfo fi
, Type genericType
, Location l
)
4688 this.constructed_generic_type
= genericType
;
4691 public override string Name
{
4693 return FieldInfo
.Name
;
4697 public override bool IsInstance
{
4699 return !FieldInfo
.IsStatic
;
4703 public override bool IsStatic
{
4705 return FieldInfo
.IsStatic
;
4709 public override Type DeclaringType
{
4711 return FieldInfo
.DeclaringType
;
4715 public override string GetSignatureForError ()
4717 return TypeManager
.GetFullNameSignature (FieldInfo
);
4720 public VariableInfo VariableInfo
{
4722 return variable_info
;
4726 public override MemberExpr
ResolveMemberAccess (EmitContext ec
, Expression left
, Location loc
,
4727 SimpleName original
)
4729 FieldInfo fi
= TypeManager
.GetGenericFieldDefinition (FieldInfo
);
4730 Type t
= fi
.FieldType
;
4732 if (t
.IsPointer
&& !ec
.InUnsafe
) {
4736 return base.ResolveMemberAccess (ec
, left
, loc
, original
);
4739 public void SetHasAddressTaken ()
4741 IVariableReference vr
= InstanceExpression
as IVariableReference
;
4743 vr
.SetHasAddressTaken ();
4746 public override Expression
CreateExpressionTree (EmitContext ec
)
4748 Expression instance
;
4749 if (InstanceExpression
== null) {
4750 instance
= new NullLiteral (loc
);
4752 instance
= InstanceExpression
.CreateExpressionTree (ec
);
4755 ArrayList args
= new ArrayList (2);
4756 args
.Add (new Argument (instance
));
4757 args
.Add (new Argument (CreateTypeOfExpression ()));
4758 return CreateExpressionFactoryCall ("Field", args
);
4761 public Expression
CreateTypeOfExpression ()
4763 return new TypeOfField (FieldInfo
, loc
);
4766 override public Expression
DoResolve (EmitContext ec
)
4768 return DoResolve (ec
, false, false);
4771 Expression
DoResolve (EmitContext ec
, bool lvalue_instance
, bool out_access
)
4773 if (!FieldInfo
.IsStatic
){
4774 if (InstanceExpression
== null){
4776 // This can happen when referencing an instance field using
4777 // a fully qualified type expression: TypeName.InstanceField = xxx
4779 SimpleName
.Error_ObjectRefRequired (ec
, loc
, GetSignatureForError ());
4783 // Resolve the field's instance expression while flow analysis is turned
4784 // off: when accessing a field "a.b", we must check whether the field
4785 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4787 if (lvalue_instance
) {
4788 using (ec
.With (EmitContext
.Flags
.DoFlowAnalysis
, false)) {
4789 Expression right_side
=
4790 out_access
? EmptyExpression
.LValueMemberOutAccess
: EmptyExpression
.LValueMemberAccess
;
4791 InstanceExpression
= InstanceExpression
.ResolveLValue (ec
, right_side
, loc
);
4794 ResolveFlags rf
= ResolveFlags
.VariableOrValue
| ResolveFlags
.DisableFlowAnalysis
;
4795 InstanceExpression
= InstanceExpression
.Resolve (ec
, rf
);
4798 if (InstanceExpression
== null)
4801 using (ec
.Set (EmitContext
.Flags
.OmitStructFlowAnalysis
)) {
4802 InstanceExpression
.CheckMarshalByRefAccess (ec
);
4806 // TODO: the code above uses some non-standard multi-resolve rules
4807 if (eclass
!= ExprClass
.Invalid
)
4810 if (!ec
.IsInObsoleteScope
) {
4811 FieldBase f
= TypeManager
.GetField (FieldInfo
);
4813 f
.CheckObsoleteness (loc
);
4815 ObsoleteAttribute oa
= AttributeTester
.GetMemberObsoleteAttribute (FieldInfo
);
4817 AttributeTester
.Report_ObsoleteMessage (oa
, TypeManager
.GetFullNameSignature (FieldInfo
), loc
);
4821 IFixedBuffer fb
= AttributeTester
.GetFixedBuffer (FieldInfo
);
4822 IVariableReference
var = InstanceExpression
as IVariableReference
;
4825 IFixedExpression fe
= InstanceExpression
as IFixedExpression
;
4826 if (!ec
.InFixedInitializer
&& (fe
== null || !fe
.IsFixed
)) {
4827 Report
.Error (1666, loc
, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4830 if (InstanceExpression
.eclass
!= ExprClass
.Variable
) {
4831 Report
.SymbolRelatedToPreviousError (FieldInfo
);
4832 Report
.Error (1708, loc
, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4833 TypeManager
.GetFullNameSignature (FieldInfo
));
4834 } else if (var != null && var.IsHoisted
) {
4835 AnonymousMethodExpression
.Error_AddressOfCapturedVar (var, loc
);
4838 return new FixedBufferPtr (this, fb
.ElementType
, loc
).Resolve (ec
);
4841 eclass
= ExprClass
.Variable
;
4843 // If the instance expression is a local variable or parameter.
4844 if (var == null || var.VariableInfo
== null)
4847 VariableInfo vi
= var.VariableInfo
;
4848 if (!vi
.IsFieldAssigned (ec
, FieldInfo
.Name
, loc
))
4851 variable_info
= vi
.GetSubStruct (FieldInfo
.Name
);
4852 eclass
= ExprClass
.Variable
;
4856 static readonly int [] codes
= {
4857 191, // instance, write access
4858 192, // instance, out access
4859 198, // static, write access
4860 199, // static, out access
4861 1648, // member of value instance, write access
4862 1649, // member of value instance, out access
4863 1650, // member of value static, write access
4864 1651 // member of value static, out access
4867 static readonly string [] msgs
= {
4868 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4869 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4870 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4871 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4872 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4873 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4874 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4875 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4878 // The return value is always null. Returning a value simplifies calling code.
4879 Expression
Report_AssignToReadonly (Expression right_side
)
4882 if (right_side
== EmptyExpression
.OutAccess
|| right_side
== EmptyExpression
.LValueMemberOutAccess
)
4886 if (right_side
== EmptyExpression
.LValueMemberAccess
|| right_side
== EmptyExpression
.LValueMemberOutAccess
)
4888 Report
.Error (codes
[i
], loc
, msgs
[i
], GetSignatureForError ());
4893 override public Expression
DoResolveLValue (EmitContext ec
, Expression right_side
)
4895 IVariableReference
var = InstanceExpression
as IVariableReference
;
4896 if (var != null && var.VariableInfo
!= null)
4897 var.VariableInfo
.SetFieldAssigned (ec
, FieldInfo
.Name
);
4899 bool lvalue_instance
= !FieldInfo
.IsStatic
&& FieldInfo
.DeclaringType
.IsValueType
;
4900 bool out_access
= right_side
== EmptyExpression
.OutAccess
|| right_side
== EmptyExpression
.LValueMemberOutAccess
;
4902 Expression e
= DoResolve (ec
, lvalue_instance
, out_access
);
4907 FieldBase fb
= TypeManager
.GetField (FieldInfo
);
4911 if (FieldInfo
.IsInitOnly
) {
4912 // InitOnly fields can only be assigned in constructors or initializers
4913 if (!ec
.IsInFieldInitializer
&& !ec
.IsConstructor
)
4914 return Report_AssignToReadonly (right_side
);
4916 if (ec
.IsConstructor
) {
4917 Type ctype
= ec
.TypeContainer
.CurrentType
;
4919 ctype
= ec
.ContainerType
;
4921 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4922 if (!TypeManager
.IsEqual (ctype
, FieldInfo
.DeclaringType
))
4923 return Report_AssignToReadonly (right_side
);
4924 // static InitOnly fields cannot be assigned-to in an instance constructor
4925 if (IsStatic
&& !ec
.IsStatic
)
4926 return Report_AssignToReadonly (right_side
);
4927 // instance constructors can't modify InitOnly fields of other instances of the same type
4928 if (!IsStatic
&& !(InstanceExpression
is This
))
4929 return Report_AssignToReadonly (right_side
);
4933 if (right_side
== EmptyExpression
.OutAccess
&&
4934 !IsStatic
&& !(InstanceExpression
is This
) && TypeManager
.mbr_type
!= null && TypeManager
.IsSubclassOf (DeclaringType
, TypeManager
.mbr_type
)) {
4935 Report
.SymbolRelatedToPreviousError (DeclaringType
);
4936 Report
.Warning (197, 1, loc
,
4937 "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",
4938 GetSignatureForError ());
4941 eclass
= ExprClass
.Variable
;
4945 bool is_marshal_by_ref ()
4947 return !IsStatic
&& Type
.IsValueType
&& TypeManager
.mbr_type
!= null && TypeManager
.IsSubclassOf (DeclaringType
, TypeManager
.mbr_type
);
4950 public override void CheckMarshalByRefAccess (EmitContext ec
)
4952 if (is_marshal_by_ref () && !(InstanceExpression
is This
)) {
4953 Report
.SymbolRelatedToPreviousError (DeclaringType
);
4954 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",
4955 GetSignatureForError ());
4959 public override int GetHashCode ()
4961 return FieldInfo
.GetHashCode ();
4964 public bool IsFixed
{
4967 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
4969 IVariableReference variable
= InstanceExpression
as IVariableReference
;
4970 return variable
!= null && InstanceExpression
.Type
.IsValueType
&& variable
.IsFixed
;
4974 public bool IsHoisted
{
4976 IVariableReference hv
= InstanceExpression
as IVariableReference
;
4977 return hv
!= null && hv
.IsHoisted
;
4981 public override bool Equals (object obj
)
4983 FieldExpr fe
= obj
as FieldExpr
;
4987 if (FieldInfo
!= fe
.FieldInfo
)
4990 if (InstanceExpression
== null || fe
.InstanceExpression
== null)
4993 return InstanceExpression
.Equals (fe
.InstanceExpression
);
4996 public void Emit (EmitContext ec
, bool leave_copy
)
4998 ILGenerator ig
= ec
.ig
;
4999 bool is_volatile
= false;
5001 FieldBase f
= TypeManager
.GetField (FieldInfo
);
5003 if ((f
.ModFlags
& Modifiers
.VOLATILE
) != 0)
5006 f
.SetMemberIsUsed ();
5009 if (FieldInfo
.IsStatic
){
5011 ig
.Emit (OpCodes
.Volatile
);
5013 ig
.Emit (OpCodes
.Ldsfld
, GetConstructedFieldInfo ());
5016 EmitInstance (ec
, false);
5018 IFixedBuffer ff
= AttributeTester
.GetFixedBuffer (FieldInfo
);
5020 ig
.Emit (OpCodes
.Ldflda
, GetConstructedFieldInfo ());
5021 ig
.Emit (OpCodes
.Ldflda
, ff
.Element
);
5024 ig
.Emit (OpCodes
.Volatile
);
5026 ig
.Emit (OpCodes
.Ldfld
, GetConstructedFieldInfo ());
5031 ec
.ig
.Emit (OpCodes
.Dup
);
5032 if (!FieldInfo
.IsStatic
) {
5033 temp
= new LocalTemporary (this.Type
);
5039 public void EmitAssign (EmitContext ec
, Expression source
, bool leave_copy
, bool prepare_for_load
)
5041 FieldAttributes fa
= FieldInfo
.Attributes
;
5042 bool is_static
= (fa
& FieldAttributes
.Static
) != 0;
5043 bool is_readonly
= (fa
& FieldAttributes
.InitOnly
) != 0;
5044 ILGenerator ig
= ec
.ig
;
5046 if (is_readonly
&& !ec
.IsConstructor
){
5047 Report_AssignToReadonly (source
);
5051 prepared
= prepare_for_load
;
5052 EmitInstance (ec
, prepared
);
5056 ec
.ig
.Emit (OpCodes
.Dup
);
5057 if (!FieldInfo
.IsStatic
) {
5058 temp
= new LocalTemporary (this.Type
);
5063 FieldBase f
= TypeManager
.GetField (FieldInfo
);
5065 if ((f
.ModFlags
& Modifiers
.VOLATILE
) != 0)
5066 ig
.Emit (OpCodes
.Volatile
);
5072 ig
.Emit (OpCodes
.Stsfld
, GetConstructedFieldInfo ());
5074 ig
.Emit (OpCodes
.Stfld
, GetConstructedFieldInfo ());
5083 public override void Emit (EmitContext ec
)
5088 public override void EmitSideEffect (EmitContext ec
)
5090 FieldBase f
= TypeManager
.GetField (FieldInfo
);
5091 bool is_volatile
= f
!= null && (f
.ModFlags
& Modifiers
.VOLATILE
) != 0;
5093 if (is_volatile
|| is_marshal_by_ref ())
5094 base.EmitSideEffect (ec
);
5097 public override void Error_VariableIsUsedBeforeItIsDeclared (string name
)
5099 Report
.Error (844, loc
,
5100 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the field `{1}'",
5101 name
, GetSignatureForError ());
5104 public void AddressOf (EmitContext ec
, AddressOp mode
)
5106 ILGenerator ig
= ec
.ig
;
5108 FieldBase f
= TypeManager
.GetField (FieldInfo
);
5110 if ((f
.ModFlags
& Modifiers
.VOLATILE
) != 0){
5111 Report
.Warning (420, 1, loc
, "`{0}': A volatile field references will not be treated as volatile",
5112 f
.GetSignatureForError ());
5115 if ((mode
& AddressOp
.Store
) != 0)
5117 if ((mode
& AddressOp
.Load
) != 0)
5118 f
.SetMemberIsUsed ();
5122 // Handle initonly fields specially: make a copy and then
5123 // get the address of the copy.
5126 if (FieldInfo
.IsInitOnly
){
5128 if (ec
.IsConstructor
){
5129 if (FieldInfo
.IsStatic
){
5141 local
= ig
.DeclareLocal (type
);
5142 ig
.Emit (OpCodes
.Stloc
, local
);
5143 ig
.Emit (OpCodes
.Ldloca
, local
);
5148 if (FieldInfo
.IsStatic
){
5149 ig
.Emit (OpCodes
.Ldsflda
, GetConstructedFieldInfo ());
5152 EmitInstance (ec
, false);
5153 ig
.Emit (OpCodes
.Ldflda
, GetConstructedFieldInfo ());
5157 FieldInfo
GetConstructedFieldInfo ()
5159 if (constructed_generic_type
== null)
5162 return TypeBuilder
.GetField (constructed_generic_type
, FieldInfo
);
5164 throw new NotSupportedException ();
5168 public override void MutateHoistedGenericType (AnonymousMethodStorey storey
)
5170 FieldInfo
= storey
.MutateField (FieldInfo
);
5171 base.MutateHoistedGenericType (storey
);
5177 /// Expression that evaluates to a Property. The Assign class
5178 /// might set the `Value' expression if we are in an assignment.
5180 /// This is not an LValue because we need to re-write the expression, we
5181 /// can not take data from the stack and store it.
5183 public class PropertyExpr
: MemberExpr
, IAssignMethod
{
5184 public readonly PropertyInfo PropertyInfo
;
5185 MethodInfo getter
, setter
;
5190 LocalTemporary temp
;
5193 public PropertyExpr (Type container_type
, PropertyInfo pi
, Location l
)
5196 eclass
= ExprClass
.PropertyAccess
;
5200 type
= TypeManager
.TypeToCoreType (pi
.PropertyType
);
5202 ResolveAccessors (container_type
);
5205 public override string Name
{
5207 return PropertyInfo
.Name
;
5211 public override bool IsInstance
{
5217 public override bool IsStatic
{
5223 public override Expression
CreateExpressionTree (EmitContext ec
)
5226 if (IsSingleDimensionalArrayLength ()) {
5227 args
= new ArrayList (1);
5228 args
.Add (new Argument (InstanceExpression
.CreateExpressionTree (ec
)));
5229 return CreateExpressionFactoryCall ("ArrayLength", args
);
5233 Error_BaseAccessInExpressionTree (loc
);
5237 args
= new ArrayList (2);
5238 if (InstanceExpression
== null)
5239 args
.Add (new Argument (new NullLiteral (loc
)));
5241 args
.Add (new Argument (InstanceExpression
.CreateExpressionTree (ec
)));
5242 args
.Add (new Argument (new TypeOfMethodInfo (getter
, loc
)));
5243 return CreateExpressionFactoryCall ("Property", args
);
5246 public Expression
CreateSetterTypeOfExpression ()
5248 return new TypeOfMethodInfo (setter
, loc
);
5251 public override Type DeclaringType
{
5253 return PropertyInfo
.DeclaringType
;
5257 public override string GetSignatureForError ()
5259 return TypeManager
.GetFullNameSignature (PropertyInfo
);
5262 void FindAccessors (Type invocation_type
)
5264 const BindingFlags flags
= BindingFlags
.Public
| BindingFlags
.NonPublic
|
5265 BindingFlags
.Static
| BindingFlags
.Instance
|
5266 BindingFlags
.DeclaredOnly
;
5268 Type current
= PropertyInfo
.DeclaringType
;
5269 for (; current
!= null; current
= current
.BaseType
) {
5270 MemberInfo
[] group = TypeManager
.MemberLookup (
5271 invocation_type
, invocation_type
, current
,
5272 MemberTypes
.Property
, flags
, PropertyInfo
.Name
, null);
5277 if (group.Length
!= 1)
5278 // Oooops, can this ever happen ?
5281 PropertyInfo pi
= (PropertyInfo
) group [0];
5284 getter
= pi
.GetGetMethod (true);
5287 setter
= pi
.GetSetMethod (true);
5289 MethodInfo accessor
= getter
!= null ? getter
: setter
;
5291 if (!accessor
.IsVirtual
)
5297 // We also perform the permission checking here, as the PropertyInfo does not
5298 // hold the information for the accessibility of its setter/getter
5300 // TODO: Refactor to use some kind of cache together with GetPropertyFromAccessor
5301 void ResolveAccessors (Type container_type
)
5303 FindAccessors (container_type
);
5305 if (getter
!= null) {
5306 MethodBase the_getter
= TypeManager
.DropGenericMethodArguments (getter
);
5307 IMethodData md
= TypeManager
.GetMethod (the_getter
);
5309 md
.SetMemberIsUsed ();
5311 is_static
= getter
.IsStatic
;
5314 if (setter
!= null) {
5315 MethodBase the_setter
= TypeManager
.DropGenericMethodArguments (setter
);
5316 IMethodData md
= TypeManager
.GetMethod (the_setter
);
5318 md
.SetMemberIsUsed ();
5320 is_static
= setter
.IsStatic
;
5324 public override void MutateHoistedGenericType (AnonymousMethodStorey storey
)
5326 if (InstanceExpression
!= null)
5327 InstanceExpression
.MutateHoistedGenericType (storey
);
5329 type
= storey
.MutateType (type
);
5331 getter
= storey
.MutateGenericMethod (getter
);
5333 setter
= storey
.MutateGenericMethod (setter
);
5336 bool InstanceResolve (EmitContext ec
, bool lvalue_instance
, bool must_do_cs1540_check
)
5339 InstanceExpression
= null;
5343 if (InstanceExpression
== null) {
5344 SimpleName
.Error_ObjectRefRequired (ec
, loc
, GetSignatureForError ());
5348 InstanceExpression
= InstanceExpression
.DoResolve (ec
);
5349 if (lvalue_instance
&& InstanceExpression
!= null)
5350 InstanceExpression
= InstanceExpression
.ResolveLValue (ec
, EmptyExpression
.LValueMemberAccess
, loc
);
5352 if (InstanceExpression
== null)
5355 InstanceExpression
.CheckMarshalByRefAccess (ec
);
5357 if (must_do_cs1540_check
&& (InstanceExpression
!= EmptyExpression
.Null
) &&
5358 !TypeManager
.IsInstantiationOfSameGenericType (InstanceExpression
.Type
, ec
.ContainerType
) &&
5359 !TypeManager
.IsNestedChildOf (ec
.ContainerType
, InstanceExpression
.Type
) &&
5360 !TypeManager
.IsSubclassOf (InstanceExpression
.Type
, ec
.ContainerType
)) {
5361 Report
.SymbolRelatedToPreviousError (PropertyInfo
);
5362 Error_CannotAccessProtected (loc
, PropertyInfo
, InstanceExpression
.Type
, ec
.ContainerType
);
5369 void Error_PropertyNotFound (MethodInfo mi
, bool getter
)
5371 // TODO: correctly we should compare arguments but it will lead to bigger changes
5372 if (mi
is MethodBuilder
) {
5373 Error_TypeDoesNotContainDefinition (loc
, PropertyInfo
.DeclaringType
, Name
);
5377 StringBuilder sig
= new StringBuilder (TypeManager
.CSharpName (mi
.DeclaringType
));
5379 AParametersCollection iparams
= TypeManager
.GetParameterData (mi
);
5380 sig
.Append (getter
? "get_" : "set_");
5382 sig
.Append (iparams
.GetSignatureForError ());
5384 Report
.SymbolRelatedToPreviousError (mi
);
5385 Report
.Error (1546, loc
, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
5386 Name
, sig
.ToString ());
5389 public bool IsAccessibleFrom (Type invocation_type
, bool lvalue
)
5392 MethodInfo accessor
= lvalue
? setter
: getter
;
5393 if (accessor
== null && lvalue
)
5395 return accessor
!= null && IsAccessorAccessible (invocation_type
, accessor
, out dummy
);
5398 bool IsSingleDimensionalArrayLength ()
5400 if (DeclaringType
!= TypeManager
.array_type
|| getter
== null || Name
!= "Length")
5403 string t_name
= InstanceExpression
.Type
.Name
;
5404 int t_name_len
= t_name
.Length
;
5405 return t_name_len
> 2 && t_name
[t_name_len
- 2] == '[';
5408 override public Expression
DoResolve (EmitContext ec
)
5413 if (getter
!= null){
5414 if (TypeManager
.GetParameterData (getter
).Count
!= 0){
5415 Error_PropertyNotFound (getter
, true);
5420 if (getter
== null){
5422 // The following condition happens if the PropertyExpr was
5423 // created, but is invalid (ie, the property is inaccessible),
5424 // and we did not want to embed the knowledge about this in
5425 // the caller routine. This only avoids double error reporting.
5430 if (InstanceExpression
!= EmptyExpression
.Null
) {
5431 Report
.Error (154, loc
, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5432 TypeManager
.GetFullNameSignature (PropertyInfo
));
5437 bool must_do_cs1540_check
= false;
5438 if (getter
!= null &&
5439 !IsAccessorAccessible (ec
.ContainerType
, getter
, out must_do_cs1540_check
)) {
5440 PropertyBase
.PropertyMethod pm
= TypeManager
.GetMethod (getter
) as PropertyBase
.PropertyMethod
;
5441 if (pm
!= null && pm
.HasCustomAccessModifier
) {
5442 Report
.SymbolRelatedToPreviousError (pm
);
5443 Report
.Error (271, loc
, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5444 TypeManager
.CSharpSignature (getter
));
5447 Report
.SymbolRelatedToPreviousError (getter
);
5448 ErrorIsInaccesible (loc
, TypeManager
.CSharpSignature (getter
));
5453 if (!InstanceResolve (ec
, false, must_do_cs1540_check
))
5457 // Only base will allow this invocation to happen.
5459 if (IsBase
&& getter
.IsAbstract
) {
5460 Error_CannotCallAbstractBase (TypeManager
.GetFullNameSignature (PropertyInfo
));
5463 if (PropertyInfo
.PropertyType
.IsPointer
&& !ec
.InUnsafe
){
5467 if (!ec
.IsInObsoleteScope
) {
5468 PropertyBase pb
= TypeManager
.GetProperty (PropertyInfo
);
5470 pb
.CheckObsoleteness (loc
);
5472 ObsoleteAttribute oa
= AttributeTester
.GetMemberObsoleteAttribute (PropertyInfo
);
5474 AttributeTester
.Report_ObsoleteMessage (oa
, GetSignatureForError (), loc
);
5483 override public Expression
DoResolveLValue (EmitContext ec
, Expression right_side
)
5485 if (right_side
== EmptyExpression
.OutAccess
) {
5486 if (ec
.CurrentBlock
.Toplevel
.GetTransparentIdentifier (PropertyInfo
.Name
) != null) {
5487 Report
.Error (1939, loc
, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5490 Report
.Error (206, loc
, "A property or indexer `{0}' may not be passed as `ref' or `out' parameter",
5491 GetSignatureForError ());
5496 if (right_side
== EmptyExpression
.LValueMemberAccess
|| right_side
== EmptyExpression
.LValueMemberOutAccess
) {
5497 Error_CannotModifyIntermediateExpressionValue (ec
);
5500 if (setter
== null){
5502 // The following condition happens if the PropertyExpr was
5503 // created, but is invalid (ie, the property is inaccessible),
5504 // and we did not want to embed the knowledge about this in
5505 // the caller routine. This only avoids double error reporting.
5510 if (ec
.CurrentBlock
.Toplevel
.GetTransparentIdentifier (PropertyInfo
.Name
) != null) {
5511 Report
.Error (1947, loc
, "A range variable `{0}' cannot be assigned to. Consider using `let' clause to store the value",
5514 Report
.Error (200, loc
, "Property or indexer `{0}' cannot be assigned to (it is read only)",
5515 GetSignatureForError ());
5520 if (TypeManager
.GetParameterData (setter
).Count
!= 1){
5521 Error_PropertyNotFound (setter
, false);
5525 bool must_do_cs1540_check
;
5526 if (!IsAccessorAccessible (ec
.ContainerType
, setter
, out must_do_cs1540_check
)) {
5527 PropertyBase
.PropertyMethod pm
= TypeManager
.GetMethod (setter
) as PropertyBase
.PropertyMethod
;
5528 if (pm
!= null && pm
.HasCustomAccessModifier
) {
5529 Report
.SymbolRelatedToPreviousError (pm
);
5530 Report
.Error (272, loc
, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5531 TypeManager
.CSharpSignature (setter
));
5534 Report
.SymbolRelatedToPreviousError (setter
);
5535 ErrorIsInaccesible (loc
, TypeManager
.CSharpSignature (setter
));
5540 if (!InstanceResolve (ec
, PropertyInfo
.DeclaringType
.IsValueType
, must_do_cs1540_check
))
5544 // Only base will allow this invocation to happen.
5546 if (IsBase
&& setter
.IsAbstract
){
5547 Error_CannotCallAbstractBase (TypeManager
.GetFullNameSignature (PropertyInfo
));
5550 if (PropertyInfo
.PropertyType
.IsPointer
&& !ec
.InUnsafe
) {
5554 if (!ec
.IsInObsoleteScope
) {
5555 PropertyBase pb
= TypeManager
.GetProperty (PropertyInfo
);
5557 pb
.CheckObsoleteness (loc
);
5559 ObsoleteAttribute oa
= AttributeTester
.GetMemberObsoleteAttribute (PropertyInfo
);
5561 AttributeTester
.Report_ObsoleteMessage (oa
, GetSignatureForError (), loc
);
5568 public override void Emit (EmitContext ec
)
5573 public void Emit (EmitContext ec
, bool leave_copy
)
5576 // Special case: length of single dimension array property is turned into ldlen
5578 if (IsSingleDimensionalArrayLength ()) {
5580 EmitInstance (ec
, false);
5581 ec
.ig
.Emit (OpCodes
.Ldlen
);
5582 ec
.ig
.Emit (OpCodes
.Conv_I4
);
5586 Invocation
.EmitCall (ec
, IsBase
, InstanceExpression
, getter
, null, loc
, prepared
, false);
5589 ec
.ig
.Emit (OpCodes
.Dup
);
5591 temp
= new LocalTemporary (this.Type
);
5598 // Implements the IAssignMethod interface for assignments
5600 public void EmitAssign (EmitContext ec
, Expression source
, bool leave_copy
, bool prepare_for_load
)
5602 Expression my_source
= source
;
5604 if (prepare_for_load
) {
5609 ec
.ig
.Emit (OpCodes
.Dup
);
5611 temp
= new LocalTemporary (this.Type
);
5615 } else if (leave_copy
) {
5617 temp
= new LocalTemporary (this.Type
);
5622 ArrayList args
= new ArrayList (1);
5623 args
.Add (new Argument (my_source
, Argument
.AType
.Expression
));
5625 Invocation
.EmitCall (ec
, IsBase
, InstanceExpression
, setter
, args
, loc
, false, prepared
);
5635 /// Fully resolved expression that evaluates to an Event
5637 public class EventExpr
: MemberExpr
{
5638 public readonly EventInfo EventInfo
;
5641 MethodInfo add_accessor
, remove_accessor
;
5643 public EventExpr (EventInfo ei
, Location loc
)
5647 eclass
= ExprClass
.EventAccess
;
5649 add_accessor
= TypeManager
.GetAddMethod (ei
);
5650 remove_accessor
= TypeManager
.GetRemoveMethod (ei
);
5651 if (add_accessor
.IsStatic
|| remove_accessor
.IsStatic
)
5654 if (EventInfo
is MyEventBuilder
){
5655 MyEventBuilder eb
= (MyEventBuilder
) EventInfo
;
5656 type
= eb
.EventType
;
5659 type
= EventInfo
.EventHandlerType
;
5662 public override string Name
{
5664 return EventInfo
.Name
;
5668 public override bool IsInstance
{
5674 public override bool IsStatic
{
5680 public override Type DeclaringType
{
5682 return EventInfo
.DeclaringType
;
5686 void Error_AssignmentEventOnly ()
5688 Report
.Error (79, loc
, "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5689 GetSignatureForError ());
5692 public override MemberExpr
ResolveMemberAccess (EmitContext ec
, Expression left
, Location loc
,
5693 SimpleName original
)
5696 // If the event is local to this class, we transform ourselves into a FieldExpr
5699 if (EventInfo
.DeclaringType
== ec
.ContainerType
||
5700 TypeManager
.IsNestedChildOf(ec
.ContainerType
, EventInfo
.DeclaringType
)) {
5701 EventField mi
= TypeManager
.GetEventField (EventInfo
);
5704 if (!ec
.IsInObsoleteScope
)
5705 mi
.CheckObsoleteness (loc
);
5707 if ((mi
.ModFlags
& (Modifiers
.ABSTRACT
| Modifiers
.EXTERN
)) != 0 && !ec
.IsInCompoundAssignment
)
5708 Error_AssignmentEventOnly ();
5710 FieldExpr ml
= new FieldExpr (mi
.FieldBuilder
, loc
);
5712 InstanceExpression
= null;
5714 return ml
.ResolveMemberAccess (ec
, left
, loc
, original
);
5718 if (left
is This
&& !ec
.IsInCompoundAssignment
)
5719 Error_AssignmentEventOnly ();
5721 return base.ResolveMemberAccess (ec
, left
, loc
, original
);
5724 bool InstanceResolve (EmitContext ec
, bool must_do_cs1540_check
)
5727 InstanceExpression
= null;
5731 if (InstanceExpression
== null) {
5732 SimpleName
.Error_ObjectRefRequired (ec
, loc
, GetSignatureForError ());
5736 InstanceExpression
= InstanceExpression
.DoResolve (ec
);
5737 if (InstanceExpression
== null)
5740 if (IsBase
&& add_accessor
.IsAbstract
) {
5741 Error_CannotCallAbstractBase(TypeManager
.CSharpSignature(add_accessor
));
5746 // This is using the same mechanism as the CS1540 check in PropertyExpr.
5747 // However, in the Event case, we reported a CS0122 instead.
5749 // TODO: Exact copy from PropertyExpr
5751 if (must_do_cs1540_check
&& InstanceExpression
!= EmptyExpression
.Null
&&
5752 !TypeManager
.IsInstantiationOfSameGenericType (InstanceExpression
.Type
, ec
.ContainerType
) &&
5753 !TypeManager
.IsNestedChildOf (ec
.ContainerType
, InstanceExpression
.Type
) &&
5754 !TypeManager
.IsSubclassOf (InstanceExpression
.Type
, ec
.ContainerType
)) {
5755 Report
.SymbolRelatedToPreviousError (EventInfo
);
5756 ErrorIsInaccesible (loc
, TypeManager
.CSharpSignature (EventInfo
));
5763 public bool IsAccessibleFrom (Type invocation_type
)
5766 return IsAccessorAccessible (invocation_type
, add_accessor
, out dummy
) &&
5767 IsAccessorAccessible (invocation_type
, remove_accessor
, out dummy
);
5770 public override Expression
CreateExpressionTree (EmitContext ec
)
5772 throw new NotSupportedException ("ET");
5775 public override Expression
DoResolveLValue (EmitContext ec
, Expression right_side
)
5777 // contexts where an LValue is valid have already devolved to FieldExprs
5778 Error_CannotAssign ();
5782 public override Expression
DoResolve (EmitContext ec
)
5784 bool must_do_cs1540_check
;
5785 if (!(IsAccessorAccessible (ec
.ContainerType
, add_accessor
, out must_do_cs1540_check
) &&
5786 IsAccessorAccessible (ec
.ContainerType
, remove_accessor
, out must_do_cs1540_check
))) {
5787 Report
.SymbolRelatedToPreviousError (EventInfo
);
5788 ErrorIsInaccesible (loc
, TypeManager
.CSharpSignature (EventInfo
));
5792 if (!InstanceResolve (ec
, must_do_cs1540_check
))
5795 if (!ec
.IsInCompoundAssignment
) {
5796 Error_CannotAssign ();
5800 if (!ec
.IsInObsoleteScope
) {
5801 EventField ev
= TypeManager
.GetEventField (EventInfo
);
5803 ev
.CheckObsoleteness (loc
);
5805 ObsoleteAttribute oa
= AttributeTester
.GetMemberObsoleteAttribute (EventInfo
);
5807 AttributeTester
.Report_ObsoleteMessage (oa
, GetSignatureForError (), loc
);
5814 public override void Emit (EmitContext ec
)
5816 Error_CannotAssign ();
5819 public void Error_CannotAssign ()
5821 Report
.Error (70, loc
,
5822 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
5823 GetSignatureForError (), TypeManager
.CSharpName (EventInfo
.DeclaringType
));
5826 public override string GetSignatureForError ()
5828 return TypeManager
.CSharpSignature (EventInfo
);
5831 public void EmitAddOrRemove (EmitContext ec
, bool is_add
, Expression source
)
5833 ArrayList args
= new ArrayList (1);
5834 args
.Add (new Argument (source
, Argument
.AType
.Expression
));
5835 Invocation
.EmitCall (ec
, IsBase
, InstanceExpression
, is_add
? add_accessor
: remove_accessor
, args
, loc
);
5839 public class TemporaryVariable
: VariableReference
5843 public TemporaryVariable (Type type
, Location loc
)
5847 eclass
= ExprClass
.Variable
;
5850 public override Expression
CreateExpressionTree (EmitContext ec
)
5852 throw new NotSupportedException ("ET");
5855 public override Expression
DoResolve (EmitContext ec
)
5860 TypeExpr te
= new TypeExpression (type
, loc
);
5861 li
= ec
.CurrentBlock
.AddTemporaryVariable (te
, loc
);
5862 if (!li
.Resolve (ec
))
5866 // Don't capture temporary variables except when using
5867 // iterator redirection
5869 if (ec
.CurrentAnonymousMethod
!= null && ec
.CurrentAnonymousMethod
.IsIterator
&& ec
.IsVariableCapturingRequired
) {
5870 AnonymousMethodStorey storey
= li
.Block
.Explicit
.CreateAnonymousMethodStorey (ec
);
5871 storey
.CaptureLocalVariable (ec
, li
);
5877 public override Expression
DoResolveLValue (EmitContext ec
, Expression right_side
)
5879 return DoResolve (ec
);
5882 public override void Emit (EmitContext ec
)
5887 public void EmitAssign (EmitContext ec
, Expression source
)
5889 EmitAssign (ec
, source
, false, false);
5892 public override HoistedVariable HoistedVariable
{
5893 get { return li.HoistedVariableReference; }
5896 public override bool IsFixed
{
5897 get { return true; }
5900 public override bool IsRef
{
5901 get { return false; }
5904 public override string Name
{
5905 get { throw new NotImplementedException (); }
5908 public override void SetHasAddressTaken ()
5910 throw new NotImplementedException ();
5913 protected override ILocalVariable Variable
{
5917 public override VariableInfo VariableInfo
{
5918 get { throw new NotImplementedException (); }
5923 /// Handles `var' contextual keyword; var becomes a keyword only
5924 /// if no type called var exists in a variable scope
5926 public class VarExpr
: SimpleName
5928 // Used for error reporting only
5929 ArrayList initializer
;
5931 public VarExpr (Location loc
)
5936 public ArrayList VariableInitializer
{
5938 this.initializer
= value;
5942 public bool InferType (EmitContext ec
, Expression right_side
)
5945 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
5947 type
= right_side
.Type
;
5948 if (type
== TypeManager
.null_type
|| type
== TypeManager
.void_type
|| type
== TypeManager
.anonymous_method_type
) {
5949 Report
.Error (815, loc
, "An implicitly typed local variable declaration cannot be initialized with `{0}'",
5950 right_side
.GetSignatureForError ());
5954 eclass
= ExprClass
.Variable
;
5958 protected override void Error_TypeOrNamespaceNotFound (IResolveContext ec
)
5960 Report
.Error (825, loc
, "The contextual keyword `var' may only appear within a local variable declaration");
5963 public override TypeExpr
ResolveAsContextualType (IResolveContext rc
, bool silent
)
5965 TypeExpr te
= base.ResolveAsContextualType (rc
, true);
5969 if (initializer
== null)
5972 if (initializer
.Count
> 1) {
5973 Location loc
= ((Mono
.CSharp
.CSharpParser
.VariableDeclaration
)initializer
[1]).Location
;
5974 Report
.Error (819, loc
, "An implicitly typed local variable declaration cannot include multiple declarators");
5979 Expression variable_initializer
= ((Mono
.CSharp
.CSharpParser
.VariableDeclaration
)initializer
[0]).expression_or_array_initializer
;
5980 if (variable_initializer
== null) {
5981 Report
.Error (818, loc
, "An implicitly typed local variable declarator must include an initializer");