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 using SLE
= System
.Linq
.Expressions
;
26 /// The ExprClass class contains the is used to pass the
27 /// classification of an expression (value, variable, namespace,
28 /// type, method group, property access, event access, indexer access,
31 public enum ExprClass
: byte {
47 /// This is used to tell Resolve in which types of expressions we're
51 public enum ResolveFlags
{
52 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
55 // Returns a type expression.
58 // Returns a method group.
61 TypeParameter
= 1 << 3,
63 // Mask of all the expression class flags.
64 MaskExprClass
= VariableOrValue
| Type
| MethodGroup
| TypeParameter
,
66 // Disable control flow analysis while resolving the expression.
67 // This is used when resolving the instance expression of a field expression.
68 DisableFlowAnalysis
= 1 << 10,
70 // Set if this is resolving the first part of a MemberAccess.
71 Intermediate
= 1 << 11,
73 // Disable control flow analysis _of struct_ while resolving the expression.
74 // This is used when resolving the instance expression of a field expression.
75 DisableStructFlowAnalysis
= 1 << 12,
80 // This is just as a hint to AddressOf of what will be done with the
83 public enum AddressOp
{
90 /// This interface is implemented by variables
92 public interface IMemoryLocation
{
94 /// The AddressOf method should generate code that loads
95 /// the address of the object and leaves it on the stack.
97 /// The `mode' argument is used to notify the expression
98 /// of whether this will be used to read from the address or
99 /// write to the address.
101 /// This is just a hint that can be used to provide good error
102 /// reporting, and should have no other side effects.
104 void AddressOf (EmitContext ec
, AddressOp mode
);
108 // An expressions resolved as a direct variable reference
110 public interface IVariableReference
: IFixedExpression
112 bool IsHoisted { get; }
114 VariableInfo VariableInfo { get; }
116 void SetHasAddressTaken ();
120 // Implemented by an expression which could be or is always
123 public interface IFixedExpression
125 bool IsFixed { get; }
129 /// Base class for expressions
131 public abstract class Expression
{
132 public ExprClass eclass
;
134 protected Location loc
;
138 set { type = value; }
141 public virtual Location Location
{
145 // Not nice but we have broken hierarchy.
146 public virtual void CheckMarshalByRefAccess (ResolveContext ec
)
150 public virtual bool GetAttributableValue (ResolveContext ec
, Type value_type
, out object value)
152 Attribute
.Error_AttributeArgumentNotValid (ec
, loc
);
157 public virtual string GetSignatureForError ()
159 return TypeManager
.CSharpName (type
);
162 public static bool IsAccessorAccessible (Type invocation_type
, MethodInfo mi
, out bool must_do_cs1540_check
)
164 MethodAttributes ma
= mi
.Attributes
& MethodAttributes
.MemberAccessMask
;
166 must_do_cs1540_check
= false; // by default we do not check for this
168 if (ma
== MethodAttributes
.Public
)
172 // If only accessible to the current class or children
174 if (ma
== MethodAttributes
.Private
)
175 return TypeManager
.IsPrivateAccessible (invocation_type
, mi
.DeclaringType
) ||
176 TypeManager
.IsNestedChildOf (invocation_type
, mi
.DeclaringType
);
178 if (TypeManager
.IsThisOrFriendAssembly (invocation_type
.Assembly
, mi
.DeclaringType
.Assembly
)) {
179 if (ma
== MethodAttributes
.Assembly
|| ma
== MethodAttributes
.FamORAssem
)
182 if (ma
== MethodAttributes
.Assembly
|| ma
== MethodAttributes
.FamANDAssem
)
186 // Family and FamANDAssem require that we derive.
187 // FamORAssem requires that we derive if in different assemblies.
188 if (!TypeManager
.IsNestedFamilyAccessible (invocation_type
, mi
.DeclaringType
))
191 if (!TypeManager
.IsNestedChildOf (invocation_type
, mi
.DeclaringType
))
192 must_do_cs1540_check
= true;
197 public virtual bool IsNull
{
204 /// Performs semantic analysis on the Expression
208 /// The Resolve method is invoked to perform the semantic analysis
211 /// The return value is an expression (it can be the
212 /// same expression in some cases) or a new
213 /// expression that better represents this node.
215 /// For example, optimizations of Unary (LiteralInt)
216 /// would return a new LiteralInt with a negated
219 /// If there is an error during semantic analysis,
220 /// then an error should be reported (using Report)
221 /// and a null value should be returned.
223 /// There are two side effects expected from calling
224 /// Resolve(): the the field variable "eclass" should
225 /// be set to any value of the enumeration
226 /// `ExprClass' and the type variable should be set
227 /// to a valid type (this is the type of the
230 public abstract Expression
DoResolve (ResolveContext ec
);
232 public virtual Expression
DoResolveLValue (ResolveContext ec
, Expression right_side
)
238 // This is used if the expression should be resolved as a type or namespace name.
239 // the default implementation fails.
241 public virtual FullNamedExpression
ResolveAsTypeStep (IMemberContext rc
, bool silent
)
244 ResolveContext ec
= new ResolveContext (rc
);
245 Expression e
= Resolve (ec
);
247 e
.Error_UnexpectedKind (ec
, ResolveFlags
.Type
, loc
);
254 // C# 3.0 introduced contextual keywords (var) which behaves like a type if type with
255 // same name exists or as a keyword when no type was found
257 public virtual TypeExpr
ResolveAsContextualType (IMemberContext rc
, bool silent
)
259 return ResolveAsTypeTerminal (rc
, silent
);
263 // This is used to resolve the expression as a type, a null
264 // value will be returned if the expression is not a type
267 public virtual TypeExpr
ResolveAsTypeTerminal (IMemberContext ec
, bool silent
)
269 TypeExpr te
= ResolveAsBaseTerminal (ec
, silent
);
273 if (!silent
) { // && !(te is TypeParameterExpr)) {
274 ObsoleteAttribute obsolete_attr
= AttributeTester
.GetObsoleteAttribute (te
.Type
);
275 if (obsolete_attr
!= null && !ec
.IsObsolete
) {
276 AttributeTester
.Report_ObsoleteMessage (obsolete_attr
, te
.GetSignatureForError (), Location
, ec
.Compiler
.Report
);
280 GenericTypeExpr ct
= te
as GenericTypeExpr
;
283 // TODO: Constrained type parameters check for parameters of generic method overrides is broken
284 // There are 2 solutions.
285 // 1, Skip this check completely when we are in override/explicit impl scope
286 // 2, Copy type parameters constraints from base implementation and pass (they have to be emitted anyway)
288 MemberCore gm
= ec
as GenericMethod
;
291 if (gm
!= null && ((gm
.ModFlags
& Modifiers
.OVERRIDE
) != 0 || gm
.MemberName
.Left
!= null)) {
296 // TODO: silent flag is ignored
297 ct
.CheckConstraints (ec
);
303 public TypeExpr
ResolveAsBaseTerminal (IMemberContext ec
, bool silent
)
305 int errors
= ec
.Compiler
.Report
.Errors
;
307 FullNamedExpression fne
= ResolveAsTypeStep (ec
, silent
);
312 TypeExpr te
= fne
as TypeExpr
;
314 if (!silent
&& errors
== ec
.Compiler
.Report
.Errors
)
315 fne
.Error_UnexpectedKind (ec
.Compiler
.Report
, null, "type", loc
);
319 if (!te
.CheckAccessLevel (ec
)) {
320 ec
.Compiler
.Report
.SymbolRelatedToPreviousError (te
.Type
);
321 ErrorIsInaccesible (loc
, TypeManager
.CSharpName (te
.Type
), ec
.Compiler
.Report
);
329 public static void ErrorIsInaccesible (Location loc
, string name
, Report Report
)
331 Report
.Error (122, loc
, "`{0}' is inaccessible due to its protection level", name
);
334 protected static void Error_CannotAccessProtected (ResolveContext ec
, Location loc
, MemberInfo m
, Type qualifier
, Type container
)
336 ec
.Report
.Error (1540, loc
, "Cannot access protected member `{0}' via a qualifier of type `{1}'."
337 + " The qualifier must be of type `{2}' or derived from it",
338 TypeManager
.GetFullNameSignature (m
),
339 TypeManager
.CSharpName (qualifier
),
340 TypeManager
.CSharpName (container
));
344 public static void Error_InvalidExpressionStatement (Report Report
, Location loc
)
346 Report
.Error (201, loc
, "Only assignment, call, increment, decrement, and new object " +
347 "expressions can be used as a statement");
350 public void Error_InvalidExpressionStatement (BlockContext ec
)
352 Error_InvalidExpressionStatement (ec
.Report
, loc
);
355 public static void Error_VoidInvalidInTheContext (Location loc
, Report Report
)
357 Report
.Error (1547, loc
, "Keyword `void' cannot be used in this context");
360 public virtual void Error_ValueCannotBeConverted (ResolveContext ec
, Location loc
, Type target
, bool expl
)
362 Error_ValueCannotBeConvertedCore (ec
, loc
, target
, expl
);
365 protected void Error_ValueCannotBeConvertedCore (ResolveContext ec
, Location loc
, Type target
, bool expl
)
367 // The error was already reported as CS1660
368 if (type
== InternalType
.AnonymousMethod
)
371 if (TypeManager
.IsGenericParameter (Type
) && TypeManager
.IsGenericParameter (target
) && type
.Name
== target
.Name
) {
372 string sig1
= type
.DeclaringMethod
== null ?
373 TypeManager
.CSharpName (type
.DeclaringType
) :
374 TypeManager
.CSharpSignature (type
.DeclaringMethod
);
375 string sig2
= target
.DeclaringMethod
== null ?
376 TypeManager
.CSharpName (target
.DeclaringType
) :
377 TypeManager
.CSharpSignature (target
.DeclaringMethod
);
378 ec
.Report
.ExtraInformation (loc
,
380 "The generic parameter `{0}' of `{1}' cannot be converted to the generic parameter `{0}' of `{2}' (in the previous ",
381 Type
.Name
, sig1
, sig2
));
382 } else if (Type
.FullName
== target
.FullName
){
383 ec
.Report
.ExtraInformation (loc
,
385 "The type `{0}' has two conflicting definitions, one comes from `{1}' and the other from `{2}' (in the previous ",
386 Type
.FullName
, Type
.Assembly
.FullName
, target
.Assembly
.FullName
));
390 ec
.Report
.Error (30, loc
, "Cannot convert type `{0}' to `{1}'",
391 TypeManager
.CSharpName (type
), TypeManager
.CSharpName (target
));
395 ec
.Report
.DisableReporting ();
396 bool expl_exists
= Convert
.ExplicitConversion (ec
, this, target
, Location
.Null
) != null;
397 ec
.Report
.EnableReporting ();
400 ec
.Report
.Error (266, loc
, "Cannot implicitly convert type `{0}' to `{1}'. " +
401 "An explicit conversion exists (are you missing a cast?)",
402 TypeManager
.CSharpName (Type
), TypeManager
.CSharpName (target
));
406 ec
.Report
.Error (29, loc
, "Cannot implicitly convert type `{0}' to `{1}'",
407 TypeManager
.CSharpName (type
),
408 TypeManager
.CSharpName (target
));
411 public virtual void Error_VariableIsUsedBeforeItIsDeclared (Report Report
, string name
)
413 Report
.Error (841, loc
, "A local variable `{0}' cannot be used before it is declared", name
);
416 public void Error_TypeArgumentsCannotBeUsed (Report report
, Location loc
)
418 // Better message for possible generic expressions
419 if (eclass
== ExprClass
.MethodGroup
|| eclass
== ExprClass
.Type
) {
420 if (this is TypeExpr
)
421 report
.SymbolRelatedToPreviousError (type
);
423 string name
= eclass
== ExprClass
.Type
? ExprClassName
: "method";
424 report
.Error (308, loc
, "The non-generic {0} `{1}' cannot be used with the type arguments",
425 name
, GetSignatureForError ());
427 report
.Error (307, loc
, "The {0} `{1}' cannot be used with type arguments",
428 ExprClassName
, GetSignatureForError ());
432 protected virtual void Error_TypeDoesNotContainDefinition (ResolveContext ec
, Type type
, string name
)
434 Error_TypeDoesNotContainDefinition (ec
, loc
, type
, name
);
437 public static void Error_TypeDoesNotContainDefinition (ResolveContext ec
, Location loc
, Type type
, string name
)
439 ec
.Report
.SymbolRelatedToPreviousError (type
);
440 ec
.Report
.Error (117, loc
, "`{0}' does not contain a definition for `{1}'",
441 TypeManager
.CSharpName (type
), name
);
444 protected static void Error_ValueAssignment (ResolveContext ec
, Location loc
)
446 ec
.Report
.Error (131, loc
, "The left-hand side of an assignment must be a variable, a property or an indexer");
449 ResolveFlags ExprClassToResolveFlags
454 case ExprClass
.Namespace
:
455 return ResolveFlags
.Type
;
457 case ExprClass
.MethodGroup
:
458 return ResolveFlags
.MethodGroup
;
460 case ExprClass
.TypeParameter
:
461 return ResolveFlags
.TypeParameter
;
463 case ExprClass
.Value
:
464 case ExprClass
.Variable
:
465 case ExprClass
.PropertyAccess
:
466 case ExprClass
.EventAccess
:
467 case ExprClass
.IndexerAccess
:
468 return ResolveFlags
.VariableOrValue
;
471 throw new InternalErrorException (loc
.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
477 /// Resolves an expression and performs semantic analysis on it.
481 /// Currently Resolve wraps DoResolve to perform sanity
482 /// checking and assertion checking on what we expect from Resolve.
484 public Expression
Resolve (ResolveContext ec
, ResolveFlags flags
)
486 if ((flags
& ResolveFlags
.MaskExprClass
) == ResolveFlags
.Type
)
487 return ResolveAsTypeStep (ec
, false);
489 bool do_flow_analysis
= ec
.DoFlowAnalysis
;
490 bool omit_struct_analysis
= ec
.OmitStructFlowAnalysis
;
491 if ((flags
& ResolveFlags
.DisableFlowAnalysis
) != 0)
492 do_flow_analysis
= false;
493 if ((flags
& ResolveFlags
.DisableStructFlowAnalysis
) != 0)
494 omit_struct_analysis
= true;
497 using (ec
.WithFlowAnalysis (do_flow_analysis
, omit_struct_analysis
)) {
498 if (this is SimpleName
) {
499 bool intermediate
= (flags
& ResolveFlags
.Intermediate
) == ResolveFlags
.Intermediate
;
500 e
= ((SimpleName
) this).DoResolve (ec
, intermediate
);
509 if ((flags
& e
.ExprClassToResolveFlags
) == 0) {
510 e
.Error_UnexpectedKind (ec
, flags
, loc
);
514 if (e
.type
== null && !(e
is Namespace
)) {
515 throw new Exception (
516 "Expression " + e
.GetType () +
517 " did not set its type after Resolve\n" +
518 "called from: " + this.GetType ());
525 /// Resolves an expression and performs semantic analysis on it.
527 public Expression
Resolve (ResolveContext ec
)
529 Expression e
= Resolve (ec
, ResolveFlags
.VariableOrValue
| ResolveFlags
.MethodGroup
);
531 if (e
!= null && e
.eclass
== ExprClass
.MethodGroup
&& RootContext
.Version
== LanguageVersion
.ISO_1
) {
532 ((MethodGroupExpr
) e
).ReportUsageError (ec
);
538 public Constant
ResolveAsConstant (ResolveContext ec
, MemberCore mc
)
540 Expression e
= Resolve (ec
);
544 Constant c
= e
as Constant
;
548 if (type
!= null && TypeManager
.IsReferenceType (type
))
549 Const
.Error_ConstantCanBeInitializedWithNullOnly (type
, loc
, mc
.GetSignatureForError (), ec
.Report
);
551 Const
.Error_ExpressionMustBeConstant (loc
, mc
.GetSignatureForError (), ec
.Report
);
557 /// Resolves an expression for LValue assignment
561 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
562 /// checking and assertion checking on what we expect from Resolve
564 public Expression
ResolveLValue (ResolveContext ec
, Expression right_side
)
566 int errors
= ec
.Report
.Errors
;
567 bool out_access
= right_side
== EmptyExpression
.OutAccess
.Instance
;
569 Expression e
= DoResolveLValue (ec
, right_side
);
571 if (e
!= null && out_access
&& !(e
is IMemoryLocation
)) {
572 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
573 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
575 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
576 // e.GetType () + " " + e.GetSignatureForError ());
581 if (errors
== ec
.Report
.Errors
) {
583 ec
.Report
.Error (1510, loc
, "A ref or out argument must be an assignable variable");
585 Error_ValueAssignment (ec
, loc
);
590 if (e
.eclass
== ExprClass
.Invalid
)
591 throw new Exception ("Expression " + e
+ " ExprClass is Invalid after resolve");
593 if ((e
.type
== null) && !(e
is GenericTypeExpr
))
594 throw new Exception ("Expression " + e
+ " did not set its type after Resolve");
600 /// Emits the code for the expression
604 /// The Emit method is invoked to generate the code
605 /// for the expression.
607 public abstract void Emit (EmitContext ec
);
609 // Emit code to branch to @target if this expression is equivalent to @on_true.
610 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
611 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
612 // including the use of conditional branches. Note also that a branch MUST be emitted
613 public virtual void EmitBranchable (EmitContext ec
, Label target
, bool on_true
)
616 ec
.ig
.Emit (on_true
? OpCodes
.Brtrue
: OpCodes
.Brfalse
, target
);
619 // Emit this expression for its side effects, not for its value.
620 // The default implementation is to emit the value, and then throw it away.
621 // Subclasses can provide more efficient implementations, but those MUST be equivalent
622 public virtual void EmitSideEffect (EmitContext ec
)
625 ec
.ig
.Emit (OpCodes
.Pop
);
629 /// Protected constructor. Only derivate types should
630 /// be able to be created
633 protected Expression ()
635 eclass
= ExprClass
.Invalid
;
640 /// Returns a fully formed expression after a MemberLookup
643 public static Expression
ExprClassFromMemberInfo (Type container_type
, MemberInfo mi
, Location loc
)
646 return new EventExpr ((EventInfo
) mi
, loc
);
647 else if (mi
is FieldInfo
) {
648 FieldInfo fi
= (FieldInfo
) mi
;
649 if (fi
.IsLiteral
|| (fi
.IsInitOnly
&& fi
.FieldType
== TypeManager
.decimal_type
))
650 return new ConstantExpr (fi
, loc
);
651 return new FieldExpr (fi
, loc
);
652 } else if (mi
is PropertyInfo
)
653 return new PropertyExpr (container_type
, (PropertyInfo
) mi
, loc
);
654 else if (mi
is Type
) {
655 return new TypeExpression ((System
.Type
) mi
, loc
);
661 // TODO: [Obsolete ("Can be removed")]
662 protected static ArrayList almost_matched_members
= new ArrayList (4);
665 // FIXME: Probably implement a cache for (t,name,current_access_set)?
667 // This code could use some optimizations, but we need to do some
668 // measurements. For example, we could use a delegate to `flag' when
669 // something can not any longer be a method-group (because it is something
673 // If the return value is an Array, then it is an array of
676 // If the return value is an MemberInfo, it is anything, but a Method
680 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
681 // the arguments here and have MemberLookup return only the methods that
682 // match the argument count/type, unlike we are doing now (we delay this
685 // This is so we can catch correctly attempts to invoke instance methods
686 // from a static body (scan for error 120 in ResolveSimpleName).
689 // FIXME: Potential optimization, have a static ArrayList
692 public static Expression
MemberLookup (CompilerContext ctx
, Type container_type
, Type queried_type
, string name
,
693 MemberTypes mt
, BindingFlags bf
, Location loc
)
695 return MemberLookup (ctx
, container_type
, null, queried_type
, name
, mt
, bf
, loc
);
699 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
700 // `qualifier_type' or null to lookup members in the current class.
703 public static Expression
MemberLookup (CompilerContext ctx
, Type container_type
,
704 Type qualifier_type
, Type queried_type
,
705 string name
, MemberTypes mt
,
706 BindingFlags bf
, Location loc
)
708 almost_matched_members
.Clear ();
710 MemberInfo
[] mi
= TypeManager
.MemberLookup (container_type
, qualifier_type
,
711 queried_type
, mt
, bf
, name
, almost_matched_members
);
717 bool is_interface
= qualifier_type
!= null && qualifier_type
.IsInterface
;
718 ArrayList methods
= new ArrayList (2);
719 ArrayList non_methods
= null;
721 foreach (MemberInfo m
in mi
) {
722 if (m
is MethodBase
) {
727 if (non_methods
== null)
728 non_methods
= new ArrayList (2);
730 bool is_candidate
= true;
731 for (int i
= 0; i
< non_methods
.Count
; ++i
) {
732 MemberInfo n_m
= (MemberInfo
) non_methods
[i
];
733 if (n_m
.DeclaringType
.IsInterface
&& TypeManager
.ImplementsInterface (m
.DeclaringType
, n_m
.DeclaringType
)) {
734 non_methods
.Remove (n_m
);
736 } else if (m
.DeclaringType
.IsInterface
&& TypeManager
.ImplementsInterface (n_m
.DeclaringType
, m
.DeclaringType
)) {
737 is_candidate
= false;
747 if (methods
.Count
== 0 && non_methods
!= null && non_methods
.Count
> 1) {
748 ctx
.Report
.SymbolRelatedToPreviousError ((MemberInfo
)non_methods
[1]);
749 ctx
.Report
.SymbolRelatedToPreviousError ((MemberInfo
)non_methods
[0]);
750 ctx
.Report
.Error (229, loc
, "Ambiguity between `{0}' and `{1}'",
751 TypeManager
.GetFullNameSignature ((MemberInfo
)non_methods
[1]),
752 TypeManager
.GetFullNameSignature ((MemberInfo
)non_methods
[0]));
756 if (methods
.Count
== 0)
757 return ExprClassFromMemberInfo (container_type
, (MemberInfo
)non_methods
[0], loc
);
759 if (non_methods
!= null && non_methods
.Count
> 0) {
760 MethodBase method
= (MethodBase
) methods
[0];
761 MemberInfo non_method
= (MemberInfo
) non_methods
[0];
762 if (method
.DeclaringType
== non_method
.DeclaringType
) {
763 // Cannot happen with C# code, but is valid in IL
764 ctx
.Report
.SymbolRelatedToPreviousError (method
);
765 ctx
.Report
.SymbolRelatedToPreviousError (non_method
);
766 ctx
.Report
.Error (229, loc
, "Ambiguity between `{0}' and `{1}'",
767 TypeManager
.GetFullNameSignature (non_method
),
768 TypeManager
.CSharpSignature (method
));
773 ctx
.Report
.SymbolRelatedToPreviousError (method
);
774 ctx
.Report
.SymbolRelatedToPreviousError (non_method
);
775 ctx
.Report
.Warning (467, 2, loc
, "Ambiguity between method `{0}' and non-method `{1}'. Using method `{0}'",
776 TypeManager
.CSharpSignature (method
), TypeManager
.GetFullNameSignature (non_method
));
780 return new MethodGroupExpr (methods
, queried_type
, loc
);
783 if (mi
[0] is MethodBase
)
784 return new MethodGroupExpr (mi
, queried_type
, loc
);
786 return ExprClassFromMemberInfo (container_type
, mi
[0], loc
);
789 public const MemberTypes AllMemberTypes
=
790 MemberTypes
.Constructor
|
794 MemberTypes
.NestedType
|
795 MemberTypes
.Property
;
797 public const BindingFlags AllBindingFlags
=
798 BindingFlags
.Public
|
799 BindingFlags
.Static
|
800 BindingFlags
.Instance
;
802 public static Expression
MemberLookup (CompilerContext ctx
, Type container_type
, Type queried_type
,
803 string name
, Location loc
)
805 return MemberLookup (ctx
, container_type
, null, queried_type
, name
,
806 AllMemberTypes
, AllBindingFlags
, loc
);
809 public static Expression
MemberLookup (CompilerContext ctx
, Type container_type
, Type qualifier_type
,
810 Type queried_type
, string name
, Location loc
)
812 return MemberLookup (ctx
, container_type
, qualifier_type
, queried_type
,
813 name
, AllMemberTypes
, AllBindingFlags
, loc
);
816 public static MethodGroupExpr
MethodLookup (CompilerContext ctx
, Type container_type
, Type queried_type
,
817 string name
, Location loc
)
819 return (MethodGroupExpr
)MemberLookup (ctx
, container_type
, null, queried_type
, name
,
820 MemberTypes
.Method
, AllBindingFlags
, loc
);
824 /// This is a wrapper for MemberLookup that is not used to "probe", but
825 /// to find a final definition. If the final definition is not found, we
826 /// look for private members and display a useful debugging message if we
829 protected Expression
MemberLookupFinal (ResolveContext ec
, Type qualifier_type
,
830 Type queried_type
, string name
,
831 MemberTypes mt
, BindingFlags bf
,
836 int errors
= ec
.Report
.Errors
;
837 e
= MemberLookup (ec
.Compiler
, ec
.CurrentType
, qualifier_type
, queried_type
, name
, mt
, bf
, loc
);
839 if (e
!= null || errors
!= ec
.Report
.Errors
)
842 // No errors were reported by MemberLookup, but there was an error.
843 return Error_MemberLookupFailed (ec
, ec
.CurrentType
, qualifier_type
, queried_type
,
847 protected virtual Expression
Error_MemberLookupFailed (ResolveContext ec
, Type container_type
, Type qualifier_type
,
848 Type queried_type
, string name
, string class_name
,
849 MemberTypes mt
, BindingFlags bf
)
851 MemberInfo
[] lookup
= null;
852 if (queried_type
== null) {
853 class_name
= "global::";
855 lookup
= TypeManager
.MemberLookup (queried_type
, null, queried_type
,
856 mt
, (bf
& ~BindingFlags
.Public
) | BindingFlags
.NonPublic
,
859 if (lookup
!= null) {
860 Expression e
= Error_MemberLookupFailed (ec
, queried_type
, lookup
);
863 // FIXME: This is still very wrong, it should be done inside
864 // OverloadResolve to do correct arguments matching.
865 // Requires MemberLookup accessiblity check removal
867 if (e
== null || (mt
& (MemberTypes
.Method
| MemberTypes
.Constructor
)) == 0) {
868 MemberInfo mi
= lookup
[0];
869 ec
.Report
.SymbolRelatedToPreviousError (mi
);
870 if (qualifier_type
!= null && container_type
!= null && qualifier_type
!= container_type
&&
871 TypeManager
.IsNestedFamilyAccessible (container_type
, mi
.DeclaringType
)) {
872 // Although a derived class can access protected members of
873 // its base class it cannot do so through an instance of the
874 // base class (CS1540). If the qualifier_type is a base of the
875 // ec.CurrentType and the lookup succeeds with the latter one,
876 // then we are in this situation.
877 Error_CannotAccessProtected (ec
, loc
, mi
, qualifier_type
, container_type
);
879 ErrorIsInaccesible (loc
, TypeManager
.GetFullNameSignature (mi
), ec
.Report
);
886 lookup
= TypeManager
.MemberLookup (queried_type
, null, queried_type
,
887 AllMemberTypes
, AllBindingFlags
| BindingFlags
.NonPublic
,
891 if (lookup
== null) {
892 if (class_name
!= null) {
893 ec
.Report
.Error (103, loc
, "The name `{0}' does not exist in the current context",
896 Error_TypeDoesNotContainDefinition (ec
, queried_type
, name
);
901 if (TypeManager
.MemberLookup (queried_type
, null, queried_type
,
902 AllMemberTypes
, AllBindingFlags
|
903 BindingFlags
.NonPublic
, name
, null) == null) {
904 if ((lookup
.Length
== 1) && (lookup
[0] is Type
)) {
905 Type t
= (Type
) lookup
[0];
907 ec
.Report
.Error (305, loc
,
908 "Using the generic type `{0}' " +
909 "requires {1} type arguments",
910 TypeManager
.CSharpName (t
),
911 TypeManager
.GetNumberOfTypeArguments (t
).ToString ());
916 return Error_MemberLookupFailed (ec
, queried_type
, lookup
);
919 protected virtual Expression
Error_MemberLookupFailed (ResolveContext ec
, Type type
, MemberInfo
[] members
)
921 for (int i
= 0; i
< members
.Length
; ++i
) {
922 if (!(members
[i
] is MethodBase
))
926 // By default propagate the closest candidates upwards
927 return new MethodGroupExpr (members
, type
, loc
, true);
930 protected virtual void Error_NegativeArrayIndex (ResolveContext ec
, Location loc
)
932 throw new NotImplementedException ();
935 protected void Error_PointerInsideExpressionTree (ResolveContext ec
)
937 ec
.Report
.Error (1944, loc
, "An expression tree cannot contain an unsafe pointer operation");
941 /// Returns an expression that can be used to invoke operator true
942 /// on the expression if it exists.
944 protected static Expression
GetOperatorTrue (ResolveContext ec
, Expression e
, Location loc
)
946 return GetOperatorTrueOrFalse (ec
, e
, true, loc
);
950 /// Returns an expression that can be used to invoke operator false
951 /// on the expression if it exists.
953 static public Expression
GetOperatorFalse (ResolveContext ec
, Expression e
, Location loc
)
955 return GetOperatorTrueOrFalse (ec
, e
, false, loc
);
958 static Expression
GetOperatorTrueOrFalse (ResolveContext ec
, Expression e
, bool is_true
, Location loc
)
960 MethodGroupExpr operator_group
;
961 string mname
= Operator
.GetMetadataName (is_true
? Operator
.OpType
.True
: Operator
.OpType
.False
);
962 operator_group
= MethodLookup (ec
.Compiler
, ec
.CurrentType
, e
.Type
, mname
, loc
) as MethodGroupExpr
;
963 if (operator_group
== null)
966 Arguments arguments
= new Arguments (1);
967 arguments
.Add (new Argument (e
));
968 operator_group
= operator_group
.OverloadResolve (
969 ec
, ref arguments
, false, loc
);
971 if (operator_group
== null)
974 return new UserOperatorCall (operator_group
, arguments
, null, loc
);
977 public virtual string ExprClassName
981 case ExprClass
.Invalid
:
983 case ExprClass
.Value
:
985 case ExprClass
.Variable
:
987 case ExprClass
.Namespace
:
991 case ExprClass
.MethodGroup
:
992 return "method group";
993 case ExprClass
.PropertyAccess
:
994 return "property access";
995 case ExprClass
.EventAccess
:
996 return "event access";
997 case ExprClass
.IndexerAccess
:
998 return "indexer access";
999 case ExprClass
.Nothing
:
1001 case ExprClass
.TypeParameter
:
1002 return "type parameter";
1004 throw new Exception ("Should not happen");
1009 /// Reports that we were expecting `expr' to be of class `expected'
1011 public void Error_UnexpectedKind (Report r
, MemberCore mc
, string expected
, Location loc
)
1013 Error_UnexpectedKind (r
, mc
, expected
, ExprClassName
, loc
);
1016 public void Error_UnexpectedKind (Report r
, MemberCore mc
, string expected
, string was
, Location loc
)
1020 name
= mc
.GetSignatureForError ();
1022 name
= GetSignatureForError ();
1024 r
.Error (118, loc
, "`{0}' is a `{1}' but a `{2}' was expected",
1025 name
, was
, expected
);
1028 public void Error_UnexpectedKind (ResolveContext ec
, ResolveFlags flags
, Location loc
)
1030 string [] valid
= new string [4];
1033 if ((flags
& ResolveFlags
.VariableOrValue
) != 0) {
1034 valid
[count
++] = "variable";
1035 valid
[count
++] = "value";
1038 if ((flags
& ResolveFlags
.Type
) != 0)
1039 valid
[count
++] = "type";
1041 if ((flags
& ResolveFlags
.MethodGroup
) != 0)
1042 valid
[count
++] = "method group";
1045 valid
[count
++] = "unknown";
1047 StringBuilder sb
= new StringBuilder (valid
[0]);
1048 for (int i
= 1; i
< count
- 1; i
++) {
1050 sb
.Append (valid
[i
]);
1053 sb
.Append ("' or `");
1054 sb
.Append (valid
[count
- 1]);
1057 ec
.Report
.Error (119, loc
,
1058 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName
, sb
.ToString ());
1061 public static void UnsafeError (ResolveContext ec
, Location loc
)
1063 UnsafeError (ec
.Report
, loc
);
1066 public static void UnsafeError (Report Report
, Location loc
)
1068 Report
.Error (214, loc
, "Pointers and fixed size buffers may only be used in an unsafe context");
1072 // Load the object from the pointer.
1074 public static void LoadFromPtr (ILGenerator ig
, Type t
)
1076 if (t
== TypeManager
.int32_type
)
1077 ig
.Emit (OpCodes
.Ldind_I4
);
1078 else if (t
== TypeManager
.uint32_type
)
1079 ig
.Emit (OpCodes
.Ldind_U4
);
1080 else if (t
== TypeManager
.short_type
)
1081 ig
.Emit (OpCodes
.Ldind_I2
);
1082 else if (t
== TypeManager
.ushort_type
)
1083 ig
.Emit (OpCodes
.Ldind_U2
);
1084 else if (t
== TypeManager
.char_type
)
1085 ig
.Emit (OpCodes
.Ldind_U2
);
1086 else if (t
== TypeManager
.byte_type
)
1087 ig
.Emit (OpCodes
.Ldind_U1
);
1088 else if (t
== TypeManager
.sbyte_type
)
1089 ig
.Emit (OpCodes
.Ldind_I1
);
1090 else if (t
== TypeManager
.uint64_type
)
1091 ig
.Emit (OpCodes
.Ldind_I8
);
1092 else if (t
== TypeManager
.int64_type
)
1093 ig
.Emit (OpCodes
.Ldind_I8
);
1094 else if (t
== TypeManager
.float_type
)
1095 ig
.Emit (OpCodes
.Ldind_R4
);
1096 else if (t
== TypeManager
.double_type
)
1097 ig
.Emit (OpCodes
.Ldind_R8
);
1098 else if (t
== TypeManager
.bool_type
)
1099 ig
.Emit (OpCodes
.Ldind_I1
);
1100 else if (t
== TypeManager
.intptr_type
)
1101 ig
.Emit (OpCodes
.Ldind_I
);
1102 else if (TypeManager
.IsEnumType (t
)) {
1103 if (t
== TypeManager
.enum_type
)
1104 ig
.Emit (OpCodes
.Ldind_Ref
);
1106 LoadFromPtr (ig
, TypeManager
.GetEnumUnderlyingType (t
));
1107 } else if (TypeManager
.IsStruct (t
) || TypeManager
.IsGenericParameter (t
))
1108 ig
.Emit (OpCodes
.Ldobj
, t
);
1109 else if (t
.IsPointer
)
1110 ig
.Emit (OpCodes
.Ldind_I
);
1112 ig
.Emit (OpCodes
.Ldind_Ref
);
1116 // The stack contains the pointer and the value of type `type'
1118 public static void StoreFromPtr (ILGenerator ig
, Type type
)
1120 if (TypeManager
.IsEnumType (type
))
1121 type
= TypeManager
.GetEnumUnderlyingType (type
);
1122 if (type
== TypeManager
.int32_type
|| type
== TypeManager
.uint32_type
)
1123 ig
.Emit (OpCodes
.Stind_I4
);
1124 else if (type
== TypeManager
.int64_type
|| type
== TypeManager
.uint64_type
)
1125 ig
.Emit (OpCodes
.Stind_I8
);
1126 else if (type
== TypeManager
.char_type
|| type
== TypeManager
.short_type
||
1127 type
== TypeManager
.ushort_type
)
1128 ig
.Emit (OpCodes
.Stind_I2
);
1129 else if (type
== TypeManager
.float_type
)
1130 ig
.Emit (OpCodes
.Stind_R4
);
1131 else if (type
== TypeManager
.double_type
)
1132 ig
.Emit (OpCodes
.Stind_R8
);
1133 else if (type
== TypeManager
.byte_type
|| type
== TypeManager
.sbyte_type
||
1134 type
== TypeManager
.bool_type
)
1135 ig
.Emit (OpCodes
.Stind_I1
);
1136 else if (type
== TypeManager
.intptr_type
)
1137 ig
.Emit (OpCodes
.Stind_I
);
1138 else if (TypeManager
.IsStruct (type
) || TypeManager
.IsGenericParameter (type
))
1139 ig
.Emit (OpCodes
.Stobj
, type
);
1141 ig
.Emit (OpCodes
.Stind_Ref
);
1145 // Returns the size of type `t' if known, otherwise, 0
1147 public static int GetTypeSize (Type t
)
1149 t
= TypeManager
.TypeToCoreType (t
);
1150 if (t
== TypeManager
.int32_type
||
1151 t
== TypeManager
.uint32_type
||
1152 t
== TypeManager
.float_type
)
1154 else if (t
== TypeManager
.int64_type
||
1155 t
== TypeManager
.uint64_type
||
1156 t
== TypeManager
.double_type
)
1158 else if (t
== TypeManager
.byte_type
||
1159 t
== TypeManager
.sbyte_type
||
1160 t
== TypeManager
.bool_type
)
1162 else if (t
== TypeManager
.short_type
||
1163 t
== TypeManager
.char_type
||
1164 t
== TypeManager
.ushort_type
)
1166 else if (t
== TypeManager
.decimal_type
)
1172 protected void Error_CannotCallAbstractBase (ResolveContext ec
, string name
)
1174 ec
.Report
.Error (205, loc
, "Cannot call an abstract base member `{0}'", name
);
1177 protected void Error_CannotModifyIntermediateExpressionValue (ResolveContext ec
)
1179 ec
.Report
.SymbolRelatedToPreviousError (type
);
1180 if (ec
.CurrentInitializerVariable
!= null) {
1181 ec
.Report
.Error (1918, loc
, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
1182 TypeManager
.CSharpName (type
), GetSignatureForError ());
1184 ec
.Report
.Error (1612, loc
, "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
1185 GetSignatureForError ());
1190 // Converts `source' to an int, uint, long or ulong.
1192 protected Expression
ConvertExpressionToArrayIndex (ResolveContext ec
, Expression source
)
1194 if (TypeManager
.IsDynamicType (source
.type
)) {
1195 Arguments args
= new Arguments (1);
1196 args
.Add (new Argument (source
));
1197 return new DynamicConversion (TypeManager
.int32_type
, CSharpBinderFlags
.ConvertArrayIndex
, args
, loc
).Resolve (ec
);
1200 Expression converted
;
1202 using (ec
.Set (ResolveContext
.Options
.CheckedScope
)) {
1203 converted
= Convert
.ImplicitConversion (ec
, source
, TypeManager
.int32_type
, source
.loc
);
1204 if (converted
== null)
1205 converted
= Convert
.ImplicitConversion (ec
, source
, TypeManager
.uint32_type
, source
.loc
);
1206 if (converted
== null)
1207 converted
= Convert
.ImplicitConversion (ec
, source
, TypeManager
.int64_type
, source
.loc
);
1208 if (converted
== null)
1209 converted
= Convert
.ImplicitConversion (ec
, source
, TypeManager
.uint64_type
, source
.loc
);
1211 if (converted
== null) {
1212 source
.Error_ValueCannotBeConverted (ec
, source
.loc
, TypeManager
.int32_type
, false);
1218 // Only positive constants are allowed at compile time
1220 Constant c
= converted
as Constant
;
1221 if (c
!= null && c
.IsNegative
)
1222 Error_NegativeArrayIndex (ec
, source
.loc
);
1224 // No conversion needed to array index
1225 if (converted
.Type
== TypeManager
.int32_type
)
1228 return new ArrayIndexCast (converted
).Resolve (ec
);
1232 // Derived classes implement this method by cloning the fields that
1233 // could become altered during the Resolve stage
1235 // Only expressions that are created for the parser need to implement
1238 protected virtual void CloneTo (CloneContext clonectx
, Expression target
)
1240 throw new NotImplementedException (
1242 "CloneTo not implemented for expression {0}", this.GetType ()));
1246 // Clones an expression created by the parser.
1248 // We only support expressions created by the parser so far, not
1249 // expressions that have been resolved (many more classes would need
1250 // to implement CloneTo).
1252 // This infrastructure is here merely for Lambda expressions which
1253 // compile the same code using different type values for the same
1254 // arguments to find the correct overload
1256 public Expression
Clone (CloneContext clonectx
)
1258 Expression cloned
= (Expression
) MemberwiseClone ();
1259 CloneTo (clonectx
, cloned
);
1265 // Implementation of expression to expression tree conversion
1267 public abstract Expression
CreateExpressionTree (ResolveContext ec
);
1269 protected Expression
CreateExpressionFactoryCall (ResolveContext ec
, string name
, Arguments args
)
1271 return CreateExpressionFactoryCall (ec
, name
, null, args
, loc
);
1274 protected Expression
CreateExpressionFactoryCall (ResolveContext ec
, string name
, TypeArguments typeArguments
, Arguments args
)
1276 return CreateExpressionFactoryCall (ec
, name
, typeArguments
, args
, loc
);
1279 public static Expression
CreateExpressionFactoryCall (ResolveContext ec
, string name
, TypeArguments typeArguments
, Arguments args
, Location loc
)
1281 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec
, loc
), name
, typeArguments
, loc
), args
);
1284 protected static TypeExpr
CreateExpressionTypeExpression (ResolveContext ec
, Location loc
)
1286 TypeExpr texpr
= TypeManager
.expression_type_expr
;
1287 if (texpr
== null) {
1288 Type t
= TypeManager
.CoreLookupType (ec
.Compiler
, "System.Linq.Expressions", "Expression", Kind
.Class
, true);
1292 TypeManager
.expression_type_expr
= texpr
= new TypeExpression (t
, Location
.Null
);
1300 // Implemented by all expressions which support conversion from
1301 // compiler expression to invokable runtime expression. Used by
1302 // dynamic C# binder.
1304 public virtual SLE
.Expression
MakeExpression (BuilderContext ctx
)
1306 throw new NotImplementedException ("MakeExpression for " + GetType ());
1310 public virtual void MutateHoistedGenericType (AnonymousMethodStorey storey
)
1312 // TODO: It should probably be type = storey.MutateType (type);
1317 /// This is just a base class for expressions that can
1318 /// appear on statements (invocations, object creation,
1319 /// assignments, post/pre increment and decrement). The idea
1320 /// being that they would support an extra Emition interface that
1321 /// does not leave a result on the stack.
1323 public abstract class ExpressionStatement
: Expression
{
1325 public virtual ExpressionStatement
ResolveStatement (BlockContext ec
)
1327 Expression e
= Resolve (ec
);
1331 ExpressionStatement es
= e
as ExpressionStatement
;
1333 Error_InvalidExpressionStatement (ec
);
1339 /// Requests the expression to be emitted in a `statement'
1340 /// context. This means that no new value is left on the
1341 /// stack after invoking this method (constrasted with
1342 /// Emit that will always leave a value on the stack).
1344 public abstract void EmitStatement (EmitContext ec
);
1346 public override void EmitSideEffect (EmitContext ec
)
1353 /// This kind of cast is used to encapsulate the child
1354 /// whose type is child.Type into an expression that is
1355 /// reported to return "return_type". This is used to encapsulate
1356 /// expressions which have compatible types, but need to be dealt
1357 /// at higher levels with.
1359 /// For example, a "byte" expression could be encapsulated in one
1360 /// of these as an "unsigned int". The type for the expression
1361 /// would be "unsigned int".
1364 public abstract class TypeCast
: Expression
1366 protected readonly Expression child
;
1368 protected TypeCast (Expression child
, Type return_type
)
1370 eclass
= child
.eclass
;
1371 loc
= child
.Location
;
1376 public override Expression
CreateExpressionTree (ResolveContext ec
)
1378 Arguments args
= new Arguments (2);
1379 args
.Add (new Argument (child
.CreateExpressionTree (ec
)));
1380 args
.Add (new Argument (new TypeOf (new TypeExpression (type
, loc
), loc
)));
1382 if (type
.IsPointer
|| child
.Type
.IsPointer
)
1383 Error_PointerInsideExpressionTree (ec
);
1385 return CreateExpressionFactoryCall (ec
, ec
.HasSet (ResolveContext
.Options
.CheckedScope
) ? "ConvertChecked" : "Convert", args
);
1388 public override Expression
DoResolve (ResolveContext ec
)
1390 // This should never be invoked, we are born in fully
1391 // initialized state.
1396 public override void Emit (EmitContext ec
)
1401 public override bool GetAttributableValue (ResolveContext ec
, Type value_type
, out object value)
1403 return child
.GetAttributableValue (ec
, value_type
, out value);
1407 public override SLE
.Expression
MakeExpression (BuilderContext ctx
)
1409 return ctx
.HasSet (BuilderContext
.Options
.CheckedScope
) ?
1410 SLE
.Expression
.ConvertChecked (child
.MakeExpression (ctx
), type
) :
1411 SLE
.Expression
.Convert (child
.MakeExpression (ctx
), type
);
1415 public override void MutateHoistedGenericType (AnonymousMethodStorey storey
)
1417 type
= storey
.MutateType (type
);
1418 child
.MutateHoistedGenericType (storey
);
1421 protected override void CloneTo (CloneContext clonectx
, Expression t
)
1426 public override bool IsNull
{
1427 get { return child.IsNull; }
1431 public class EmptyCast
: TypeCast
{
1432 EmptyCast (Expression child
, Type target_type
)
1433 : base (child
, target_type
)
1437 public static Expression
Create (Expression child
, Type type
)
1439 Constant c
= child
as Constant
;
1441 return new EmptyConstantCast (c
, type
);
1443 EmptyCast e
= child
as EmptyCast
;
1445 return new EmptyCast (e
.child
, type
);
1447 return new EmptyCast (child
, type
);
1450 public override void EmitBranchable (EmitContext ec
, Label label
, bool on_true
)
1452 child
.EmitBranchable (ec
, label
, on_true
);
1455 public override void EmitSideEffect (EmitContext ec
)
1457 child
.EmitSideEffect (ec
);
1462 // Used for predefined class library user casts (no obsolete check, etc.)
1464 public class OperatorCast
: TypeCast
{
1465 MethodInfo conversion_operator
;
1467 public OperatorCast (Expression child
, Type target_type
)
1468 : this (child
, target_type
, false)
1472 public OperatorCast (Expression child
, Type target_type
, bool find_explicit
)
1473 : base (child
, target_type
)
1475 conversion_operator
= GetConversionOperator (find_explicit
);
1476 if (conversion_operator
== null)
1477 throw new InternalErrorException ("Outer conversion routine is out of sync");
1480 // Returns the implicit operator that converts from
1481 // 'child.Type' to our target type (type)
1482 MethodInfo
GetConversionOperator (bool find_explicit
)
1484 string operator_name
= find_explicit
? "op_Explicit" : "op_Implicit";
1488 mi
= TypeManager
.MemberLookup (child
.Type
, child
.Type
, child
.Type
, MemberTypes
.Method
,
1489 BindingFlags
.Static
| BindingFlags
.Public
, operator_name
, null);
1492 mi
= TypeManager
.MemberLookup (type
, type
, type
, MemberTypes
.Method
,
1493 BindingFlags
.Static
| BindingFlags
.Public
, operator_name
, null);
1496 foreach (MethodInfo oper
in mi
) {
1497 AParametersCollection pd
= TypeManager
.GetParameterData (oper
);
1499 if (pd
.Types
[0] == child
.Type
&& TypeManager
.TypeToCoreType (oper
.ReturnType
) == type
)
1506 public override void Emit (EmitContext ec
)
1509 ec
.ig
.Emit (OpCodes
.Call
, conversion_operator
);
1514 /// This is a numeric cast to a Decimal
1516 public class CastToDecimal
: OperatorCast
{
1517 public CastToDecimal (Expression child
)
1518 : this (child
, false)
1522 public CastToDecimal (Expression child
, bool find_explicit
)
1523 : base (child
, TypeManager
.decimal_type
, find_explicit
)
1529 /// This is an explicit numeric cast from a Decimal
1531 public class CastFromDecimal
: TypeCast
1533 static IDictionary operators
;
1535 public CastFromDecimal (Expression child
, Type return_type
)
1536 : base (child
, return_type
)
1538 if (child
.Type
!= TypeManager
.decimal_type
)
1539 throw new InternalErrorException (
1540 "The expected type is Decimal, instead it is " + child
.Type
.FullName
);
1543 // Returns the explicit operator that converts from an
1544 // express of type System.Decimal to 'type'.
1545 public Expression
Resolve ()
1547 if (operators
== null) {
1548 MemberInfo
[] all_oper
= TypeManager
.MemberLookup (TypeManager
.decimal_type
,
1549 TypeManager
.decimal_type
, TypeManager
.decimal_type
, MemberTypes
.Method
,
1550 BindingFlags
.Static
| BindingFlags
.Public
, "op_Explicit", null);
1552 operators
= new System
.Collections
.Specialized
.HybridDictionary ();
1553 foreach (MethodInfo oper
in all_oper
) {
1554 AParametersCollection pd
= TypeManager
.GetParameterData (oper
);
1555 if (pd
.Types
[0] == TypeManager
.decimal_type
)
1556 operators
.Add (TypeManager
.TypeToCoreType (oper
.ReturnType
), oper
);
1560 return operators
.Contains (type
) ? this : null;
1563 public override void Emit (EmitContext ec
)
1565 ILGenerator ig
= ec
.ig
;
1568 ig
.Emit (OpCodes
.Call
, (MethodInfo
)operators
[type
]);
1574 // Constant specialization of EmptyCast.
1575 // We need to special case this since an empty cast of
1576 // a constant is still a constant.
1578 public class EmptyConstantCast
: Constant
1580 public readonly Constant child
;
1582 public EmptyConstantCast(Constant child
, Type type
)
1583 : base (child
.Location
)
1585 eclass
= child
.eclass
;
1590 public override string AsString ()
1592 return child
.AsString ();
1595 public override object GetValue ()
1597 return child
.GetValue ();
1600 public override Constant
ConvertExplicitly (bool in_checked_context
, Type target_type
)
1602 // FIXME: check that 'type' can be converted to 'target_type' first
1603 return child
.ConvertExplicitly (in_checked_context
, target_type
);
1606 public override Expression
CreateExpressionTree (ResolveContext ec
)
1608 Arguments args
= Arguments
.CreateForExpressionTree (ec
, null,
1609 child
.CreateExpressionTree (ec
),
1610 new TypeOf (new TypeExpression (type
, loc
), loc
));
1613 Error_PointerInsideExpressionTree (ec
);
1615 return CreateExpressionFactoryCall (ec
, "Convert", args
);
1618 public override Constant
Increment ()
1620 return child
.Increment ();
1623 public override bool IsDefaultValue
{
1624 get { return child.IsDefaultValue; }
1627 public override bool IsNegative
{
1628 get { return child.IsNegative; }
1631 public override bool IsNull
{
1632 get { return child.IsNull; }
1635 public override bool IsZeroInteger
{
1636 get { return child.IsZeroInteger; }
1639 public override void Emit (EmitContext ec
)
1644 public override void EmitBranchable (EmitContext ec
, Label label
, bool on_true
)
1646 child
.EmitBranchable (ec
, label
, on_true
);
1648 // Only to make verifier happy
1649 if (TypeManager
.IsGenericParameter (type
) && child
.IsNull
)
1650 ec
.ig
.Emit (OpCodes
.Unbox_Any
, type
);
1653 public override void EmitSideEffect (EmitContext ec
)
1655 child
.EmitSideEffect (ec
);
1658 public override Constant
ConvertImplicitly (Type target_type
)
1660 // FIXME: Do we need to check user conversions?
1661 if (!Convert
.ImplicitStandardConversionExists (this, target_type
))
1663 return child
.ConvertImplicitly (target_type
);
1666 public override void MutateHoistedGenericType (AnonymousMethodStorey storey
)
1668 child
.MutateHoistedGenericType (storey
);
1674 /// This class is used to wrap literals which belong inside Enums
1676 public class EnumConstant
: Constant
{
1677 public Constant Child
;
1679 public EnumConstant (Constant child
, Type enum_type
):
1680 base (child
.Location
)
1682 eclass
= child
.eclass
;
1687 protected EnumConstant ()
1688 : base (Location
.Null
)
1692 public override Expression
DoResolve (ResolveContext ec
)
1694 // This should never be invoked, we are born in fully
1695 // initialized state.
1700 public override void Emit (EmitContext ec
)
1705 public override void EmitBranchable (EmitContext ec
, Label label
, bool on_true
)
1707 Child
.EmitBranchable (ec
, label
, on_true
);
1710 public override void EmitSideEffect (EmitContext ec
)
1712 Child
.EmitSideEffect (ec
);
1715 public override bool GetAttributableValue (ResolveContext ec
, Type value_type
, out object value)
1717 value = GetTypedValue ();
1721 public override string GetSignatureForError()
1723 return TypeManager
.CSharpName (Type
);
1726 public override object GetValue ()
1728 return Child
.GetValue ();
1731 public override object GetTypedValue ()
1733 // FIXME: runtime is not ready to work with just emited enums
1734 if (!RootContext
.StdLib
) {
1735 return Child
.GetValue ();
1739 // Small workaround for big problem
1740 // System.Enum.ToObject cannot be called on dynamic types
1741 // EnumBuilder has to be used, but we cannot use EnumBuilder
1742 // because it does not properly support generics
1744 // This works only sometimes
1746 if (TypeManager
.IsBeingCompiled (type
))
1747 return Child
.GetValue ();
1750 return System
.Enum
.ToObject (type
, Child
.GetValue ());
1753 public override string AsString ()
1755 return Child
.AsString ();
1758 public override Constant
Increment()
1760 return new EnumConstant (Child
.Increment (), type
);
1763 public override bool IsDefaultValue
{
1765 return Child
.IsDefaultValue
;
1769 public override bool IsZeroInteger
{
1770 get { return Child.IsZeroInteger; }
1773 public override bool IsNegative
{
1775 return Child
.IsNegative
;
1779 public override Constant
ConvertExplicitly(bool in_checked_context
, Type target_type
)
1781 if (Child
.Type
== target_type
)
1784 return Child
.ConvertExplicitly (in_checked_context
, target_type
);
1787 public override Constant
ConvertImplicitly (Type type
)
1789 Type this_type
= TypeManager
.DropGenericTypeArguments (Type
);
1790 type
= TypeManager
.DropGenericTypeArguments (type
);
1792 if (this_type
== type
) {
1793 // This is workaround of mono bug. It can be removed when the latest corlib spreads enough
1794 if (TypeManager
.IsEnumType (type
.UnderlyingSystemType
))
1797 Type child_type
= TypeManager
.DropGenericTypeArguments (Child
.Type
);
1798 if (type
.UnderlyingSystemType
!= child_type
)
1799 Child
= Child
.ConvertImplicitly (type
.UnderlyingSystemType
);
1803 if (!Convert
.ImplicitStandardConversionExists (this, type
)){
1807 return Child
.ConvertImplicitly(type
);
1813 /// This kind of cast is used to encapsulate Value Types in objects.
1815 /// The effect of it is to box the value type emitted by the previous
1818 public class BoxedCast
: TypeCast
{
1820 public BoxedCast (Expression expr
, Type target_type
)
1821 : base (expr
, target_type
)
1823 eclass
= ExprClass
.Value
;
1826 public override Expression
DoResolve (ResolveContext ec
)
1828 // This should never be invoked, we are born in fully
1829 // initialized state.
1834 public override void Emit (EmitContext ec
)
1838 ec
.ig
.Emit (OpCodes
.Box
, child
.Type
);
1841 public override void EmitSideEffect (EmitContext ec
)
1843 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1844 // so, we need to emit the box+pop instructions in most cases
1845 if (TypeManager
.IsStruct (child
.Type
) &&
1846 (type
== TypeManager
.object_type
|| type
== TypeManager
.value_type
))
1847 child
.EmitSideEffect (ec
);
1849 base.EmitSideEffect (ec
);
1853 public class UnboxCast
: TypeCast
{
1854 public UnboxCast (Expression expr
, Type return_type
)
1855 : base (expr
, return_type
)
1859 public override Expression
DoResolve (ResolveContext ec
)
1861 // This should never be invoked, we are born in fully
1862 // initialized state.
1867 public override Expression
DoResolveLValue (ResolveContext ec
, Expression right_side
)
1869 if (right_side
== EmptyExpression
.LValueMemberAccess
|| right_side
== EmptyExpression
.LValueMemberOutAccess
)
1870 ec
.Report
.Error (445, loc
, "Cannot modify the result of an unboxing conversion");
1871 return base.DoResolveLValue (ec
, right_side
);
1874 public override void Emit (EmitContext ec
)
1878 ILGenerator ig
= ec
.ig
;
1879 ig
.Emit (OpCodes
.Unbox_Any
, type
);
1882 public override void MutateHoistedGenericType (AnonymousMethodStorey storey
)
1884 type
= storey
.MutateType (type
);
1885 base.MutateHoistedGenericType (storey
);
1890 /// This is used to perform explicit numeric conversions.
1892 /// Explicit numeric conversions might trigger exceptions in a checked
1893 /// context, so they should generate the conv.ovf opcodes instead of
1896 public class ConvCast
: TypeCast
{
1897 public enum Mode
: byte {
1898 I1_U1
, I1_U2
, I1_U4
, I1_U8
, I1_CH
,
1900 I2_I1
, I2_U1
, I2_U2
, I2_U4
, I2_U8
, I2_CH
,
1901 U2_I1
, U2_U1
, U2_I2
, U2_CH
,
1902 I4_I1
, I4_U1
, I4_I2
, I4_U2
, I4_U4
, I4_U8
, I4_CH
,
1903 U4_I1
, U4_U1
, U4_I2
, U4_U2
, U4_I4
, U4_CH
,
1904 I8_I1
, I8_U1
, I8_I2
, I8_U2
, I8_I4
, I8_U4
, I8_U8
, I8_CH
, I8_I
,
1905 U8_I1
, U8_U1
, U8_I2
, U8_U2
, U8_I4
, U8_U4
, U8_I8
, U8_CH
, U8_I
,
1906 CH_I1
, CH_U1
, CH_I2
,
1907 R4_I1
, R4_U1
, R4_I2
, R4_U2
, R4_I4
, R4_U4
, R4_I8
, R4_U8
, R4_CH
,
1908 R8_I1
, R8_U1
, R8_I2
, R8_U2
, R8_I4
, R8_U4
, R8_I8
, R8_U8
, R8_CH
, R8_R4
,
1914 public ConvCast (Expression child
, Type return_type
, Mode m
)
1915 : base (child
, return_type
)
1920 public override Expression
DoResolve (ResolveContext ec
)
1922 // This should never be invoked, we are born in fully
1923 // initialized state.
1928 public override string ToString ()
1930 return String
.Format ("ConvCast ({0}, {1})", mode
, child
);
1933 public override void Emit (EmitContext ec
)
1935 ILGenerator ig
= ec
.ig
;
1939 if (ec
.HasSet (EmitContext
.Options
.CheckedScope
)) {
1941 case Mode
.I1_U1
: ig
.Emit (OpCodes
.Conv_Ovf_U1
); break;
1942 case Mode
.I1_U2
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
1943 case Mode
.I1_U4
: ig
.Emit (OpCodes
.Conv_Ovf_U4
); break;
1944 case Mode
.I1_U8
: ig
.Emit (OpCodes
.Conv_Ovf_U8
); break;
1945 case Mode
.I1_CH
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
1947 case Mode
.U1_I1
: ig
.Emit (OpCodes
.Conv_Ovf_I1_Un
); break;
1948 case Mode
.U1_CH
: /* nothing */ break;
1950 case Mode
.I2_I1
: ig
.Emit (OpCodes
.Conv_Ovf_I1
); break;
1951 case Mode
.I2_U1
: ig
.Emit (OpCodes
.Conv_Ovf_U1
); break;
1952 case Mode
.I2_U2
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
1953 case Mode
.I2_U4
: ig
.Emit (OpCodes
.Conv_Ovf_U4
); break;
1954 case Mode
.I2_U8
: ig
.Emit (OpCodes
.Conv_Ovf_U8
); break;
1955 case Mode
.I2_CH
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
1957 case Mode
.U2_I1
: ig
.Emit (OpCodes
.Conv_Ovf_I1_Un
); break;
1958 case Mode
.U2_U1
: ig
.Emit (OpCodes
.Conv_Ovf_U1_Un
); break;
1959 case Mode
.U2_I2
: ig
.Emit (OpCodes
.Conv_Ovf_I2_Un
); break;
1960 case Mode
.U2_CH
: /* nothing */ break;
1962 case Mode
.I4_I1
: ig
.Emit (OpCodes
.Conv_Ovf_I1
); break;
1963 case Mode
.I4_U1
: ig
.Emit (OpCodes
.Conv_Ovf_U1
); break;
1964 case Mode
.I4_I2
: ig
.Emit (OpCodes
.Conv_Ovf_I2
); break;
1965 case Mode
.I4_U4
: ig
.Emit (OpCodes
.Conv_Ovf_U4
); break;
1966 case Mode
.I4_U2
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
1967 case Mode
.I4_U8
: ig
.Emit (OpCodes
.Conv_Ovf_U8
); break;
1968 case Mode
.I4_CH
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
1970 case Mode
.U4_I1
: ig
.Emit (OpCodes
.Conv_Ovf_I1_Un
); break;
1971 case Mode
.U4_U1
: ig
.Emit (OpCodes
.Conv_Ovf_U1_Un
); break;
1972 case Mode
.U4_I2
: ig
.Emit (OpCodes
.Conv_Ovf_I2_Un
); break;
1973 case Mode
.U4_U2
: ig
.Emit (OpCodes
.Conv_Ovf_U2_Un
); break;
1974 case Mode
.U4_I4
: ig
.Emit (OpCodes
.Conv_Ovf_I4_Un
); break;
1975 case Mode
.U4_CH
: ig
.Emit (OpCodes
.Conv_Ovf_U2_Un
); break;
1977 case Mode
.I8_I1
: ig
.Emit (OpCodes
.Conv_Ovf_I1
); break;
1978 case Mode
.I8_U1
: ig
.Emit (OpCodes
.Conv_Ovf_U1
); break;
1979 case Mode
.I8_I2
: ig
.Emit (OpCodes
.Conv_Ovf_I2
); break;
1980 case Mode
.I8_U2
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
1981 case Mode
.I8_I4
: ig
.Emit (OpCodes
.Conv_Ovf_I4
); break;
1982 case Mode
.I8_U4
: ig
.Emit (OpCodes
.Conv_Ovf_U4
); break;
1983 case Mode
.I8_U8
: ig
.Emit (OpCodes
.Conv_Ovf_U8
); break;
1984 case Mode
.I8_CH
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
1985 case Mode
.I8_I
: ig
.Emit (OpCodes
.Conv_Ovf_U
); break;
1987 case Mode
.U8_I1
: ig
.Emit (OpCodes
.Conv_Ovf_I1_Un
); break;
1988 case Mode
.U8_U1
: ig
.Emit (OpCodes
.Conv_Ovf_U1_Un
); break;
1989 case Mode
.U8_I2
: ig
.Emit (OpCodes
.Conv_Ovf_I2_Un
); break;
1990 case Mode
.U8_U2
: ig
.Emit (OpCodes
.Conv_Ovf_U2_Un
); break;
1991 case Mode
.U8_I4
: ig
.Emit (OpCodes
.Conv_Ovf_I4_Un
); break;
1992 case Mode
.U8_U4
: ig
.Emit (OpCodes
.Conv_Ovf_U4_Un
); break;
1993 case Mode
.U8_I8
: ig
.Emit (OpCodes
.Conv_Ovf_I8_Un
); break;
1994 case Mode
.U8_CH
: ig
.Emit (OpCodes
.Conv_Ovf_U2_Un
); break;
1995 case Mode
.U8_I
: ig
.Emit (OpCodes
.Conv_Ovf_U_Un
); break;
1997 case Mode
.CH_I1
: ig
.Emit (OpCodes
.Conv_Ovf_I1_Un
); break;
1998 case Mode
.CH_U1
: ig
.Emit (OpCodes
.Conv_Ovf_U1_Un
); break;
1999 case Mode
.CH_I2
: ig
.Emit (OpCodes
.Conv_Ovf_I2_Un
); break;
2001 case Mode
.R4_I1
: ig
.Emit (OpCodes
.Conv_Ovf_I1
); break;
2002 case Mode
.R4_U1
: ig
.Emit (OpCodes
.Conv_Ovf_U1
); break;
2003 case Mode
.R4_I2
: ig
.Emit (OpCodes
.Conv_Ovf_I2
); break;
2004 case Mode
.R4_U2
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
2005 case Mode
.R4_I4
: ig
.Emit (OpCodes
.Conv_Ovf_I4
); break;
2006 case Mode
.R4_U4
: ig
.Emit (OpCodes
.Conv_Ovf_U4
); break;
2007 case Mode
.R4_I8
: ig
.Emit (OpCodes
.Conv_Ovf_I8
); break;
2008 case Mode
.R4_U8
: ig
.Emit (OpCodes
.Conv_Ovf_U8
); break;
2009 case Mode
.R4_CH
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
2011 case Mode
.R8_I1
: ig
.Emit (OpCodes
.Conv_Ovf_I1
); break;
2012 case Mode
.R8_U1
: ig
.Emit (OpCodes
.Conv_Ovf_U1
); break;
2013 case Mode
.R8_I2
: ig
.Emit (OpCodes
.Conv_Ovf_I2
); break;
2014 case Mode
.R8_U2
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
2015 case Mode
.R8_I4
: ig
.Emit (OpCodes
.Conv_Ovf_I4
); break;
2016 case Mode
.R8_U4
: ig
.Emit (OpCodes
.Conv_Ovf_U4
); break;
2017 case Mode
.R8_I8
: ig
.Emit (OpCodes
.Conv_Ovf_I8
); break;
2018 case Mode
.R8_U8
: ig
.Emit (OpCodes
.Conv_Ovf_U8
); break;
2019 case Mode
.R8_CH
: ig
.Emit (OpCodes
.Conv_Ovf_U2
); break;
2020 case Mode
.R8_R4
: ig
.Emit (OpCodes
.Conv_R4
); break;
2022 case Mode
.I_I8
: ig
.Emit (OpCodes
.Conv_Ovf_I8_Un
); break;
2026 case Mode
.I1_U1
: ig
.Emit (OpCodes
.Conv_U1
); break;
2027 case Mode
.I1_U2
: ig
.Emit (OpCodes
.Conv_U2
); break;
2028 case Mode
.I1_U4
: ig
.Emit (OpCodes
.Conv_U4
); break;
2029 case Mode
.I1_U8
: ig
.Emit (OpCodes
.Conv_I8
); break;
2030 case Mode
.I1_CH
: ig
.Emit (OpCodes
.Conv_U2
); break;
2032 case Mode
.U1_I1
: ig
.Emit (OpCodes
.Conv_I1
); break;
2033 case Mode
.U1_CH
: ig
.Emit (OpCodes
.Conv_U2
); break;
2035 case Mode
.I2_I1
: ig
.Emit (OpCodes
.Conv_I1
); break;
2036 case Mode
.I2_U1
: ig
.Emit (OpCodes
.Conv_U1
); break;
2037 case Mode
.I2_U2
: ig
.Emit (OpCodes
.Conv_U2
); break;
2038 case Mode
.I2_U4
: ig
.Emit (OpCodes
.Conv_U4
); break;
2039 case Mode
.I2_U8
: ig
.Emit (OpCodes
.Conv_I8
); break;
2040 case Mode
.I2_CH
: ig
.Emit (OpCodes
.Conv_U2
); break;
2042 case Mode
.U2_I1
: ig
.Emit (OpCodes
.Conv_I1
); break;
2043 case Mode
.U2_U1
: ig
.Emit (OpCodes
.Conv_U1
); break;
2044 case Mode
.U2_I2
: ig
.Emit (OpCodes
.Conv_I2
); break;
2045 case Mode
.U2_CH
: /* nothing */ break;
2047 case Mode
.I4_I1
: ig
.Emit (OpCodes
.Conv_I1
); break;
2048 case Mode
.I4_U1
: ig
.Emit (OpCodes
.Conv_U1
); break;
2049 case Mode
.I4_I2
: ig
.Emit (OpCodes
.Conv_I2
); break;
2050 case Mode
.I4_U4
: /* nothing */ break;
2051 case Mode
.I4_U2
: ig
.Emit (OpCodes
.Conv_U2
); break;
2052 case Mode
.I4_U8
: ig
.Emit (OpCodes
.Conv_I8
); break;
2053 case Mode
.I4_CH
: ig
.Emit (OpCodes
.Conv_U2
); break;
2055 case Mode
.U4_I1
: ig
.Emit (OpCodes
.Conv_I1
); break;
2056 case Mode
.U4_U1
: ig
.Emit (OpCodes
.Conv_U1
); break;
2057 case Mode
.U4_I2
: ig
.Emit (OpCodes
.Conv_I2
); break;
2058 case Mode
.U4_U2
: ig
.Emit (OpCodes
.Conv_U2
); break;
2059 case Mode
.U4_I4
: /* nothing */ break;
2060 case Mode
.U4_CH
: ig
.Emit (OpCodes
.Conv_U2
); break;
2062 case Mode
.I8_I1
: ig
.Emit (OpCodes
.Conv_I1
); break;
2063 case Mode
.I8_U1
: ig
.Emit (OpCodes
.Conv_U1
); break;
2064 case Mode
.I8_I2
: ig
.Emit (OpCodes
.Conv_I2
); break;
2065 case Mode
.I8_U2
: ig
.Emit (OpCodes
.Conv_U2
); break;
2066 case Mode
.I8_I4
: ig
.Emit (OpCodes
.Conv_I4
); break;
2067 case Mode
.I8_U4
: ig
.Emit (OpCodes
.Conv_U4
); break;
2068 case Mode
.I8_U8
: /* nothing */ break;
2069 case Mode
.I8_CH
: ig
.Emit (OpCodes
.Conv_U2
); break;
2070 case Mode
.I8_I
: ig
.Emit (OpCodes
.Conv_U
); break;
2072 case Mode
.U8_I1
: ig
.Emit (OpCodes
.Conv_I1
); break;
2073 case Mode
.U8_U1
: ig
.Emit (OpCodes
.Conv_U1
); break;
2074 case Mode
.U8_I2
: ig
.Emit (OpCodes
.Conv_I2
); break;
2075 case Mode
.U8_U2
: ig
.Emit (OpCodes
.Conv_U2
); break;
2076 case Mode
.U8_I4
: ig
.Emit (OpCodes
.Conv_I4
); break;
2077 case Mode
.U8_U4
: ig
.Emit (OpCodes
.Conv_U4
); break;
2078 case Mode
.U8_I8
: /* nothing */ break;
2079 case Mode
.U8_CH
: ig
.Emit (OpCodes
.Conv_U2
); break;
2080 case Mode
.U8_I
: ig
.Emit (OpCodes
.Conv_U
); break;
2082 case Mode
.CH_I1
: ig
.Emit (OpCodes
.Conv_I1
); break;
2083 case Mode
.CH_U1
: ig
.Emit (OpCodes
.Conv_U1
); break;
2084 case Mode
.CH_I2
: ig
.Emit (OpCodes
.Conv_I2
); break;
2086 case Mode
.R4_I1
: ig
.Emit (OpCodes
.Conv_I1
); break;
2087 case Mode
.R4_U1
: ig
.Emit (OpCodes
.Conv_U1
); break;
2088 case Mode
.R4_I2
: ig
.Emit (OpCodes
.Conv_I2
); break;
2089 case Mode
.R4_U2
: ig
.Emit (OpCodes
.Conv_U2
); break;
2090 case Mode
.R4_I4
: ig
.Emit (OpCodes
.Conv_I4
); break;
2091 case Mode
.R4_U4
: ig
.Emit (OpCodes
.Conv_U4
); break;
2092 case Mode
.R4_I8
: ig
.Emit (OpCodes
.Conv_I8
); break;
2093 case Mode
.R4_U8
: ig
.Emit (OpCodes
.Conv_U8
); break;
2094 case Mode
.R4_CH
: ig
.Emit (OpCodes
.Conv_U2
); break;
2096 case Mode
.R8_I1
: ig
.Emit (OpCodes
.Conv_I1
); break;
2097 case Mode
.R8_U1
: ig
.Emit (OpCodes
.Conv_U1
); break;
2098 case Mode
.R8_I2
: ig
.Emit (OpCodes
.Conv_I2
); break;
2099 case Mode
.R8_U2
: ig
.Emit (OpCodes
.Conv_U2
); break;
2100 case Mode
.R8_I4
: ig
.Emit (OpCodes
.Conv_I4
); break;
2101 case Mode
.R8_U4
: ig
.Emit (OpCodes
.Conv_U4
); break;
2102 case Mode
.R8_I8
: ig
.Emit (OpCodes
.Conv_I8
); break;
2103 case Mode
.R8_U8
: ig
.Emit (OpCodes
.Conv_U8
); break;
2104 case Mode
.R8_CH
: ig
.Emit (OpCodes
.Conv_U2
); break;
2105 case Mode
.R8_R4
: ig
.Emit (OpCodes
.Conv_R4
); break;
2107 case Mode
.I_I8
: ig
.Emit (OpCodes
.Conv_U8
); break;
2113 public class OpcodeCast
: TypeCast
{
2116 public OpcodeCast (Expression child
, Type return_type
, OpCode op
)
2117 : base (child
, return_type
)
2122 public override Expression
DoResolve (ResolveContext ec
)
2124 // This should never be invoked, we are born in fully
2125 // initialized state.
2130 public override void Emit (EmitContext ec
)
2136 public Type UnderlyingType
{
2137 get { return child.Type; }
2142 /// This kind of cast is used to encapsulate a child and cast it
2143 /// to the class requested
2145 public sealed class ClassCast
: TypeCast
{
2146 readonly bool forced
;
2148 public ClassCast (Expression child
, Type return_type
)
2149 : base (child
, return_type
)
2153 public ClassCast (Expression child
, Type return_type
, bool forced
)
2154 : base (child
, return_type
)
2156 this.forced
= forced
;
2159 public override void Emit (EmitContext ec
)
2163 bool gen
= TypeManager
.IsGenericParameter (child
.Type
);
2165 ec
.ig
.Emit (OpCodes
.Box
, child
.Type
);
2167 if (type
.IsGenericParameter
) {
2168 ec
.ig
.Emit (OpCodes
.Unbox_Any
, type
);
2175 ec
.ig
.Emit (OpCodes
.Castclass
, type
);
2180 // Created during resolving pahse when an expression is wrapped or constantified
2181 // and original expression can be used later (e.g. for expression trees)
2183 public class ReducedExpression
: Expression
2185 sealed class ReducedConstantExpression
: EmptyConstantCast
2187 readonly Expression orig_expr
;
2189 public ReducedConstantExpression (Constant expr
, Expression orig_expr
)
2190 : base (expr
, expr
.Type
)
2192 this.orig_expr
= orig_expr
;
2195 public override Constant
ConvertImplicitly (Type target_type
)
2197 Constant c
= base.ConvertImplicitly (target_type
);
2199 c
= new ReducedConstantExpression (c
, orig_expr
);
2203 public override Expression
CreateExpressionTree (ResolveContext ec
)
2205 return orig_expr
.CreateExpressionTree (ec
);
2208 public override bool GetAttributableValue (ResolveContext ec
, Type value_type
, out object value)
2211 // Even if resolved result is a constant original expression was not
2212 // and attribute accepts constants only
2214 Attribute
.Error_AttributeArgumentNotValid (ec
, orig_expr
.Location
);
2219 public override Constant
ConvertExplicitly (bool in_checked_context
, Type target_type
)
2221 Constant c
= base.ConvertExplicitly (in_checked_context
, target_type
);
2223 c
= new ReducedConstantExpression (c
, orig_expr
);
2228 sealed class ReducedExpressionStatement
: ExpressionStatement
2230 readonly Expression orig_expr
;
2231 readonly ExpressionStatement stm
;
2233 public ReducedExpressionStatement (ExpressionStatement stm
, Expression orig
)
2235 this.orig_expr
= orig
;
2237 this.loc
= orig
.Location
;
2240 public override Expression
CreateExpressionTree (ResolveContext ec
)
2242 return orig_expr
.CreateExpressionTree (ec
);
2245 public override Expression
DoResolve (ResolveContext ec
)
2247 eclass
= stm
.eclass
;
2252 public override void Emit (EmitContext ec
)
2257 public override void EmitStatement (EmitContext ec
)
2259 stm
.EmitStatement (ec
);
2262 public override void MutateHoistedGenericType (AnonymousMethodStorey storey
)
2264 stm
.MutateHoistedGenericType (storey
);
2268 readonly Expression expr
, orig_expr
;
2270 private ReducedExpression (Expression expr
, Expression orig_expr
)
2273 this.orig_expr
= orig_expr
;
2274 this.loc
= orig_expr
.Location
;
2277 public static Constant
Create (Constant expr
, Expression original_expr
)
2279 return new ReducedConstantExpression (expr
, original_expr
);
2282 public static ExpressionStatement
Create (ExpressionStatement s
, Expression orig
)
2284 return new ReducedExpressionStatement (s
, orig
);
2287 public static Expression
Create (Expression expr
, Expression original_expr
)
2289 Constant c
= expr
as Constant
;
2291 return Create (c
, original_expr
);
2293 ExpressionStatement s
= expr
as ExpressionStatement
;
2295 return Create (s
, original_expr
);
2297 return new ReducedExpression (expr
, original_expr
);
2300 public override Expression
CreateExpressionTree (ResolveContext ec
)
2302 return orig_expr
.CreateExpressionTree (ec
);
2305 public override Expression
DoResolve (ResolveContext ec
)
2307 eclass
= expr
.eclass
;
2312 public override void Emit (EmitContext ec
)
2317 public override void EmitBranchable (EmitContext ec
, Label target
, bool on_true
)
2319 expr
.EmitBranchable (ec
, target
, on_true
);
2323 public override SLE
.Expression
MakeExpression (BuilderContext ctx
)
2325 return orig_expr
.MakeExpression (ctx
);
2329 public override void MutateHoistedGenericType (AnonymousMethodStorey storey
)
2331 expr
.MutateHoistedGenericType (storey
);
2336 // Standard composite pattern
2338 public abstract class CompositeExpression
: Expression
2342 protected CompositeExpression (Expression expr
)
2345 this.loc
= expr
.Location
;
2348 public override Expression
CreateExpressionTree (ResolveContext ec
)
2350 return expr
.CreateExpressionTree (ec
);
2353 public Expression Child
{
2354 get { return expr; }
2357 public override Expression
DoResolve (ResolveContext ec
)
2359 expr
= expr
.Resolve (ec
);
2362 eclass
= expr
.eclass
;
2368 public override void Emit (EmitContext ec
)
2373 public override bool IsNull
{
2374 get { return expr.IsNull; }
2379 // Base of expressions used only to narrow resolve flow
2381 public abstract class ShimExpression
: Expression
2383 protected Expression expr
;
2385 protected ShimExpression (Expression expr
)
2390 protected override void CloneTo (CloneContext clonectx
, Expression t
)
2395 ShimExpression target
= (ShimExpression
) t
;
2396 target
.expr
= expr
.Clone (clonectx
);
2399 public override Expression
CreateExpressionTree (ResolveContext ec
)
2401 throw new NotSupportedException ("ET");
2404 public override void Emit (EmitContext ec
)
2406 throw new InternalErrorException ("Missing Resolve call");
2409 public Expression Expr
{
2410 get { return expr; }
2413 public override void MutateHoistedGenericType (AnonymousMethodStorey storey
)
2415 throw new InternalErrorException ("Missing Resolve call");
2420 // Unresolved type name expressions
2422 public abstract class ATypeNameExpression
: FullNamedExpression
2425 protected TypeArguments targs
;
2427 protected ATypeNameExpression (string name
, Location l
)
2433 protected ATypeNameExpression (string name
, TypeArguments targs
, Location l
)
2440 public bool HasTypeArguments
{
2442 return targs
!= null;
2446 public override bool Equals (object obj
)
2448 ATypeNameExpression atne
= obj
as ATypeNameExpression
;
2449 return atne
!= null && atne
.Name
== Name
&&
2450 (targs
== null || targs
.Equals (atne
.targs
));
2453 public override int GetHashCode ()
2455 return Name
.GetHashCode ();
2458 public override string GetSignatureForError ()
2460 if (targs
!= null) {
2461 return TypeManager
.RemoveGenericArity (Name
) + "<" +
2462 targs
.GetSignatureForError () + ">";
2468 public string Name
{
2477 public TypeArguments TypeArguments
{
2485 /// SimpleName expressions are formed of a single word and only happen at the beginning
2486 /// of a dotted-name.
2488 public class SimpleName
: ATypeNameExpression
{
2491 public SimpleName (string name
, Location l
)
2496 public SimpleName (string name
, TypeArguments args
, Location l
)
2497 : base (name
, args
, l
)
2501 public SimpleName (string name
, TypeParameter
[] type_params
, Location l
)
2504 targs
= new TypeArguments ();
2505 foreach (TypeParameter type_param
in type_params
)
2506 targs
.Add (new TypeParameterExpr (type_param
, l
));
2509 public static string RemoveGenericArity (string name
)
2512 StringBuilder sb
= null;
2514 int pos
= name
.IndexOf ('`', start
);
2519 sb
.Append (name
.Substring (start
));
2524 sb
= new StringBuilder ();
2525 sb
.Append (name
.Substring (start
, pos
-start
));
2528 while ((pos
< name
.Length
) && Char
.IsNumber (name
[pos
]))
2532 } while (start
< name
.Length
);
2534 return sb
.ToString ();
2537 public SimpleName
GetMethodGroup ()
2539 return new SimpleName (RemoveGenericArity (Name
), targs
, loc
);
2542 public static void Error_ObjectRefRequired (ResolveContext ec
, Location l
, string name
)
2544 if (ec
.HasSet (ResolveContext
.Options
.FieldInitializerScope
))
2545 ec
.Report
.Error (236, l
,
2546 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2549 ec
.Report
.Error (120, l
,
2550 "An object reference is required to access non-static member `{0}'",
2554 public bool IdenticalNameAndTypeName (IMemberContext mc
, Expression resolved_to
, Location loc
)
2556 return resolved_to
!= null && resolved_to
.Type
!= null &&
2557 resolved_to
.Type
.Name
== Name
&&
2558 (mc
.LookupNamespaceOrType (Name
, loc
, /* ignore_cs0104 = */ true) != null);
2561 public override Expression
DoResolve (ResolveContext ec
)
2563 return SimpleNameResolve (ec
, null, false);
2566 public override Expression
DoResolveLValue (ResolveContext ec
, Expression right_side
)
2568 return SimpleNameResolve (ec
, right_side
, false);
2572 public Expression
DoResolve (ResolveContext ec
, bool intermediate
)
2574 return SimpleNameResolve (ec
, null, intermediate
);
2577 static bool IsNestedChild (Type t
, Type parent
)
2579 while (parent
!= null) {
2580 if (TypeManager
.IsNestedChildOf (t
, TypeManager
.DropGenericTypeArguments (parent
)))
2583 parent
= parent
.BaseType
;
2589 FullNamedExpression
ResolveNested (Type t
)
2591 if (!TypeManager
.IsGenericTypeDefinition (t
) && !TypeManager
.IsGenericType (t
))
2595 while (ds
!= null && !IsNestedChild (t
, ds
))
2596 ds
= ds
.DeclaringType
;
2601 Type
[] gen_params
= TypeManager
.GetTypeArguments (t
);
2603 int arg_count
= targs
!= null ? targs
.Count
: 0;
2605 for (; (ds
!= null) && TypeManager
.IsGenericType (ds
); ds
= ds
.DeclaringType
) {
2606 Type
[] gargs
= TypeManager
.GetTypeArguments (ds
);
2607 if (arg_count
+ gargs
.Length
== gen_params
.Length
) {
2608 TypeArguments new_args
= new TypeArguments ();
2609 foreach (Type param
in gargs
)
2610 new_args
.Add (new TypeExpression (param
, loc
));
2613 new_args
.Add (targs
);
2615 return new GenericTypeExpr (t
, new_args
, loc
);
2622 public override FullNamedExpression
ResolveAsTypeStep (IMemberContext ec
, bool silent
)
2624 int errors
= ec
.Compiler
.Report
.Errors
;
2625 FullNamedExpression fne
= ec
.LookupNamespaceOrType (Name
, loc
, /*ignore_cs0104=*/ false);
2628 if (fne
.Type
== null)
2631 FullNamedExpression nested
= ResolveNested (fne
.Type
);
2633 return nested
.ResolveAsTypeStep (ec
, false);
2635 if (targs
!= null) {
2636 if (TypeManager
.IsGenericType (fne
.Type
)) {
2637 GenericTypeExpr ct
= new GenericTypeExpr (fne
.Type
, targs
, loc
);
2638 return ct
.ResolveAsTypeStep (ec
, false);
2641 fne
.Error_TypeArgumentsCannotBeUsed (ec
.Compiler
.Report
, loc
);
2647 if (!HasTypeArguments
&& Name
== "dynamic" &&
2648 RootContext
.Version
> LanguageVersion
.V_3
&&
2649 RootContext
.MetadataCompatibilityVersion
> MetadataVersion
.v2
) {
2651 if (!PredefinedAttributes
.Get
.Dynamic
.IsDefined
) {
2652 ec
.Compiler
.Report
.Error (1980, Location
,
2653 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2654 PredefinedAttributes
.Get
.Dynamic
.GetSignatureForError ());
2657 return new DynamicTypeExpr (loc
);
2660 if (silent
|| errors
!= ec
.Compiler
.Report
.Errors
)
2663 Error_TypeOrNamespaceNotFound (ec
);
2667 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ec
)
2669 if (ec
.CurrentType
!= null) {
2670 if (ec
.CurrentTypeDefinition
!= null) {
2671 MemberCore mc
= ec
.CurrentTypeDefinition
.GetDefinition (Name
);
2673 Error_UnexpectedKind (ec
.Compiler
.Report
, mc
, "type", GetMemberType (mc
), loc
);
2678 string ns
= ec
.CurrentType
.Namespace
;
2679 string fullname
= (ns
.Length
> 0) ? ns
+ "." + Name
: Name
;
2680 foreach (Assembly a
in GlobalRootNamespace
.Instance
.Assemblies
) {
2681 Type type
= a
.GetType (fullname
);
2683 ec
.Compiler
.Report
.SymbolRelatedToPreviousError (type
);
2684 Expression
.ErrorIsInaccesible (loc
, TypeManager
.CSharpName (type
), ec
.Compiler
.Report
);
2689 if (ec
.CurrentTypeDefinition
!= null) {
2690 Type t
= ec
.CurrentTypeDefinition
.LookupAnyGeneric (Name
);
2692 Namespace
.Error_InvalidNumberOfTypeArguments (t
, loc
);
2698 if (targs
!= null) {
2699 FullNamedExpression retval
= ec
.LookupNamespaceOrType (SimpleName
.RemoveGenericArity (Name
), loc
, true);
2700 if (retval
!= null) {
2701 retval
.Error_TypeArgumentsCannotBeUsed (ec
.Compiler
.Report
, loc
);
2706 NamespaceEntry
.Error_NamespaceNotFound (loc
, Name
, ec
.Compiler
.Report
);
2709 // TODO: I am still not convinced about this. If someone else will need it
2710 // implement this as virtual property in MemberCore hierarchy
2711 public static string GetMemberType (MemberCore mc
)
2717 if (mc
is FieldBase
)
2719 if (mc
is MethodCore
)
2721 if (mc
is EnumMember
)
2729 Expression
SimpleNameResolve (ResolveContext ec
, Expression right_side
, bool intermediate
)
2735 Expression e
= DoSimpleNameResolve (ec
, right_side
, intermediate
);
2741 if (ec
.CurrentBlock
== null || ec
.CurrentBlock
.CheckInvariantMeaningInBlock (Name
, e
, Location
))
2748 /// 7.5.2: Simple Names.
2750 /// Local Variables and Parameters are handled at
2751 /// parse time, so they never occur as SimpleNames.
2753 /// The `intermediate' flag is used by MemberAccess only
2754 /// and it is used to inform us that it is ok for us to
2755 /// avoid the static check, because MemberAccess might end
2756 /// up resolving the Name as a Type name and the access as
2757 /// a static type access.
2759 /// ie: Type Type; .... { Type.GetType (""); }
2761 /// Type is both an instance variable and a Type; Type.GetType
2762 /// is the static method not an instance method of type.
2764 Expression
DoSimpleNameResolve (ResolveContext ec
, Expression right_side
, bool intermediate
)
2766 Expression e
= null;
2769 // Stage 1: Performed by the parser (binding to locals or parameters).
2771 Block current_block
= ec
.CurrentBlock
;
2772 if (current_block
!= null){
2773 LocalInfo vi
= current_block
.GetLocalInfo (Name
);
2775 e
= new LocalVariableReference (ec
.CurrentBlock
, Name
, loc
);
2777 if (right_side
!= null) {
2778 e
= e
.ResolveLValue (ec
, right_side
);
2780 ResolveFlags rf
= ResolveFlags
.VariableOrValue
;
2782 rf
|= ResolveFlags
.DisableFlowAnalysis
;
2784 e
= e
.Resolve (ec
, rf
);
2787 if (targs
!= null && e
!= null)
2788 e
.Error_TypeArgumentsCannotBeUsed (ec
.Report
, loc
);
2793 e
= current_block
.Toplevel
.GetParameterReference (Name
, loc
);
2795 if (right_side
!= null)
2796 e
= e
.ResolveLValue (ec
, right_side
);
2800 if (targs
!= null && e
!= null)
2801 e
.Error_TypeArgumentsCannotBeUsed (ec
.Report
, loc
);
2808 // Stage 2: Lookup members
2811 Type almost_matched_type
= null;
2812 ArrayList almost_matched
= null;
2813 for (Type lookup_ds
= ec
.CurrentType
; lookup_ds
!= null; lookup_ds
= lookup_ds
.DeclaringType
) {
2814 e
= MemberLookup (ec
.Compiler
, ec
.CurrentType
, lookup_ds
, Name
, loc
);
2816 PropertyExpr pe
= e
as PropertyExpr
;
2818 AParametersCollection param
= TypeManager
.GetParameterData (pe
.PropertyInfo
);
2820 // since TypeManager.MemberLookup doesn't know if we're doing a lvalue access or not,
2821 // it doesn't know which accessor to check permissions against
2822 if (param
.IsEmpty
&& pe
.IsAccessibleFrom (ec
.CurrentType
, right_side
!= null))
2824 } else if (e
is EventExpr
) {
2825 if (((EventExpr
) e
).IsAccessibleFrom (ec
.CurrentType
))
2827 } else if (targs
!= null && e
is TypeExpression
) {
2828 e
= new GenericTypeExpr (e
.Type
, targs
, loc
).ResolveAsTypeStep (ec
, false);
2836 if (almost_matched
== null && almost_matched_members
.Count
> 0) {
2837 almost_matched_type
= lookup_ds
;
2838 almost_matched
= (ArrayList
) almost_matched_members
.Clone ();
2843 if (almost_matched
== null && almost_matched_members
.Count
> 0) {
2844 almost_matched_type
= ec
.CurrentType
;
2845 almost_matched
= (ArrayList
) almost_matched_members
.Clone ();
2847 e
= ResolveAsTypeStep (ec
, true);
2851 if (current_block
!= null) {
2852 IKnownVariable ikv
= current_block
.Explicit
.GetKnownVariable (Name
);
2854 LocalInfo li
= ikv
as LocalInfo
;
2855 // Supress CS0219 warning
2859 Error_VariableIsUsedBeforeItIsDeclared (ec
.Report
, Name
);
2864 if (RootContext
.EvalMode
){
2865 FieldInfo fi
= Evaluator
.LookupField (Name
);
2867 return new FieldExpr (fi
, loc
).Resolve (ec
);
2870 if (almost_matched
!= null)
2871 almost_matched_members
= almost_matched
;
2872 if (almost_matched_type
== null)
2873 almost_matched_type
= ec
.CurrentType
;
2875 string type_name
= ec
.MemberContext
.CurrentType
== null ? null : ec
.MemberContext
.CurrentType
.Name
;
2876 return Error_MemberLookupFailed (ec
, ec
.CurrentType
, null, almost_matched_type
, Name
,
2877 type_name
, AllMemberTypes
, AllBindingFlags
);
2880 if (e
is MemberExpr
) {
2881 MemberExpr me
= (MemberExpr
) e
;
2884 if (me
.IsInstance
) {
2885 if (ec
.IsStatic
|| ec
.HasAny (ResolveContext
.Options
.FieldInitializerScope
| ResolveContext
.Options
.BaseInitializer
| ResolveContext
.Options
.ConstantScope
)) {
2887 // Note that an MemberExpr can be both IsInstance and IsStatic.
2888 // An unresolved MethodGroupExpr can contain both kinds of methods
2889 // and each predicate is true if the MethodGroupExpr contains
2890 // at least one of that kind of method.
2894 (!intermediate
|| !IdenticalNameAndTypeName (ec
, me
, loc
))) {
2895 Error_ObjectRefRequired (ec
, loc
, me
.GetSignatureForError ());
2900 // Pass the buck to MemberAccess and Invocation.
2902 left
= EmptyExpression
.Null
;
2904 left
= ec
.GetThis (loc
);
2907 left
= new TypeExpression (ec
.CurrentType
, loc
);
2910 me
= me
.ResolveMemberAccess (ec
, left
, loc
, null);
2914 if (targs
!= null) {
2915 if (!targs
.Resolve (ec
))
2918 me
.SetTypeArguments (ec
, targs
);
2921 if (!me
.IsStatic
&& (me
.InstanceExpression
!= null && me
.InstanceExpression
!= EmptyExpression
.Null
) &&
2922 TypeManager
.IsNestedFamilyAccessible (me
.InstanceExpression
.Type
, me
.DeclaringType
) &&
2923 me
.InstanceExpression
.Type
!= me
.DeclaringType
&&
2924 !TypeManager
.IsFamilyAccessible (me
.InstanceExpression
.Type
, me
.DeclaringType
) &&
2925 (!intermediate
|| !IdenticalNameAndTypeName (ec
, e
, loc
))) {
2926 ec
.Report
.Error (38, loc
, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2927 TypeManager
.CSharpName (me
.DeclaringType
), TypeManager
.CSharpName (me
.InstanceExpression
.Type
));
2931 return (right_side
!= null)
2932 ? me
.DoResolveLValue (ec
, right_side
)
2933 : me
.DoResolve (ec
);
2941 /// Represents a namespace or a type. The name of the class was inspired by
2942 /// section 10.8.1 (Fully Qualified Names).
2944 public abstract class FullNamedExpression
: Expression
2946 protected override void CloneTo (CloneContext clonectx
, Expression target
)
2948 // Do nothing, most unresolved type expressions cannot be
2949 // resolved to different type
2952 public override Expression
CreateExpressionTree (ResolveContext ec
)
2954 throw new NotSupportedException ("ET");
2957 public override void MutateHoistedGenericType (AnonymousMethodStorey storey
)
2959 throw new NotSupportedException ();
2962 public override FullNamedExpression
ResolveAsTypeStep (IMemberContext ec
, bool silent
)
2967 public override void Emit (EmitContext ec
)
2969 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2970 GetSignatureForError ());
2975 /// Expression that evaluates to a type
2977 public abstract class TypeExpr
: FullNamedExpression
{
2978 public override FullNamedExpression
ResolveAsTypeStep (IMemberContext ec
, bool silent
)
2980 TypeExpr t
= DoResolveAsTypeStep (ec
);
2984 eclass
= ExprClass
.Type
;
2988 override public Expression
DoResolve (ResolveContext ec
)
2990 return ResolveAsTypeTerminal (ec
, false);
2993 public virtual bool CheckAccessLevel (IMemberContext mc
)
2995 return mc
.CurrentTypeDefinition
.CheckAccessLevel (Type
);
2998 public virtual bool IsClass
{
2999 get { return Type.IsClass; }
3002 public virtual bool IsValueType
{
3003 get { return TypeManager.IsStruct (Type); }
3006 public virtual bool IsInterface
{
3007 get { return Type.IsInterface; }
3010 public virtual bool IsSealed
{
3011 get { return Type.IsSealed; }
3014 public virtual bool CanInheritFrom ()
3016 if (Type
== TypeManager
.enum_type
||
3017 (Type
== TypeManager
.value_type
&& RootContext
.StdLib
) ||
3018 Type
== TypeManager
.multicast_delegate_type
||
3019 Type
== TypeManager
.delegate_type
||
3020 Type
== TypeManager
.array_type
)
3026 protected abstract TypeExpr
DoResolveAsTypeStep (IMemberContext ec
);
3028 public override bool Equals (object obj
)
3030 TypeExpr tobj
= obj
as TypeExpr
;
3034 return Type
== tobj
.Type
;
3037 public override int GetHashCode ()
3039 return Type
.GetHashCode ();
3042 public override void MutateHoistedGenericType (AnonymousMethodStorey storey
)
3044 type
= storey
.MutateType (type
);
3049 /// Fully resolved Expression that already evaluated to a type
3051 public class TypeExpression
: TypeExpr
{
3052 public TypeExpression (Type t
, Location l
)
3055 eclass
= ExprClass
.Type
;
3059 protected override TypeExpr
DoResolveAsTypeStep (IMemberContext ec
)
3064 public override TypeExpr
ResolveAsTypeTerminal (IMemberContext ec
, bool silent
)
3071 // Used to create types from a fully qualified name. These are just used
3072 // by the parser to setup the core types.
3074 public sealed class TypeLookupExpression
: TypeExpr
{
3075 readonly string ns_name
;
3076 readonly string name
;
3078 public TypeLookupExpression (string ns
, string name
)
3082 eclass
= ExprClass
.Type
;
3085 public override TypeExpr
ResolveAsTypeTerminal (IMemberContext ec
, bool silent
)
3088 // It's null only during mscorlib bootstrap when DefineType
3089 // nees to resolve base type of same type
3091 // For instance struct Char : IComparable<char>
3093 // TODO: it could be removed when Resolve starts to use
3094 // DeclSpace instead of Type
3097 Namespace ns
= GlobalRootNamespace
.Instance
.GetNamespace (ns_name
, false);
3098 FullNamedExpression fne
= ns
.Lookup (ec
.Compiler
, name
, loc
);
3106 protected override TypeExpr
DoResolveAsTypeStep (IMemberContext ec
)
3111 public override string GetSignatureForError ()
3114 return TypeManager
.CSharpName (ns_name
+ "." + name
, null);
3116 return base.GetSignatureForError ();
3121 /// This class denotes an expression which evaluates to a member
3122 /// of a struct or a class.
3124 public abstract class MemberExpr
: Expression
3126 protected bool is_base
;
3129 /// The name of this member.
3131 public abstract string Name
{
3136 // When base.member is used
3138 public bool IsBase
{
3139 get { return is_base; }
3140 set { is_base = value; }
3144 /// Whether this is an instance member.
3146 public abstract bool IsInstance
{
3151 /// Whether this is a static member.
3153 public abstract bool IsStatic
{
3158 /// The type which declares this member.
3160 public abstract Type DeclaringType
{
3165 /// The instance expression associated with this member, if it's a
3166 /// non-static member.
3168 public Expression InstanceExpression
;
3170 public static void error176 (ResolveContext ec
, Location loc
, string name
)
3172 ec
.Report
.Error (176, loc
, "Static member `{0}' cannot be accessed " +
3173 "with an instance reference, qualify it with a type name instead", name
);
3176 public static void Error_BaseAccessInExpressionTree (ResolveContext ec
, Location loc
)
3178 ec
.Report
.Error (831, loc
, "An expression tree may not contain a base access");
3181 public override void MutateHoistedGenericType (AnonymousMethodStorey storey
)
3183 if (InstanceExpression
!= null)
3184 InstanceExpression
.MutateHoistedGenericType (storey
);
3187 // TODO: possible optimalization
3188 // Cache resolved constant result in FieldBuilder <-> expression map
3189 public virtual MemberExpr
ResolveMemberAccess (ResolveContext ec
, Expression left
, Location loc
,
3190 SimpleName original
)
3194 // original == null || original.Resolve (...) ==> left
3197 if (left
is TypeExpr
) {
3198 left
= left
.ResolveAsBaseTerminal (ec
, false);
3202 // TODO: Same problem as in class.cs, TypeTerminal does not
3203 // always do all necessary checks
3204 ObsoleteAttribute oa
= AttributeTester
.GetObsoleteAttribute (left
.Type
);
3205 if (oa
!= null && !ec
.IsObsolete
) {
3206 AttributeTester
.Report_ObsoleteMessage (oa
, left
.GetSignatureForError (), loc
, ec
.Report
);
3209 GenericTypeExpr ct
= left
as GenericTypeExpr
;
3210 if (ct
!= null && !ct
.CheckConstraints (ec
))
3215 SimpleName
.Error_ObjectRefRequired (ec
, loc
, GetSignatureForError ());
3223 if (original
!= null && original
.IdenticalNameAndTypeName (ec
, left
, loc
))
3226 return ResolveExtensionMemberAccess (ec
, left
);
3229 InstanceExpression
= left
;
3233 protected virtual MemberExpr
ResolveExtensionMemberAccess (ResolveContext ec
, Expression left
)
3235 error176 (ec
, loc
, GetSignatureForError ());
3239 protected void EmitInstance (EmitContext ec
, bool prepare_for_load
)
3244 if (InstanceExpression
== EmptyExpression
.Null
) {
3245 // FIXME: This should not be here at all
3246 SimpleName
.Error_ObjectRefRequired (new ResolveContext (ec
.MemberContext
), loc
, GetSignatureForError ());
3250 if (TypeManager
.IsValueType (InstanceExpression
.Type
)) {
3251 if (InstanceExpression
is IMemoryLocation
) {
3252 ((IMemoryLocation
) InstanceExpression
).AddressOf (ec
, AddressOp
.LoadStore
);
3254 LocalTemporary t
= new LocalTemporary (InstanceExpression
.Type
);
3255 InstanceExpression
.Emit (ec
);
3257 t
.AddressOf (ec
, AddressOp
.Store
);
3260 InstanceExpression
.Emit (ec
);
3262 if (prepare_for_load
)
3263 ec
.ig
.Emit (OpCodes
.Dup
);
3266 public virtual void SetTypeArguments (ResolveContext ec
, TypeArguments ta
)
3268 // TODO: need to get correct member type
3269 ec
.Report
.Error (307, loc
, "The property `{0}' cannot be used with type arguments",
3270 GetSignatureForError ());
3275 /// Represents group of extension methods
3277 public class ExtensionMethodGroupExpr
: MethodGroupExpr
3279 readonly NamespaceEntry namespace_entry
;
3280 public Expression ExtensionExpression
;
3281 Argument extension_argument
;
3283 public ExtensionMethodGroupExpr (ArrayList list
, NamespaceEntry n
, Type extensionType
, Location l
)
3284 : base (list
, extensionType
, l
)
3286 this.namespace_entry
= n
;
3289 public override bool IsStatic
{
3290 get { return true; }
3293 public bool IsTopLevel
{
3294 get { return namespace_entry == null; }
3297 public override void MutateHoistedGenericType (AnonymousMethodStorey storey
)
3299 extension_argument
.Expr
.MutateHoistedGenericType (storey
);
3300 base.MutateHoistedGenericType (storey
);
3303 public override MethodGroupExpr
OverloadResolve (ResolveContext ec
, ref Arguments arguments
, bool may_fail
, Location loc
)
3305 if (arguments
== null)
3306 arguments
= new Arguments (1);
3308 arguments
.Insert (0, new Argument (ExtensionExpression
));
3309 MethodGroupExpr mg
= ResolveOverloadExtensions (ec
, ref arguments
, namespace_entry
, loc
);
3311 // Store resolved argument and restore original arguments
3313 ((ExtensionMethodGroupExpr
)mg
).extension_argument
= arguments
[0];
3315 arguments
.RemoveAt (0); // Clean-up modified arguments for error reporting
3320 MethodGroupExpr
ResolveOverloadExtensions (ResolveContext ec
, ref Arguments arguments
, NamespaceEntry ns
, Location loc
)
3322 // Use normal resolve rules
3323 MethodGroupExpr mg
= base.OverloadResolve (ec
, ref arguments
, ns
!= null, loc
);
3331 ExtensionMethodGroupExpr e
= ns
.LookupExtensionMethod (type
, Name
, loc
);
3333 return base.OverloadResolve (ec
, ref arguments
, false, loc
);
3335 e
.ExtensionExpression
= ExtensionExpression
;
3336 e
.SetTypeArguments (ec
, type_arguments
);
3337 return e
.ResolveOverloadExtensions (ec
, ref arguments
, e
.namespace_entry
, loc
);
3342 /// MethodGroupExpr represents a group of method candidates which
3343 /// can be resolved to the best method overload
3345 public class MethodGroupExpr
: MemberExpr
3347 public interface IErrorHandler
3349 bool AmbiguousCall (ResolveContext ec
, MethodBase ambiguous
);
3350 bool NoExactMatch (ResolveContext ec
, MethodBase method
);
3353 public IErrorHandler CustomErrorHandler
;
3354 public MethodBase
[] Methods
;
3355 MethodBase best_candidate
;
3356 // TODO: make private
3357 public TypeArguments type_arguments
;
3358 bool identical_type_name
;
3359 bool has_inaccessible_candidates_only
;
3363 public MethodGroupExpr (MemberInfo
[] mi
, Type type
, Location l
)
3366 Methods
= new MethodBase
[mi
.Length
];
3367 mi
.CopyTo (Methods
, 0);
3370 public MethodGroupExpr (MemberInfo
[] mi
, Type type
, Location l
, bool inacessibleCandidatesOnly
)
3371 : this (mi
, type
, l
)
3373 has_inaccessible_candidates_only
= inacessibleCandidatesOnly
;
3376 public MethodGroupExpr (ArrayList list
, Type type
, Location l
)
3380 Methods
= (MethodBase
[])list
.ToArray (typeof (MethodBase
));
3382 foreach (MemberInfo m
in list
){
3383 if (!(m
is MethodBase
)){
3384 Console
.WriteLine ("Name " + m
.Name
);
3385 Console
.WriteLine ("Found a: " + m
.GetType ().FullName
);
3394 protected MethodGroupExpr (Type type
, Location loc
)
3397 eclass
= ExprClass
.MethodGroup
;
3398 this.type
= InternalType
.MethodGroup
;
3399 queried_type
= type
;
3402 public override Type DeclaringType
{
3404 return queried_type
;
3408 public Type DelegateType
{
3410 delegate_type
= value;
3414 public bool IdenticalTypeName
{
3416 return identical_type_name
;
3420 public override string GetSignatureForError ()
3422 if (best_candidate
!= null)
3423 return TypeManager
.CSharpSignature (best_candidate
);
3425 return TypeManager
.CSharpSignature (Methods
[0]);
3428 public override string Name
{
3430 return Methods
[0].Name
;
3434 public override bool IsInstance
{
3436 if (best_candidate
!= null)
3437 return !best_candidate
.IsStatic
;
3439 foreach (MethodBase mb
in Methods
)
3447 public override bool IsStatic
{
3449 if (best_candidate
!= null)
3450 return best_candidate
.IsStatic
;
3452 foreach (MethodBase mb
in Methods
)
3460 public static explicit operator ConstructorInfo (MethodGroupExpr mg
)
3462 return (ConstructorInfo
)mg
.best_candidate
;
3465 public static explicit operator MethodInfo (MethodGroupExpr mg
)
3467 return (MethodInfo
)mg
.best_candidate
;
3471 // 7.4.3.3 Better conversion from expression
3472 // Returns : 1 if a->p is better,
3473 // 2 if a->q is better,
3474 // 0 if neither is better
3476 static int BetterExpressionConversion (ResolveContext ec
, Argument a
, Type p
, Type q
)
3478 Type argument_type
= TypeManager
.TypeToCoreType (a
.Type
);
3479 if (argument_type
== InternalType
.AnonymousMethod
&& RootContext
.Version
> LanguageVersion
.ISO_2
) {
3481 // Uwrap delegate from Expression<T>
3483 if (TypeManager
.DropGenericTypeArguments (p
) == TypeManager
.expression_type
) {
3484 p
= TypeManager
.GetTypeArguments (p
) [0];
3486 if (TypeManager
.DropGenericTypeArguments (q
) == TypeManager
.expression_type
) {
3487 q
= TypeManager
.GetTypeArguments (q
) [0];
3490 p
= Delegate
.GetInvokeMethod (ec
.Compiler
, null, p
).ReturnType
;
3491 q
= Delegate
.GetInvokeMethod (ec
.Compiler
, null, q
).ReturnType
;
3492 if (p
== TypeManager
.void_type
&& q
!= TypeManager
.void_type
)
3494 if (q
== TypeManager
.void_type
&& p
!= TypeManager
.void_type
)
3497 if (argument_type
== p
)
3500 if (argument_type
== q
)
3504 return BetterTypeConversion (ec
, p
, q
);
3508 // 7.4.3.4 Better conversion from type
3510 public static int BetterTypeConversion (ResolveContext ec
, Type p
, Type q
)
3512 if (p
== null || q
== null)
3513 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3515 if (p
== TypeManager
.int32_type
) {
3516 if (q
== TypeManager
.uint32_type
|| q
== TypeManager
.uint64_type
)
3518 } else if (p
== TypeManager
.int64_type
) {
3519 if (q
== TypeManager
.uint64_type
)
3521 } else if (p
== TypeManager
.sbyte_type
) {
3522 if (q
== TypeManager
.byte_type
|| q
== TypeManager
.ushort_type
||
3523 q
== TypeManager
.uint32_type
|| q
== TypeManager
.uint64_type
)
3525 } else if (p
== TypeManager
.short_type
) {
3526 if (q
== TypeManager
.ushort_type
|| q
== TypeManager
.uint32_type
||
3527 q
== TypeManager
.uint64_type
)
3529 } else if (p
== InternalType
.Dynamic
) {
3530 if (q
== TypeManager
.object_type
)
3534 if (q
== TypeManager
.int32_type
) {
3535 if (p
== TypeManager
.uint32_type
|| p
== TypeManager
.uint64_type
)
3537 } if (q
== TypeManager
.int64_type
) {
3538 if (p
== TypeManager
.uint64_type
)
3540 } else if (q
== TypeManager
.sbyte_type
) {
3541 if (p
== TypeManager
.byte_type
|| p
== TypeManager
.ushort_type
||
3542 p
== TypeManager
.uint32_type
|| p
== TypeManager
.uint64_type
)
3544 } if (q
== TypeManager
.short_type
) {
3545 if (p
== TypeManager
.ushort_type
|| p
== TypeManager
.uint32_type
||
3546 p
== TypeManager
.uint64_type
)
3548 } else if (q
== InternalType
.Dynamic
) {
3549 if (p
== TypeManager
.object_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 (ResolveContext ec
, Arguments 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
= args
[j
];
3591 // Provided default argument value is never better
3592 if (a
.IsDefaultArgument
&& candidate_params
== best_params
)
3595 Type ct
= candidate_pd
.Types
[c_idx
];
3596 Type bt
= best_pd
.Types
[b_idx
];
3598 if (candidate_params
&& candidate_pd
.FixedParameters
[c_idx
].ModFlags
== Parameter
.Modifier
.PARAMS
)
3600 ct
= TypeManager
.GetElementType (ct
);
3604 if (best_params
&& best_pd
.FixedParameters
[b_idx
].ModFlags
== Parameter
.Modifier
.PARAMS
)
3606 bt
= TypeManager
.GetElementType (bt
);
3614 int result
= BetterExpressionConversion (ec
, a
, ct
, bt
);
3616 // for each argument, the conversion to 'ct' should be no worse than
3617 // the conversion to 'bt'.
3621 // for at least one argument, the conversion to 'ct' should be better than
3622 // the conversion to 'bt'.
3624 better_at_least_one
= true;
3627 if (better_at_least_one
)
3631 // This handles the case
3633 // Add (float f1, float f2, float f3);
3634 // Add (params decimal [] foo);
3636 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3637 // first candidate would've chosen as better.
3643 // The two methods have equal parameter types. Now apply tie-breaking rules
3645 if (TypeManager
.IsGenericMethod (best
)) {
3646 if (!TypeManager
.IsGenericMethod (candidate
))
3648 } else if (TypeManager
.IsGenericMethod (candidate
)) {
3653 // This handles the following cases:
3655 // Trim () is better than Trim (params char[] chars)
3656 // Concat (string s1, string s2, string s3) is better than
3657 // Concat (string s1, params string [] srest)
3658 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3660 if (!candidate_params
&& best_params
)
3662 if (candidate_params
&& !best_params
)
3665 int candidate_param_count
= candidate_pd
.Count
;
3666 int best_param_count
= best_pd
.Count
;
3668 if (candidate_param_count
!= best_param_count
)
3669 // can only happen if (candidate_params && best_params)
3670 return candidate_param_count
> best_param_count
&& best_pd
.HasParams
;
3673 // now, both methods have the same number of parameters, and the parameters have the same types
3674 // Pick the "more specific" signature
3677 MethodBase orig_candidate
= TypeManager
.DropGenericMethodArguments (candidate
);
3678 MethodBase orig_best
= TypeManager
.DropGenericMethodArguments (best
);
3680 AParametersCollection orig_candidate_pd
= TypeManager
.GetParameterData (orig_candidate
);
3681 AParametersCollection orig_best_pd
= TypeManager
.GetParameterData (orig_best
);
3683 bool specific_at_least_once
= false;
3684 for (int j
= 0; j
< candidate_param_count
; ++j
)
3686 Type ct
= orig_candidate_pd
.Types
[j
];
3687 Type bt
= orig_best_pd
.Types
[j
];
3690 Type specific
= MoreSpecific (ct
, bt
);
3694 specific_at_least_once
= true;
3697 if (specific_at_least_once
)
3700 // FIXME: handle lifted operators
3706 protected override MemberExpr
ResolveExtensionMemberAccess (ResolveContext ec
, Expression left
)
3709 return base.ResolveExtensionMemberAccess (ec
, left
);
3712 // When left side is an expression and at least one candidate method is
3713 // static, it can be extension method
3715 InstanceExpression
= left
;
3719 public override MemberExpr
ResolveMemberAccess (ResolveContext ec
, Expression left
, Location loc
,
3720 SimpleName original
)
3722 if (!(left
is TypeExpr
) &&
3723 original
!= null && original
.IdenticalNameAndTypeName (ec
, left
, loc
))
3724 identical_type_name
= true;
3726 return base.ResolveMemberAccess (ec
, left
, loc
, original
);
3729 public override Expression
CreateExpressionTree (ResolveContext ec
)
3731 if (best_candidate
== null) {
3732 ec
.Report
.Error (1953, loc
, "An expression tree cannot contain an expression with method group");
3736 IMethodData md
= TypeManager
.GetMethod (best_candidate
);
3737 if (md
!= null && md
.IsExcluded ())
3738 ec
.Report
.Error (765, loc
,
3739 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3741 return new TypeOfMethod (best_candidate
, loc
);
3744 override public Expression
DoResolve (ResolveContext ec
)
3746 if (InstanceExpression
!= null) {
3747 InstanceExpression
= InstanceExpression
.DoResolve (ec
);
3748 if (InstanceExpression
== null)
3755 public void ReportUsageError (ResolveContext ec
)
3757 ec
.Report
.Error (654, loc
, "Method `" + DeclaringType
+ "." +
3758 Name
+ "()' is referenced without parentheses");
3761 override public void Emit (EmitContext ec
)
3763 throw new NotSupportedException ();
3764 // ReportUsageError ();
3767 public void EmitCall (EmitContext ec
, Arguments arguments
)
3769 Invocation
.EmitCall (ec
, IsBase
, InstanceExpression
, best_candidate
, arguments
, loc
);
3772 void Error_AmbiguousCall (ResolveContext ec
, MethodBase ambiguous
)
3774 if (CustomErrorHandler
!= null && CustomErrorHandler
.AmbiguousCall (ec
, ambiguous
))
3777 ec
.Report
.SymbolRelatedToPreviousError (best_candidate
);
3778 ec
.Report
.Error (121, loc
, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
3779 TypeManager
.CSharpSignature (ambiguous
), TypeManager
.CSharpSignature (best_candidate
));
3782 protected virtual void Error_InvalidArguments (ResolveContext ec
, Location loc
, int idx
, MethodBase method
,
3783 Argument a
, AParametersCollection expected_par
, Type paramType
)
3785 ExtensionMethodGroupExpr emg
= this as ExtensionMethodGroupExpr
;
3787 if (a
is CollectionElementInitializer
.ElementInitializerArgument
) {
3788 ec
.Report
.SymbolRelatedToPreviousError (method
);
3789 if ((expected_par
.FixedParameters
[idx
].ModFlags
& Parameter
.Modifier
.ISBYREF
) != 0) {
3790 ec
.Report
.Error (1954, loc
, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
3791 TypeManager
.CSharpSignature (method
));
3794 ec
.Report
.Error (1950, loc
, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
3795 TypeManager
.CSharpSignature (method
));
3796 } else if (TypeManager
.IsDelegateType (method
.DeclaringType
)) {
3797 ec
.Report
.Error (1594, loc
, "Delegate `{0}' has some invalid arguments",
3798 TypeManager
.CSharpName (method
.DeclaringType
));
3800 ec
.Report
.SymbolRelatedToPreviousError (method
);
3802 ec
.Report
.Error (1928, loc
,
3803 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3804 emg
.ExtensionExpression
.GetSignatureForError (),
3805 emg
.Name
, TypeManager
.CSharpSignature (method
));
3807 ec
.Report
.Error (1502, loc
, "The best overloaded method match for `{0}' has some invalid arguments",
3808 TypeManager
.CSharpSignature (method
));
3812 Parameter
.Modifier mod
= idx
>= expected_par
.Count
? 0 : expected_par
.FixedParameters
[idx
].ModFlags
;
3814 string index
= (idx
+ 1).ToString ();
3815 if (((mod
& (Parameter
.Modifier
.REF
| Parameter
.Modifier
.OUT
)) ^
3816 (a
.Modifier
& (Parameter
.Modifier
.REF
| Parameter
.Modifier
.OUT
))) != 0) {
3817 if ((mod
& Parameter
.Modifier
.ISBYREF
) == 0)
3818 ec
.Report
.Error (1615, loc
, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
3819 index
, Parameter
.GetModifierSignature (a
.Modifier
));
3821 ec
.Report
.Error (1620, loc
, "Argument `#{0}' is missing `{1}' modifier",
3822 index
, Parameter
.GetModifierSignature (mod
));
3824 string p1
= a
.GetSignatureForError ();
3825 string p2
= TypeManager
.CSharpName (paramType
);
3828 ec
.Report
.ExtraInformation (loc
, "(equally named types possibly from different assemblies in previous ");
3829 ec
.Report
.SymbolRelatedToPreviousError (a
.Expr
.Type
);
3830 ec
.Report
.SymbolRelatedToPreviousError (paramType
);
3833 if (idx
== 0 && emg
!= null) {
3834 ec
.Report
.Error (1929, loc
,
3835 "Extension method instance type `{0}' cannot be converted to `{1}'", p1
, p2
);
3837 ec
.Report
.Error (1503, loc
,
3838 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index
, p1
, p2
);
3843 public override void Error_ValueCannotBeConverted (ResolveContext ec
, Location loc
, Type target
, bool expl
)
3845 ec
.Report
.Error (428, loc
, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3846 Name
, TypeManager
.CSharpName (target
));
3849 void Error_ArgumentCountWrong (ResolveContext ec
, int arg_count
)
3851 ec
.Report
.Error (1501, loc
, "No overload for method `{0}' takes `{1}' arguments",
3852 Name
, arg_count
.ToString ());
3855 protected virtual int GetApplicableParametersCount (MethodBase method
, AParametersCollection parameters
)
3857 return parameters
.Count
;
3860 public static bool IsAncestralType (Type first_type
, Type second_type
)
3862 return first_type
!= second_type
&&
3863 (TypeManager
.IsSubclassOf (second_type
, first_type
) ||
3864 TypeManager
.ImplementsInterface (second_type
, first_type
));
3868 /// Determines if the candidate method is applicable (section 14.4.2.1)
3869 /// to the given set of arguments
3870 /// A return value rates candidate method compatibility,
3871 /// 0 = the best, int.MaxValue = the worst
3873 public int IsApplicable (ResolveContext ec
,
3874 ref Arguments arguments
, int arg_count
, ref MethodBase method
, ref bool params_expanded_form
)
3876 MethodBase candidate
= method
;
3878 AParametersCollection pd
= TypeManager
.GetParameterData (candidate
);
3879 int param_count
= GetApplicableParametersCount (candidate
, pd
);
3880 int optional_count
= 0;
3882 if (arg_count
!= param_count
) {
3883 for (int i
= 0; i
< pd
.Count
; ++i
) {
3884 if (pd
.FixedParameters
[i
].HasDefaultValue
) {
3885 optional_count
= pd
.Count
- i
;
3890 int args_gap
= Math
.Abs (arg_count
- param_count
);
3891 if (optional_count
!= 0) {
3892 if (args_gap
> optional_count
)
3893 return int.MaxValue
- 10000 + args_gap
- optional_count
;
3895 // Readjust expected number when params used
3898 if (arg_count
< param_count
)
3900 } else if (arg_count
> param_count
) {
3901 return int.MaxValue
- 10000 + args_gap
;
3903 } else if (arg_count
!= param_count
) {
3905 return int.MaxValue
- 10000 + args_gap
;
3906 if (arg_count
< param_count
- 1)
3907 return int.MaxValue
- 10000 + args_gap
;
3910 // Initialize expanded form of a method with 1 params parameter
3911 params_expanded_form
= param_count
== 1 && pd
.HasParams
;
3913 // Resize to fit optional arguments
3914 if (optional_count
!= 0) {
3916 if (arguments
== null) {
3917 resized
= new Arguments (optional_count
);
3919 resized
= new Arguments (param_count
);
3920 resized
.AddRange (arguments
);
3923 for (int i
= arg_count
; i
< param_count
; ++i
)
3925 arguments
= resized
;
3929 if (arg_count
> 0) {
3931 // Shuffle named arguments to the right positions if there are any
3933 if (arguments
[arg_count
- 1] is NamedArgument
) {
3934 arg_count
= arguments
.Count
;
3936 for (int i
= 0; i
< arg_count
; ++i
) {
3937 bool arg_moved
= false;
3939 NamedArgument na
= arguments
[i
] as NamedArgument
;
3943 int index
= pd
.GetParameterIndexByName (na
.Name
.Value
);
3945 // Named parameter not found or already reordered
3949 // When using parameters which should not be available to the user
3950 if (index
>= param_count
)
3954 arguments
.MarkReorderedArgument (na
);
3958 Argument temp
= arguments
[index
];
3959 arguments
[index
] = arguments
[i
];
3960 arguments
[i
] = temp
;
3967 arg_count
= arguments
.Count
;
3969 } else if (arguments
!= null) {
3970 arg_count
= arguments
.Count
;
3974 // 1. Handle generic method using type arguments when specified or type inference
3976 if (TypeManager
.IsGenericMethod (candidate
)) {
3977 if (type_arguments
!= null) {
3978 Type
[] g_args
= candidate
.GetGenericArguments ();
3979 if (g_args
.Length
!= type_arguments
.Count
)
3980 return int.MaxValue
- 20000 + Math
.Abs (type_arguments
.Count
- g_args
.Length
);
3982 // TODO: Don't create new method, create Parameters only
3983 method
= ((MethodInfo
) candidate
).MakeGenericMethod (type_arguments
.Arguments
);
3985 pd
= TypeManager
.GetParameterData (candidate
);
3987 int score
= TypeManager
.InferTypeArguments (ec
, arguments
, ref candidate
);
3989 return score
- 20000;
3991 if (TypeManager
.IsGenericMethodDefinition (candidate
))
3992 throw new InternalErrorException ("A generic method `{0}' definition took part in overload resolution",
3993 TypeManager
.CSharpSignature (candidate
));
3995 pd
= TypeManager
.GetParameterData (candidate
);
3998 if (type_arguments
!= null)
3999 return int.MaxValue
- 15000;
4003 // 2. Each argument has to be implicitly convertible to method parameter
4006 Parameter
.Modifier p_mod
= 0;
4008 for (int i
= 0; i
< arg_count
; i
++) {
4009 Argument a
= arguments
[i
];
4011 if (!pd
.FixedParameters
[i
].HasDefaultValue
)
4012 throw new InternalErrorException ();
4014 Expression e
= pd
.FixedParameters
[i
].DefaultValue
as Constant
;
4016 e
= new DefaultValueExpression (new TypeExpression (pd
.Types
[i
], loc
), loc
).Resolve (ec
);
4018 arguments
[i
] = new Argument (e
, Argument
.AType
.Default
);
4022 if (p_mod
!= Parameter
.Modifier
.PARAMS
) {
4023 p_mod
= pd
.FixedParameters
[i
].ModFlags
& ~
(Parameter
.Modifier
.OUTMASK
| Parameter
.Modifier
.REFMASK
);
4026 params_expanded_form
= true;
4029 Parameter
.Modifier a_mod
= a
.Modifier
& ~
(Parameter
.Modifier
.OUTMASK
| Parameter
.Modifier
.REFMASK
);
4031 if (!params_expanded_form
)
4032 score
= IsArgumentCompatible (ec
, a_mod
, a
, p_mod
& ~Parameter
.Modifier
.PARAMS
, pt
);
4034 if (score
!= 0 && (p_mod
& Parameter
.Modifier
.PARAMS
) != 0 && delegate_type
== null) {
4035 // It can be applicable in expanded form
4036 score
= IsArgumentCompatible (ec
, a_mod
, a
, 0, TypeManager
.GetElementType (pt
));
4038 params_expanded_form
= true;
4042 if (params_expanded_form
)
4044 return (arg_count
- i
) * 2 + score
;
4048 if (arg_count
!= param_count
)
4049 params_expanded_form
= true;
4054 int IsArgumentCompatible (ResolveContext ec
, Parameter
.Modifier arg_mod
, Argument argument
, Parameter
.Modifier param_mod
, Type parameter
)
4057 // Types have to be identical when ref or out modifer is used
4059 if (arg_mod
!= 0 || param_mod
!= 0) {
4060 if (TypeManager
.HasElementType (parameter
))
4061 parameter
= TypeManager
.GetElementType (parameter
);
4063 Type a_type
= argument
.Type
;
4064 if (TypeManager
.HasElementType (a_type
))
4065 a_type
= TypeManager
.GetElementType (a_type
);
4067 if (a_type
!= parameter
) {
4068 if (TypeManager
.IsDynamicType (a_type
))
4074 if (!Convert
.ImplicitConversionExists (ec
, argument
.Expr
, parameter
)) {
4075 if (TypeManager
.IsDynamicType (argument
.Type
))
4082 if (arg_mod
!= param_mod
)
4088 public static bool IsOverride (MethodBase cand_method
, MethodBase base_method
)
4090 if (!IsAncestralType (base_method
.DeclaringType
, cand_method
.DeclaringType
))
4093 AParametersCollection cand_pd
= TypeManager
.GetParameterData (cand_method
);
4094 AParametersCollection base_pd
= TypeManager
.GetParameterData (base_method
);
4096 if (cand_pd
.Count
!= base_pd
.Count
)
4099 for (int j
= 0; j
< cand_pd
.Count
; ++j
)
4101 Parameter
.Modifier cm
= cand_pd
.FixedParameters
[j
].ModFlags
;
4102 Parameter
.Modifier bm
= base_pd
.FixedParameters
[j
].ModFlags
;
4103 Type ct
= cand_pd
.Types
[j
];
4104 Type bt
= base_pd
.Types
[j
];
4106 if (cm
!= bm
|| ct
!= bt
)
4113 public static MethodGroupExpr
MakeUnionSet (MethodGroupExpr mg1
, MethodGroupExpr mg2
, Location loc
)
4124 ArrayList all
= new ArrayList (mg1
.Methods
);
4125 foreach (MethodBase m
in mg2
.Methods
){
4126 if (!TypeManager
.ArrayContainsMethod (mg1
.Methods
, m
, false))
4130 return new MethodGroupExpr (all
, null, loc
);
4133 static Type
MoreSpecific (Type p
, Type q
)
4135 if (TypeManager
.IsGenericParameter (p
) && !TypeManager
.IsGenericParameter (q
))
4137 if (!TypeManager
.IsGenericParameter (p
) && TypeManager
.IsGenericParameter (q
))
4140 if (TypeManager
.HasElementType (p
))
4142 Type pe
= TypeManager
.GetElementType (p
);
4143 Type qe
= TypeManager
.GetElementType (q
);
4144 Type specific
= MoreSpecific (pe
, qe
);
4150 else if (TypeManager
.IsGenericType (p
))
4152 Type
[] pargs
= TypeManager
.GetTypeArguments (p
);
4153 Type
[] qargs
= TypeManager
.GetTypeArguments (q
);
4155 bool p_specific_at_least_once
= false;
4156 bool q_specific_at_least_once
= false;
4158 for (int i
= 0; i
< pargs
.Length
; i
++)
4160 Type specific
= MoreSpecific (TypeManager
.TypeToCoreType (pargs
[i
]), TypeManager
.TypeToCoreType (qargs
[i
]));
4161 if (specific
== pargs
[i
])
4162 p_specific_at_least_once
= true;
4163 if (specific
== qargs
[i
])
4164 q_specific_at_least_once
= true;
4167 if (p_specific_at_least_once
&& !q_specific_at_least_once
)
4169 if (!p_specific_at_least_once
&& q_specific_at_least_once
)
4176 public override void MutateHoistedGenericType (AnonymousMethodStorey storey
)
4178 base.MutateHoistedGenericType (storey
);
4180 MethodInfo mi
= best_candidate
as MethodInfo
;
4182 best_candidate
= storey
.MutateGenericMethod (mi
);
4186 best_candidate
= storey
.MutateConstructor ((ConstructorInfo
) this);
4190 /// Find the Applicable Function Members (7.4.2.1)
4192 /// me: Method Group expression with the members to select.
4193 /// it might contain constructors or methods (or anything
4194 /// that maps to a method).
4196 /// Arguments: ArrayList containing resolved Argument objects.
4198 /// loc: The location if we want an error to be reported, or a Null
4199 /// location for "probing" purposes.
4201 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4202 /// that is the best match of me on Arguments.
4205 public virtual MethodGroupExpr
OverloadResolve (ResolveContext ec
, ref Arguments Arguments
,
4206 bool may_fail
, Location loc
)
4208 bool method_params
= false;
4209 Type applicable_type
= null;
4210 ArrayList candidates
= new ArrayList (2);
4211 ArrayList candidate_overrides
= null;
4214 // Used to keep a map between the candidate
4215 // and whether it is being considered in its
4216 // normal or expanded form
4218 // false is normal form, true is expanded form
4220 Hashtable candidate_to_form
= null;
4221 Hashtable candidates_expanded
= null;
4222 Arguments candidate_args
= Arguments
;
4224 int arg_count
= Arguments
!= null ? Arguments
.Count
: 0;
4226 if (RootContext
.Version
== LanguageVersion
.ISO_1
&& Name
== "Invoke" && TypeManager
.IsDelegateType (DeclaringType
)) {
4228 ec
.Report
.Error (1533, loc
, "Invoke cannot be called directly on a delegate");
4232 int nmethods
= Methods
.Length
;
4236 // Methods marked 'override' don't take part in 'applicable_type'
4237 // computation, nor in the actual overload resolution.
4238 // However, they still need to be emitted instead of a base virtual method.
4239 // So, we salt them away into the 'candidate_overrides' array.
4241 // In case of reflected methods, we replace each overriding method with
4242 // its corresponding base virtual method. This is to improve compatibility
4243 // with non-C# libraries which change the visibility of overrides (#75636)
4246 for (int i
= 0; i
< Methods
.Length
; ++i
) {
4247 MethodBase m
= Methods
[i
];
4248 if (TypeManager
.IsOverride (m
)) {
4249 if (candidate_overrides
== null)
4250 candidate_overrides
= new ArrayList ();
4251 candidate_overrides
.Add (m
);
4252 m
= TypeManager
.TryGetBaseDefinition (m
);
4261 // Enable message recording, it's used mainly by lambda expressions
4263 SessionReportPrinter msg_recorder
= new SessionReportPrinter ();
4264 ReportPrinter prev_recorder
= ec
.Report
.SetPrinter (msg_recorder
);
4267 // First we construct the set of applicable methods
4269 bool is_sorted
= true;
4270 int best_candidate_rate
= int.MaxValue
;
4271 for (int i
= 0; i
< nmethods
; i
++) {
4272 Type decl_type
= Methods
[i
].DeclaringType
;
4275 // If we have already found an applicable method
4276 // we eliminate all base types (Section 14.5.5.1)
4278 if (applicable_type
!= null && IsAncestralType (decl_type
, applicable_type
))
4282 // Check if candidate is applicable (section 14.4.2.1)
4284 bool params_expanded_form
= false;
4285 int candidate_rate
= IsApplicable (ec
, ref candidate_args
, arg_count
, ref Methods
[i
], ref params_expanded_form
);
4287 if (candidate_rate
< best_candidate_rate
) {
4288 best_candidate_rate
= candidate_rate
;
4289 best_candidate
= Methods
[i
];
4292 if (params_expanded_form
) {
4293 if (candidate_to_form
== null)
4294 candidate_to_form
= new PtrHashtable ();
4295 MethodBase candidate
= Methods
[i
];
4296 candidate_to_form
[candidate
] = candidate
;
4299 if (candidate_args
!= Arguments
) {
4300 if (candidates_expanded
== null)
4301 candidates_expanded
= new Hashtable (2);
4303 candidates_expanded
.Add (Methods
[i
], candidate_args
);
4304 candidate_args
= Arguments
;
4307 if (candidate_rate
!= 0 || has_inaccessible_candidates_only
) {
4308 if (msg_recorder
!= null)
4309 msg_recorder
.EndSession ();
4313 msg_recorder
= null;
4314 candidates
.Add (Methods
[i
]);
4316 if (applicable_type
== null)
4317 applicable_type
= decl_type
;
4318 else if (applicable_type
!= decl_type
) {
4320 if (IsAncestralType (applicable_type
, decl_type
))
4321 applicable_type
= decl_type
;
4325 ec
.Report
.SetPrinter (prev_recorder
);
4326 if (msg_recorder
!= null && !msg_recorder
.IsEmpty
) {
4328 msg_recorder
.Merge (prev_recorder
);
4333 int candidate_top
= candidates
.Count
;
4335 if (applicable_type
== null) {
4337 // When we found a top level method which does not match and it's
4338 // not an extension method. We start extension methods lookup from here
4340 if (InstanceExpression
!= null) {
4341 ExtensionMethodGroupExpr ex_method_lookup
= ec
.LookupExtensionMethod (type
, Name
, loc
);
4342 if (ex_method_lookup
!= null) {
4343 ex_method_lookup
.ExtensionExpression
= InstanceExpression
;
4344 ex_method_lookup
.SetTypeArguments (ec
, type_arguments
);
4345 return ex_method_lookup
.OverloadResolve (ec
, ref Arguments
, may_fail
, loc
);
4353 // Okay so we have failed to find exact match so we
4354 // return error info about the closest match
4356 if (best_candidate
!= null) {
4357 if (CustomErrorHandler
!= null && !has_inaccessible_candidates_only
&& CustomErrorHandler
.NoExactMatch (ec
, best_candidate
))
4360 if (NoExactMatch (ec
, ref Arguments
, candidate_to_form
))
4365 // We failed to find any method with correct argument count
4367 if (Name
== ConstructorInfo
.ConstructorName
) {
4368 ec
.Report
.SymbolRelatedToPreviousError (queried_type
);
4369 ec
.Report
.Error (1729, loc
,
4370 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4371 TypeManager
.CSharpName (queried_type
), arg_count
);
4373 Error_ArgumentCountWrong (ec
, arg_count
);
4379 if (arg_count
!= 0 && Arguments
.HasDynamic
) {
4380 best_candidate
= null;
4386 // At this point, applicable_type is _one_ of the most derived types
4387 // in the set of types containing the methods in this MethodGroup.
4388 // Filter the candidates so that they only contain methods from the
4389 // most derived types.
4392 int finalized
= 0; // Number of finalized candidates
4395 // Invariant: applicable_type is a most derived type
4397 // We'll try to complete Section 14.5.5.1 for 'applicable_type' by
4398 // eliminating all it's base types. At the same time, we'll also move
4399 // every unrelated type to the end of the array, and pick the next
4400 // 'applicable_type'.
4402 Type next_applicable_type
= null;
4403 int j
= finalized
; // where to put the next finalized candidate
4404 int k
= finalized
; // where to put the next undiscarded candidate
4405 for (int i
= finalized
; i
< candidate_top
; ++i
) {
4406 MethodBase candidate
= (MethodBase
) candidates
[i
];
4407 Type decl_type
= candidate
.DeclaringType
;
4409 if (decl_type
== applicable_type
) {
4410 candidates
[k
++] = candidates
[j
];
4411 candidates
[j
++] = candidates
[i
];
4415 if (IsAncestralType (decl_type
, applicable_type
))
4418 if (next_applicable_type
!= null &&
4419 IsAncestralType (decl_type
, next_applicable_type
))
4422 candidates
[k
++] = candidates
[i
];
4424 if (next_applicable_type
== null ||
4425 IsAncestralType (next_applicable_type
, decl_type
))
4426 next_applicable_type
= decl_type
;
4429 applicable_type
= next_applicable_type
;
4432 } while (applicable_type
!= null);
4436 // Now we actually find the best method
4439 best_candidate
= (MethodBase
) candidates
[0];
4440 method_params
= candidate_to_form
!= null && candidate_to_form
.Contains (best_candidate
);
4443 // TODO: Broken inverse order of candidates logic does not work with optional
4444 // parameters used for method overrides and I am not going to fix it for SRE
4446 if (candidates_expanded
!= null && candidates_expanded
.Contains (best_candidate
)) {
4447 candidate_args
= (Arguments
) candidates_expanded
[best_candidate
];
4448 arg_count
= candidate_args
.Count
;
4451 for (int ix
= 1; ix
< candidate_top
; ix
++) {
4452 MethodBase candidate
= (MethodBase
) candidates
[ix
];
4454 if (candidate
== best_candidate
)
4457 bool cand_params
= candidate_to_form
!= null && candidate_to_form
.Contains (candidate
);
4459 if (BetterFunction (ec
, candidate_args
, arg_count
,
4460 candidate
, cand_params
,
4461 best_candidate
, method_params
)) {
4462 best_candidate
= candidate
;
4463 method_params
= cand_params
;
4467 // Now check that there are no ambiguities i.e the selected method
4468 // should be better than all the others
4470 MethodBase ambiguous
= null;
4471 for (int ix
= 1; ix
< candidate_top
; ix
++) {
4472 MethodBase candidate
= (MethodBase
) candidates
[ix
];
4474 if (candidate
== best_candidate
)
4477 bool cand_params
= candidate_to_form
!= null && candidate_to_form
.Contains (candidate
);
4478 if (!BetterFunction (ec
, candidate_args
, arg_count
,
4479 best_candidate
, method_params
,
4480 candidate
, cand_params
))
4483 ec
.Report
.SymbolRelatedToPreviousError (candidate
);
4484 ambiguous
= candidate
;
4488 if (ambiguous
!= null) {
4489 Error_AmbiguousCall (ec
, ambiguous
);
4494 // If the method is a virtual function, pick an override closer to the LHS type.
4496 if (!IsBase
&& best_candidate
.IsVirtual
) {
4497 if (TypeManager
.IsOverride (best_candidate
))
4498 throw new InternalErrorException (
4499 "Should not happen. An 'override' method took part in overload resolution: " + best_candidate
);
4501 if (candidate_overrides
!= null) {
4502 Type
[] gen_args
= null;
4503 bool gen_override
= false;
4504 if (TypeManager
.IsGenericMethod (best_candidate
))
4505 gen_args
= TypeManager
.GetGenericArguments (best_candidate
);
4507 foreach (MethodBase candidate
in candidate_overrides
) {
4508 if (TypeManager
.IsGenericMethod (candidate
)) {
4509 if (gen_args
== null)
4512 if (gen_args
.Length
!= TypeManager
.GetGenericArguments (candidate
).Length
)
4515 if (gen_args
!= null)
4519 if (IsOverride (candidate
, best_candidate
)) {
4520 gen_override
= true;
4521 best_candidate
= candidate
;
4525 if (gen_override
&& gen_args
!= null) {
4526 best_candidate
= ((MethodInfo
) best_candidate
).MakeGenericMethod (gen_args
);
4532 // And now check if the arguments are all
4533 // compatible, perform conversions if
4534 // necessary etc. and return if everything is
4537 if (!VerifyArgumentsCompat (ec
, ref candidate_args
, arg_count
, best_candidate
,
4538 method_params
, may_fail
, loc
))
4541 if (best_candidate
== null)
4544 MethodBase the_method
= TypeManager
.DropGenericMethodArguments (best_candidate
);
4545 if (TypeManager
.IsGenericMethodDefinition (the_method
) &&
4546 !ConstraintChecker
.CheckConstraints (ec
, the_method
, best_candidate
, loc
))
4550 // Check ObsoleteAttribute on the best method
4552 ObsoleteAttribute oa
= AttributeTester
.GetMethodObsoleteAttribute (the_method
);
4553 if (oa
!= null && !ec
.IsObsolete
)
4554 AttributeTester
.Report_ObsoleteMessage (oa
, GetSignatureForError (), loc
, ec
.Report
);
4556 IMethodData data
= TypeManager
.GetMethod (the_method
);
4558 data
.SetMemberIsUsed ();
4560 Arguments
= candidate_args
;
4564 bool NoExactMatch (ResolveContext ec
, ref Arguments Arguments
, Hashtable candidate_to_form
)
4566 AParametersCollection pd
= TypeManager
.GetParameterData (best_candidate
);
4567 int arg_count
= Arguments
== null ? 0 : Arguments
.Count
;
4569 if (arg_count
== pd
.Count
|| pd
.HasParams
) {
4570 if (TypeManager
.IsGenericMethodDefinition (best_candidate
)) {
4571 if (type_arguments
== null) {
4572 ec
.Report
.Error (411, loc
,
4573 "The type arguments for method `{0}' cannot be inferred from " +
4574 "the usage. Try specifying the type arguments explicitly",
4575 TypeManager
.CSharpSignature (best_candidate
));
4579 Type
[] g_args
= TypeManager
.GetGenericArguments (best_candidate
);
4580 if (type_arguments
.Count
!= g_args
.Length
) {
4581 ec
.Report
.SymbolRelatedToPreviousError (best_candidate
);
4582 ec
.Report
.Error (305, loc
, "Using the generic method `{0}' requires `{1}' type argument(s)",
4583 TypeManager
.CSharpSignature (best_candidate
),
4584 g_args
.Length
.ToString ());
4588 if (type_arguments
!= null && !TypeManager
.IsGenericMethod (best_candidate
)) {
4589 Error_TypeArgumentsCannotBeUsed (ec
.Report
, loc
);
4594 if (has_inaccessible_candidates_only
) {
4595 if (InstanceExpression
!= null && type
!= ec
.CurrentType
&& TypeManager
.IsNestedFamilyAccessible (ec
.CurrentType
, best_candidate
.DeclaringType
)) {
4596 // Although a derived class can access protected members of
4597 // its base class it cannot do so through an instance of the
4598 // base class (CS1540). If the qualifier_type is a base of the
4599 // ec.CurrentType and the lookup succeeds with the latter one,
4600 // then we are in this situation.
4601 Error_CannotAccessProtected (ec
, loc
, best_candidate
, queried_type
, ec
.CurrentType
);
4603 ec
.Report
.SymbolRelatedToPreviousError (best_candidate
);
4604 ErrorIsInaccesible (loc
, GetSignatureForError (), ec
.Report
);
4608 bool cand_params
= candidate_to_form
!= null && candidate_to_form
.Contains (best_candidate
);
4609 if (!VerifyArgumentsCompat (ec
, ref Arguments
, arg_count
, best_candidate
, cand_params
, false, loc
))
4612 if (has_inaccessible_candidates_only
)
4619 public override void SetTypeArguments (ResolveContext ec
, TypeArguments ta
)
4621 type_arguments
= ta
;
4624 public bool VerifyArgumentsCompat (ResolveContext ec
, ref Arguments arguments
,
4625 int arg_count
, MethodBase method
,
4626 bool chose_params_expanded
,
4627 bool may_fail
, Location loc
)
4629 AParametersCollection pd
= TypeManager
.GetParameterData (method
);
4630 int param_count
= GetApplicableParametersCount (method
, pd
);
4632 int errors
= ec
.Report
.Errors
;
4633 Parameter
.Modifier p_mod
= 0;
4635 int a_idx
= 0, a_pos
= 0;
4637 ArrayList params_initializers
= null;
4638 bool has_unsafe_arg
= method
is MethodInfo
? ((MethodInfo
) method
).ReturnType
.IsPointer
: false;
4640 for (; a_idx
< arg_count
; a_idx
++, ++a_pos
) {
4641 a
= arguments
[a_idx
];
4642 if (p_mod
!= Parameter
.Modifier
.PARAMS
) {
4643 p_mod
= pd
.FixedParameters
[a_idx
].ModFlags
;
4644 pt
= pd
.Types
[a_idx
];
4645 has_unsafe_arg
|= pt
.IsPointer
;
4647 if (p_mod
== Parameter
.Modifier
.PARAMS
) {
4648 if (chose_params_expanded
) {
4649 params_initializers
= new ArrayList (arg_count
- a_idx
);
4650 pt
= TypeManager
.GetElementType (pt
);
4656 // Types have to be identical when ref or out modifer is used
4658 if (a
.Modifier
!= 0 || (p_mod
& ~Parameter
.Modifier
.PARAMS
) != 0) {
4659 if ((p_mod
& ~Parameter
.Modifier
.PARAMS
) != a
.Modifier
)
4662 if (!TypeManager
.IsEqual (a
.Expr
.Type
, pt
))
4667 NamedArgument na
= a
as NamedArgument
;
4669 int name_index
= pd
.GetParameterIndexByName (na
.Name
.Value
);
4670 if (name_index
< 0 || name_index
>= param_count
) {
4671 if (DeclaringType
!= null && TypeManager
.IsDelegateType (DeclaringType
)) {
4672 ec
.Report
.SymbolRelatedToPreviousError (DeclaringType
);
4673 ec
.Report
.Error (1746, na
.Name
.Location
,
4674 "The delegate `{0}' does not contain a parameter named `{1}'",
4675 TypeManager
.CSharpName (DeclaringType
), na
.Name
.Value
);
4677 ec
.Report
.SymbolRelatedToPreviousError (best_candidate
);
4678 ec
.Report
.Error (1739, na
.Name
.Location
,
4679 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
4680 TypeManager
.CSharpSignature (method
), na
.Name
.Value
);
4682 } else if (arguments
[name_index
] != a
) {
4683 if (DeclaringType
!= null && TypeManager
.IsDelegateType (DeclaringType
))
4684 ec
.Report
.SymbolRelatedToPreviousError (DeclaringType
);
4686 ec
.Report
.SymbolRelatedToPreviousError (best_candidate
);
4688 ec
.Report
.Error (1744, na
.Name
.Location
,
4689 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
4695 if (TypeManager
.IsDynamicType (a
.Expr
.Type
))
4698 if (delegate_type
!= null && !Delegate
.IsTypeCovariant (a
.Expr
, pt
))
4701 Expression conv
= Convert
.ImplicitConversion (ec
, a
.Expr
, pt
, loc
);
4706 // Convert params arguments to an array initializer
4708 if (params_initializers
!= null) {
4709 // we choose to use 'a.Expr' rather than 'conv' so that
4710 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
4711 params_initializers
.Add (a
.Expr
);
4712 arguments
.RemoveAt (a_idx
--);
4717 // Update the argument with the implicit conversion
4721 if (a_idx
!= arg_count
) {
4722 if (!may_fail
&& ec
.Report
.Errors
== errors
) {
4723 if (CustomErrorHandler
!= null)
4724 CustomErrorHandler
.NoExactMatch (ec
, best_candidate
);
4726 Error_InvalidArguments (ec
, loc
, a_pos
, method
, a
, pd
, pt
);
4732 // Fill not provided arguments required by params modifier
4734 if (params_initializers
== null && pd
.HasParams
&& arg_count
+ 1 == param_count
) {
4735 if (arguments
== null)
4736 arguments
= new Arguments (1);
4738 pt
= pd
.Types
[param_count
- 1];
4739 pt
= TypeManager
.GetElementType (pt
);
4740 has_unsafe_arg
|= pt
.IsPointer
;
4741 params_initializers
= new ArrayList (0);
4745 // Append an array argument with all params arguments
4747 if (params_initializers
!= null) {
4748 arguments
.Add (new Argument (
4749 new ArrayCreation (new TypeExpression (pt
, loc
), "[]",
4750 params_initializers
, loc
).Resolve (ec
)));
4754 if (arg_count
< param_count
) {
4756 Error_ArgumentCountWrong (ec
, arg_count
);
4760 if (has_unsafe_arg
&& !ec
.IsUnsafe
) {
4762 UnsafeError (ec
, loc
);
4770 public class ConstantExpr
: MemberExpr
4774 public ConstantExpr (FieldInfo constant
, Location loc
)
4776 this.constant
= constant
;
4780 public override string Name
{
4781 get { throw new NotImplementedException (); }
4784 public override bool IsInstance
{
4785 get { return !IsStatic; }
4788 public override bool IsStatic
{
4789 get { return constant.IsStatic; }
4792 public override Type DeclaringType
{
4793 get { return constant.DeclaringType; }
4796 public override MemberExpr
ResolveMemberAccess (ResolveContext ec
, Expression left
, Location loc
, SimpleName original
)
4798 constant
= TypeManager
.GetGenericFieldDefinition (constant
);
4800 IConstant ic
= TypeManager
.GetConstant (constant
);
4802 if (constant
.IsLiteral
) {
4803 ic
= new ExternalConstant (constant
);
4805 ic
= ExternalConstant
.CreateDecimal (constant
);
4806 // HACK: decimal field was not resolved as constant
4808 return new FieldExpr (constant
, loc
).ResolveMemberAccess (ec
, left
, loc
, original
);
4810 TypeManager
.RegisterConstant (constant
, ic
);
4813 return base.ResolveMemberAccess (ec
, left
, loc
, original
);
4816 public override Expression
CreateExpressionTree (ResolveContext ec
)
4818 throw new NotSupportedException ("ET");
4821 public override Expression
DoResolve (ResolveContext ec
)
4823 IConstant ic
= TypeManager
.GetConstant (constant
);
4824 if (ic
.ResolveValue ()) {
4826 ic
.CheckObsoleteness (loc
);
4829 return ic
.CreateConstantReference (loc
);
4832 public override void Emit (EmitContext ec
)
4834 throw new NotSupportedException ();
4837 public override string GetSignatureForError ()
4839 return TypeManager
.GetFullNameSignature (constant
);
4844 /// Fully resolved expression that evaluates to a Field
4846 public class FieldExpr
: MemberExpr
, IDynamicAssign
, IMemoryLocation
, IVariableReference
{
4847 public FieldInfo FieldInfo
;
4848 readonly Type constructed_generic_type
;
4849 VariableInfo variable_info
;
4851 LocalTemporary temp
;
4854 protected FieldExpr (Location l
)
4859 public FieldExpr (FieldInfo fi
, Location l
)
4862 type
= TypeManager
.TypeToCoreType (fi
.FieldType
);
4866 public FieldExpr (FieldInfo fi
, Type genericType
, Location l
)
4869 if (TypeManager
.IsGenericTypeDefinition (genericType
))
4871 this.constructed_generic_type
= genericType
;
4874 public override string Name
{
4876 return FieldInfo
.Name
;
4880 public override bool IsInstance
{
4882 return !FieldInfo
.IsStatic
;
4886 public override bool IsStatic
{
4888 return FieldInfo
.IsStatic
;
4892 public override Type DeclaringType
{
4894 return FieldInfo
.DeclaringType
;
4898 public override string GetSignatureForError ()
4900 return TypeManager
.GetFullNameSignature (FieldInfo
);
4903 public VariableInfo VariableInfo
{
4905 return variable_info
;
4909 public override MemberExpr
ResolveMemberAccess (ResolveContext ec
, Expression left
, Location loc
,
4910 SimpleName original
)
4912 FieldInfo fi
= TypeManager
.GetGenericFieldDefinition (FieldInfo
);
4913 Type t
= fi
.FieldType
;
4915 if (t
.IsPointer
&& !ec
.IsUnsafe
) {
4916 UnsafeError (ec
, loc
);
4919 return base.ResolveMemberAccess (ec
, left
, loc
, original
);
4922 public void SetHasAddressTaken ()
4924 IVariableReference vr
= InstanceExpression
as IVariableReference
;
4926 vr
.SetHasAddressTaken ();
4929 public override Expression
CreateExpressionTree (ResolveContext ec
)
4931 Expression instance
;
4932 if (InstanceExpression
== null) {
4933 instance
= new NullLiteral (loc
);
4935 instance
= InstanceExpression
.CreateExpressionTree (ec
);
4938 Arguments args
= Arguments
.CreateForExpressionTree (ec
, null,
4940 CreateTypeOfExpression ());
4942 return CreateExpressionFactoryCall (ec
, "Field", args
);
4945 public Expression
CreateTypeOfExpression ()
4947 return new TypeOfField (GetConstructedFieldInfo (), loc
);
4950 override public Expression
DoResolve (ResolveContext ec
)
4952 return DoResolve (ec
, false, false);
4955 Expression
DoResolve (ResolveContext ec
, bool lvalue_instance
, bool out_access
)
4957 if (!FieldInfo
.IsStatic
){
4958 if (InstanceExpression
== null){
4960 // This can happen when referencing an instance field using
4961 // a fully qualified type expression: TypeName.InstanceField = xxx
4963 SimpleName
.Error_ObjectRefRequired (ec
, loc
, GetSignatureForError ());
4967 // Resolve the field's instance expression while flow analysis is turned
4968 // off: when accessing a field "a.b", we must check whether the field
4969 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4971 if (lvalue_instance
) {
4972 using (ec
.With (ResolveContext
.Options
.DoFlowAnalysis
, false)) {
4973 Expression right_side
=
4974 out_access
? EmptyExpression
.LValueMemberOutAccess
: EmptyExpression
.LValueMemberAccess
;
4976 if (InstanceExpression
!= EmptyExpression
.Null
)
4977 InstanceExpression
= InstanceExpression
.ResolveLValue (ec
, right_side
);
4980 ResolveFlags rf
= ResolveFlags
.VariableOrValue
| ResolveFlags
.DisableFlowAnalysis
;
4982 if (InstanceExpression
!= EmptyExpression
.Null
)
4983 InstanceExpression
= InstanceExpression
.Resolve (ec
, rf
);
4986 if (InstanceExpression
== null)
4989 using (ec
.Set (ResolveContext
.Options
.OmitStructFlowAnalysis
)) {
4990 InstanceExpression
.CheckMarshalByRefAccess (ec
);
4994 // TODO: the code above uses some non-standard multi-resolve rules
4995 if (eclass
!= ExprClass
.Invalid
)
4998 if (!ec
.IsObsolete
) {
4999 FieldBase f
= TypeManager
.GetField (FieldInfo
);
5001 f
.CheckObsoleteness (loc
);
5003 ObsoleteAttribute oa
= AttributeTester
.GetMemberObsoleteAttribute (FieldInfo
);
5005 AttributeTester
.Report_ObsoleteMessage (oa
, TypeManager
.GetFullNameSignature (FieldInfo
), loc
, ec
.Report
);
5009 IFixedBuffer fb
= AttributeTester
.GetFixedBuffer (FieldInfo
);
5010 IVariableReference
var = InstanceExpression
as IVariableReference
;
5013 IFixedExpression fe
= InstanceExpression
as IFixedExpression
;
5014 if (!ec
.HasSet (ResolveContext
.Options
.FixedInitializerScope
) && (fe
== null || !fe
.IsFixed
)) {
5015 ec
.Report
.Error (1666, loc
, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
5018 if (InstanceExpression
.eclass
!= ExprClass
.Variable
) {
5019 ec
.Report
.SymbolRelatedToPreviousError (FieldInfo
);
5020 ec
.Report
.Error (1708, loc
, "`{0}': Fixed size buffers can only be accessed through locals or fields",
5021 TypeManager
.GetFullNameSignature (FieldInfo
));
5022 } else if (var != null && var.IsHoisted
) {
5023 AnonymousMethodExpression
.Error_AddressOfCapturedVar (ec
, var, loc
);
5026 return new FixedBufferPtr (this, fb
.ElementType
, loc
).Resolve (ec
);
5029 eclass
= ExprClass
.Variable
;
5031 // If the instance expression is a local variable or parameter.
5032 if (var == null || var.VariableInfo
== null)
5035 VariableInfo vi
= var.VariableInfo
;
5036 if (!vi
.IsFieldAssigned (ec
, FieldInfo
.Name
, loc
))
5039 variable_info
= vi
.GetSubStruct (FieldInfo
.Name
);
5040 eclass
= ExprClass
.Variable
;
5044 static readonly int [] codes
= {
5045 191, // instance, write access
5046 192, // instance, out access
5047 198, // static, write access
5048 199, // static, out access
5049 1648, // member of value instance, write access
5050 1649, // member of value instance, out access
5051 1650, // member of value static, write access
5052 1651 // member of value static, out access
5055 static readonly string [] msgs
= {
5056 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
5057 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5058 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5059 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
5060 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
5061 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5062 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5063 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
5066 // The return value is always null. Returning a value simplifies calling code.
5067 Expression
Report_AssignToReadonly (ResolveContext ec
, Expression right_side
)
5070 if (right_side
== EmptyExpression
.OutAccess
.Instance
|| right_side
== EmptyExpression
.LValueMemberOutAccess
)
5074 if (right_side
== EmptyExpression
.LValueMemberAccess
|| right_side
== EmptyExpression
.LValueMemberOutAccess
)
5076 ec
.Report
.Error (codes
[i
], loc
, msgs
[i
], GetSignatureForError ());
5081 override public Expression
DoResolveLValue (ResolveContext ec
, Expression right_side
)
5083 IVariableReference
var = InstanceExpression
as IVariableReference
;
5084 if (var != null && var.VariableInfo
!= null)
5085 var.VariableInfo
.SetFieldAssigned (ec
, FieldInfo
.Name
);
5087 bool lvalue_instance
= !FieldInfo
.IsStatic
&& TypeManager
.IsValueType (FieldInfo
.DeclaringType
);
5088 bool out_access
= right_side
== EmptyExpression
.OutAccess
.Instance
|| right_side
== EmptyExpression
.LValueMemberOutAccess
;
5090 Expression e
= DoResolve (ec
, lvalue_instance
, out_access
);
5095 FieldBase fb
= TypeManager
.GetField (FieldInfo
);
5099 if ((right_side
== EmptyExpression
.UnaryAddress
|| right_side
== EmptyExpression
.OutAccess
.Instance
) &&
5100 (fb
.ModFlags
& Modifiers
.VOLATILE
) != 0) {
5101 ec
.Report
.Warning (420, 1, loc
,
5102 "`{0}': A volatile field references will not be treated as volatile",
5103 fb
.GetSignatureForError ());
5107 if (FieldInfo
.IsInitOnly
) {
5108 // InitOnly fields can only be assigned in constructors or initializers
5109 if (!ec
.HasAny (ResolveContext
.Options
.FieldInitializerScope
| ResolveContext
.Options
.ConstructorScope
))
5110 return Report_AssignToReadonly (ec
, right_side
);
5112 if (ec
.HasSet (ResolveContext
.Options
.ConstructorScope
)) {
5113 Type ctype
= ec
.CurrentType
;
5115 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
5116 if (!TypeManager
.IsEqual (ctype
, FieldInfo
.DeclaringType
))
5117 return Report_AssignToReadonly (ec
, right_side
);
5118 // static InitOnly fields cannot be assigned-to in an instance constructor
5119 if (IsStatic
&& !ec
.IsStatic
)
5120 return Report_AssignToReadonly (ec
, right_side
);
5121 // instance constructors can't modify InitOnly fields of other instances of the same type
5122 if (!IsStatic
&& !(InstanceExpression
is This
))
5123 return Report_AssignToReadonly (ec
, right_side
);
5127 if (right_side
== EmptyExpression
.OutAccess
.Instance
&&
5128 !IsStatic
&& !(InstanceExpression
is This
) && TypeManager
.mbr_type
!= null && TypeManager
.IsSubclassOf (DeclaringType
, TypeManager
.mbr_type
)) {
5129 ec
.Report
.SymbolRelatedToPreviousError (DeclaringType
);
5130 ec
.Report
.Warning (197, 1, loc
,
5131 "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",
5132 GetSignatureForError ());
5135 eclass
= ExprClass
.Variable
;
5139 bool is_marshal_by_ref ()
5141 return !IsStatic
&& TypeManager
.IsStruct (Type
) && TypeManager
.mbr_type
!= null && TypeManager
.IsSubclassOf (DeclaringType
, TypeManager
.mbr_type
);
5144 public override void CheckMarshalByRefAccess (ResolveContext ec
)
5146 if (is_marshal_by_ref () && !(InstanceExpression
is This
)) {
5147 ec
.Report
.SymbolRelatedToPreviousError (DeclaringType
);
5148 ec
.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",
5149 GetSignatureForError ());
5153 public override int GetHashCode ()
5155 return FieldInfo
.GetHashCode ();
5158 public bool IsFixed
{
5161 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
5163 IVariableReference variable
= InstanceExpression
as IVariableReference
;
5164 if (variable
!= null)
5165 return TypeManager
.IsStruct (InstanceExpression
.Type
) && variable
.IsFixed
;
5167 IFixedExpression fe
= InstanceExpression
as IFixedExpression
;
5168 return fe
!= null && fe
.IsFixed
;
5172 public bool IsHoisted
{
5174 IVariableReference hv
= InstanceExpression
as IVariableReference
;
5175 return hv
!= null && hv
.IsHoisted
;
5179 public override bool Equals (object obj
)
5181 FieldExpr fe
= obj
as FieldExpr
;
5185 if (FieldInfo
!= fe
.FieldInfo
)
5188 if (InstanceExpression
== null || fe
.InstanceExpression
== null)
5191 return InstanceExpression
.Equals (fe
.InstanceExpression
);
5194 public void Emit (EmitContext ec
, bool leave_copy
)
5196 ILGenerator ig
= ec
.ig
;
5197 bool is_volatile
= false;
5199 FieldBase f
= TypeManager
.GetField (FieldInfo
);
5201 if ((f
.ModFlags
& Modifiers
.VOLATILE
) != 0)
5204 f
.SetMemberIsUsed ();
5207 if (FieldInfo
.IsStatic
){
5209 ig
.Emit (OpCodes
.Volatile
);
5211 ig
.Emit (OpCodes
.Ldsfld
, GetConstructedFieldInfo ());
5214 EmitInstance (ec
, false);
5216 // Optimization for build-in types
5217 if (TypeManager
.IsStruct (type
) && TypeManager
.IsEqual (type
, ec
.MemberContext
.CurrentType
)) {
5218 LoadFromPtr (ig
, type
);
5220 IFixedBuffer ff
= AttributeTester
.GetFixedBuffer (FieldInfo
);
5222 ig
.Emit (OpCodes
.Ldflda
, GetConstructedFieldInfo ());
5223 ig
.Emit (OpCodes
.Ldflda
, ff
.Element
);
5226 ig
.Emit (OpCodes
.Volatile
);
5228 ig
.Emit (OpCodes
.Ldfld
, GetConstructedFieldInfo ());
5234 ec
.ig
.Emit (OpCodes
.Dup
);
5235 if (!FieldInfo
.IsStatic
) {
5236 temp
= new LocalTemporary (this.Type
);
5242 public void EmitAssign (EmitContext ec
, Expression source
, bool leave_copy
, bool prepare_for_load
)
5244 FieldAttributes fa
= FieldInfo
.Attributes
;
5245 bool is_static
= (fa
& FieldAttributes
.Static
) != 0;
5246 ILGenerator ig
= ec
.ig
;
5248 prepared
= prepare_for_load
;
5249 EmitInstance (ec
, prepared
);
5253 ec
.ig
.Emit (OpCodes
.Dup
);
5254 if (!FieldInfo
.IsStatic
) {
5255 temp
= new LocalTemporary (this.Type
);
5260 FieldBase f
= TypeManager
.GetField (FieldInfo
);
5262 if ((f
.ModFlags
& Modifiers
.VOLATILE
) != 0)
5263 ig
.Emit (OpCodes
.Volatile
);
5269 ig
.Emit (OpCodes
.Stsfld
, GetConstructedFieldInfo ());
5271 ig
.Emit (OpCodes
.Stfld
, GetConstructedFieldInfo ());
5280 public override void Emit (EmitContext ec
)
5285 public override void EmitSideEffect (EmitContext ec
)
5287 FieldBase f
= TypeManager
.GetField (FieldInfo
);
5288 bool is_volatile
= f
!= null && (f
.ModFlags
& Modifiers
.VOLATILE
) != 0;
5290 if (is_volatile
|| is_marshal_by_ref ())
5291 base.EmitSideEffect (ec
);
5294 public override void Error_VariableIsUsedBeforeItIsDeclared (Report r
, string name
)
5297 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the field `{1}'",
5298 name
, GetSignatureForError ());
5301 public void AddressOf (EmitContext ec
, AddressOp mode
)
5303 ILGenerator ig
= ec
.ig
;
5305 FieldBase f
= TypeManager
.GetField (FieldInfo
);
5307 if ((mode
& AddressOp
.Store
) != 0)
5309 if ((mode
& AddressOp
.Load
) != 0)
5310 f
.SetMemberIsUsed ();
5314 // Handle initonly fields specially: make a copy and then
5315 // get the address of the copy.
5318 if (FieldInfo
.IsInitOnly
){
5320 if (ec
.HasSet (EmitContext
.Options
.ConstructorScope
)){
5321 if (FieldInfo
.IsStatic
){
5333 local
= ig
.DeclareLocal (type
);
5334 ig
.Emit (OpCodes
.Stloc
, local
);
5335 ig
.Emit (OpCodes
.Ldloca
, local
);
5340 if (FieldInfo
.IsStatic
){
5341 ig
.Emit (OpCodes
.Ldsflda
, GetConstructedFieldInfo ());
5344 EmitInstance (ec
, false);
5345 ig
.Emit (OpCodes
.Ldflda
, GetConstructedFieldInfo ());
5349 FieldInfo
GetConstructedFieldInfo ()
5351 if (constructed_generic_type
== null)
5354 return TypeBuilder
.GetField (constructed_generic_type
, FieldInfo
);
5358 public SLE
.Expression
MakeAssignExpression (BuilderContext ctx
)
5360 return MakeExpression (ctx
);
5363 public override SLE
.Expression
MakeExpression (BuilderContext ctx
)
5365 return SLE
.Expression
.Field (InstanceExpression
.MakeExpression (ctx
), FieldInfo
);
5369 public override void MutateHoistedGenericType (AnonymousMethodStorey storey
)
5371 FieldInfo
= storey
.MutateField (FieldInfo
);
5372 base.MutateHoistedGenericType (storey
);
5378 /// Expression that evaluates to a Property. The Assign class
5379 /// might set the `Value' expression if we are in an assignment.
5381 /// This is not an LValue because we need to re-write the expression, we
5382 /// can not take data from the stack and store it.
5384 public class PropertyExpr
: MemberExpr
, IDynamicAssign
5386 public readonly PropertyInfo PropertyInfo
;
5387 MethodInfo getter
, setter
;
5391 TypeArguments targs
;
5393 LocalTemporary temp
;
5396 public PropertyExpr (Type container_type
, PropertyInfo pi
, Location l
)
5399 eclass
= ExprClass
.PropertyAccess
;
5403 type
= TypeManager
.TypeToCoreType (pi
.PropertyType
);
5405 ResolveAccessors (container_type
);
5408 public override string Name
{
5410 return PropertyInfo
.Name
;
5414 public override bool IsInstance
{
5420 public override bool IsStatic
{
5426 public override Expression
CreateExpressionTree (ResolveContext ec
)
5429 if (IsSingleDimensionalArrayLength ()) {
5430 args
= new Arguments (1);
5431 args
.Add (new Argument (InstanceExpression
.CreateExpressionTree (ec
)));
5432 return CreateExpressionFactoryCall (ec
, "ArrayLength", args
);
5436 Error_BaseAccessInExpressionTree (ec
, loc
);
5440 args
= new Arguments (2);
5441 if (InstanceExpression
== null)
5442 args
.Add (new Argument (new NullLiteral (loc
)));
5444 args
.Add (new Argument (InstanceExpression
.CreateExpressionTree (ec
)));
5445 args
.Add (new Argument (new TypeOfMethod (getter
, loc
)));
5446 return CreateExpressionFactoryCall (ec
, "Property", args
);
5449 public Expression
CreateSetterTypeOfExpression ()
5451 return new TypeOfMethod (setter
, loc
);
5454 public override Type DeclaringType
{
5456 return PropertyInfo
.DeclaringType
;
5460 public override string GetSignatureForError ()
5462 return TypeManager
.GetFullNameSignature (PropertyInfo
);
5465 void FindAccessors (Type invocation_type
)
5467 const BindingFlags flags
= BindingFlags
.Public
| BindingFlags
.NonPublic
|
5468 BindingFlags
.Static
| BindingFlags
.Instance
|
5469 BindingFlags
.DeclaredOnly
;
5471 Type current
= PropertyInfo
.DeclaringType
;
5472 for (; current
!= null; current
= current
.BaseType
) {
5473 MemberInfo
[] group = TypeManager
.MemberLookup (
5474 invocation_type
, invocation_type
, current
,
5475 MemberTypes
.Property
, flags
, PropertyInfo
.Name
, null);
5480 if (group.Length
!= 1)
5481 // Oooops, can this ever happen ?
5484 PropertyInfo pi
= (PropertyInfo
) group [0];
5487 getter
= pi
.GetGetMethod (true);
5490 setter
= pi
.GetSetMethod (true);
5492 MethodInfo accessor
= getter
!= null ? getter
: setter
;
5494 if (!accessor
.IsVirtual
)
5500 // We also perform the permission checking here, as the PropertyInfo does not
5501 // hold the information for the accessibility of its setter/getter
5503 // TODO: Refactor to use some kind of cache together with GetPropertyFromAccessor
5504 void ResolveAccessors (Type container_type
)
5506 FindAccessors (container_type
);
5508 if (getter
!= null) {
5509 MethodBase the_getter
= TypeManager
.DropGenericMethodArguments (getter
);
5510 IMethodData md
= TypeManager
.GetMethod (the_getter
);
5512 md
.SetMemberIsUsed ();
5514 is_static
= getter
.IsStatic
;
5517 if (setter
!= null) {
5518 MethodBase the_setter
= TypeManager
.DropGenericMethodArguments (setter
);
5519 IMethodData md
= TypeManager
.GetMethod (the_setter
);
5521 md
.SetMemberIsUsed ();
5523 is_static
= setter
.IsStatic
;
5528 public SLE
.Expression
MakeAssignExpression (BuilderContext ctx
)
5530 return SLE
.Expression
.Property (InstanceExpression
.MakeExpression (ctx
), setter
);
5533 public override SLE
.Expression
MakeExpression (BuilderContext ctx
)
5535 return SLE
.Expression
.Property (InstanceExpression
.MakeExpression (ctx
), getter
);
5539 public override void MutateHoistedGenericType (AnonymousMethodStorey storey
)
5541 if (InstanceExpression
!= null)
5542 InstanceExpression
.MutateHoistedGenericType (storey
);
5544 type
= storey
.MutateType (type
);
5546 getter
= storey
.MutateGenericMethod (getter
);
5548 setter
= storey
.MutateGenericMethod (setter
);
5551 bool InstanceResolve (ResolveContext ec
, bool lvalue_instance
, bool must_do_cs1540_check
)
5554 InstanceExpression
= null;
5558 if (InstanceExpression
== null) {
5559 SimpleName
.Error_ObjectRefRequired (ec
, loc
, GetSignatureForError ());
5563 InstanceExpression
= InstanceExpression
.DoResolve (ec
);
5564 if (lvalue_instance
&& InstanceExpression
!= null)
5565 InstanceExpression
= InstanceExpression
.ResolveLValue (ec
, EmptyExpression
.LValueMemberAccess
);
5567 if (InstanceExpression
== null)
5570 InstanceExpression
.CheckMarshalByRefAccess (ec
);
5572 if (must_do_cs1540_check
&& (InstanceExpression
!= EmptyExpression
.Null
) &&
5573 !TypeManager
.IsInstantiationOfSameGenericType (InstanceExpression
.Type
, ec
.CurrentType
) &&
5574 !TypeManager
.IsNestedChildOf (ec
.CurrentType
, InstanceExpression
.Type
) &&
5575 !TypeManager
.IsSubclassOf (InstanceExpression
.Type
, ec
.CurrentType
)) {
5576 ec
.Report
.SymbolRelatedToPreviousError (PropertyInfo
);
5577 Error_CannotAccessProtected (ec
, loc
, PropertyInfo
, InstanceExpression
.Type
, ec
.CurrentType
);
5584 void Error_PropertyNotFound (ResolveContext ec
, MethodInfo mi
, bool getter
)
5586 // TODO: correctly we should compare arguments but it will lead to bigger changes
5587 if (mi
is MethodBuilder
) {
5588 Error_TypeDoesNotContainDefinition (ec
, loc
, PropertyInfo
.DeclaringType
, Name
);
5592 StringBuilder sig
= new StringBuilder (TypeManager
.CSharpName (mi
.DeclaringType
));
5594 AParametersCollection iparams
= TypeManager
.GetParameterData (mi
);
5595 sig
.Append (getter
? "get_" : "set_");
5597 sig
.Append (iparams
.GetSignatureForError ());
5599 ec
.Report
.SymbolRelatedToPreviousError (mi
);
5600 ec
.Report
.Error (1546, loc
, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
5601 Name
, sig
.ToString ());
5604 public bool IsAccessibleFrom (Type invocation_type
, bool lvalue
)
5607 MethodInfo accessor
= lvalue
? setter
: getter
;
5608 if (accessor
== null && lvalue
)
5610 return accessor
!= null && IsAccessorAccessible (invocation_type
, accessor
, out dummy
);
5613 bool IsSingleDimensionalArrayLength ()
5615 if (DeclaringType
!= TypeManager
.array_type
|| getter
== null || Name
!= "Length")
5618 string t_name
= InstanceExpression
.Type
.Name
;
5619 int t_name_len
= t_name
.Length
;
5620 return t_name_len
> 2 && t_name
[t_name_len
- 2] == '[';
5623 public override Expression
DoResolve (ResolveContext ec
)
5628 bool must_do_cs1540_check
= false;
5629 ec
.Report
.DisableReporting ();
5630 bool res
= ResolveGetter (ec
, ref must_do_cs1540_check
);
5631 ec
.Report
.EnableReporting ();
5634 if (InstanceExpression
!= null) {
5635 Type expr_type
= InstanceExpression
.Type
;
5636 ExtensionMethodGroupExpr ex_method_lookup
= ec
.LookupExtensionMethod (expr_type
, Name
, loc
);
5637 if (ex_method_lookup
!= null) {
5638 ex_method_lookup
.ExtensionExpression
= InstanceExpression
;
5639 ex_method_lookup
.SetTypeArguments (ec
, targs
);
5640 return ex_method_lookup
.DoResolve (ec
);
5644 ResolveGetter (ec
, ref must_do_cs1540_check
);
5648 if (!InstanceResolve (ec
, false, must_do_cs1540_check
))
5652 // Only base will allow this invocation to happen.
5654 if (IsBase
&& getter
.IsAbstract
) {
5655 Error_CannotCallAbstractBase (ec
, TypeManager
.GetFullNameSignature (PropertyInfo
));
5658 if (PropertyInfo
.PropertyType
.IsPointer
&& !ec
.IsUnsafe
){
5659 UnsafeError (ec
, loc
);
5662 if (!ec
.IsObsolete
) {
5663 PropertyBase pb
= TypeManager
.GetProperty (PropertyInfo
);
5665 pb
.CheckObsoleteness (loc
);
5667 ObsoleteAttribute oa
= AttributeTester
.GetMemberObsoleteAttribute (PropertyInfo
);
5669 AttributeTester
.Report_ObsoleteMessage (oa
, GetSignatureForError (), loc
, ec
.Report
);
5678 override public Expression
DoResolveLValue (ResolveContext ec
, Expression right_side
)
5680 if (right_side
== EmptyExpression
.OutAccess
.Instance
) {
5681 if (ec
.CurrentBlock
.Toplevel
.GetParameterReference (PropertyInfo
.Name
, loc
) is MemberAccess
) {
5682 ec
.Report
.Error (1939, loc
, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5685 right_side
.DoResolveLValue (ec
, this);
5690 if (right_side
== EmptyExpression
.LValueMemberAccess
|| right_side
== EmptyExpression
.LValueMemberOutAccess
) {
5691 Error_CannotModifyIntermediateExpressionValue (ec
);
5694 if (setter
== null){
5696 // The following condition happens if the PropertyExpr was
5697 // created, but is invalid (ie, the property is inaccessible),
5698 // and we did not want to embed the knowledge about this in
5699 // the caller routine. This only avoids double error reporting.
5704 if (ec
.CurrentBlock
.Toplevel
.GetParameterReference (PropertyInfo
.Name
, loc
) is MemberAccess
) {
5705 ec
.Report
.Error (1947, loc
, "A range variable `{0}' cannot be assigned to. Consider using `let' clause to store the value",
5708 ec
.Report
.Error (200, loc
, "Property or indexer `{0}' cannot be assigned to (it is read only)",
5709 GetSignatureForError ());
5714 if (targs
!= null) {
5715 base.SetTypeArguments (ec
, targs
);
5719 if (TypeManager
.GetParameterData (setter
).Count
!= 1){
5720 Error_PropertyNotFound (ec
, setter
, false);
5724 bool must_do_cs1540_check
;
5725 if (!IsAccessorAccessible (ec
.CurrentType
, setter
, out must_do_cs1540_check
)) {
5726 PropertyBase
.PropertyMethod pm
= TypeManager
.GetMethod (setter
) as PropertyBase
.PropertyMethod
;
5727 if (pm
!= null && pm
.HasCustomAccessModifier
) {
5728 ec
.Report
.SymbolRelatedToPreviousError (pm
);
5729 ec
.Report
.Error (272, loc
, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5730 TypeManager
.CSharpSignature (setter
));
5733 ec
.Report
.SymbolRelatedToPreviousError (setter
);
5734 ErrorIsInaccesible (loc
, TypeManager
.CSharpSignature (setter
), ec
.Report
);
5739 if (!InstanceResolve (ec
, TypeManager
.IsStruct (PropertyInfo
.DeclaringType
), must_do_cs1540_check
))
5743 // Only base will allow this invocation to happen.
5745 if (IsBase
&& setter
.IsAbstract
){
5746 Error_CannotCallAbstractBase (ec
, TypeManager
.GetFullNameSignature (PropertyInfo
));
5749 if (PropertyInfo
.PropertyType
.IsPointer
&& !ec
.IsUnsafe
) {
5750 UnsafeError (ec
, loc
);
5753 if (!ec
.IsObsolete
) {
5754 PropertyBase pb
= TypeManager
.GetProperty (PropertyInfo
);
5756 pb
.CheckObsoleteness (loc
);
5758 ObsoleteAttribute oa
= AttributeTester
.GetMemberObsoleteAttribute (PropertyInfo
);
5760 AttributeTester
.Report_ObsoleteMessage (oa
, GetSignatureForError (), loc
, ec
.Report
);
5767 public override void Emit (EmitContext ec
)
5772 public void Emit (EmitContext ec
, bool leave_copy
)
5775 // Special case: length of single dimension array property is turned into ldlen
5777 if (IsSingleDimensionalArrayLength ()) {
5779 EmitInstance (ec
, false);
5780 ec
.ig
.Emit (OpCodes
.Ldlen
);
5781 ec
.ig
.Emit (OpCodes
.Conv_I4
);
5785 Invocation
.EmitCall (ec
, IsBase
, InstanceExpression
, getter
, null, loc
, prepared
, false);
5788 ec
.ig
.Emit (OpCodes
.Dup
);
5790 temp
= new LocalTemporary (this.Type
);
5797 // Implements the IAssignMethod interface for assignments
5799 public void EmitAssign (EmitContext ec
, Expression source
, bool leave_copy
, bool prepare_for_load
)
5801 Expression my_source
= source
;
5803 if (prepare_for_load
) {
5808 ec
.ig
.Emit (OpCodes
.Dup
);
5810 temp
= new LocalTemporary (this.Type
);
5814 } else if (leave_copy
) {
5816 temp
= new LocalTemporary (this.Type
);
5821 Arguments args
= new Arguments (1);
5822 args
.Add (new Argument (my_source
));
5824 Invocation
.EmitCall (ec
, IsBase
, InstanceExpression
, setter
, args
, loc
, false, prepared
);
5832 bool ResolveGetter (ResolveContext ec
, ref bool must_do_cs1540_check
)
5834 if (targs
!= null) {
5835 base.SetTypeArguments (ec
, targs
);
5839 if (getter
!= null) {
5840 if (TypeManager
.GetParameterData (getter
).Count
!= 0) {
5841 Error_PropertyNotFound (ec
, getter
, true);
5846 if (getter
== null) {
5848 // The following condition happens if the PropertyExpr was
5849 // created, but is invalid (ie, the property is inaccessible),
5850 // and we did not want to embed the knowledge about this in
5851 // the caller routine. This only avoids double error reporting.
5856 if (InstanceExpression
!= EmptyExpression
.Null
) {
5857 ec
.Report
.Error (154, loc
, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5858 TypeManager
.GetFullNameSignature (PropertyInfo
));
5863 if (getter
!= null &&
5864 !IsAccessorAccessible (ec
.CurrentType
, getter
, out must_do_cs1540_check
)) {
5865 PropertyBase
.PropertyMethod pm
= TypeManager
.GetMethod (getter
) as PropertyBase
.PropertyMethod
;
5866 if (pm
!= null && pm
.HasCustomAccessModifier
) {
5867 ec
.Report
.SymbolRelatedToPreviousError (pm
);
5868 ec
.Report
.Error (271, loc
, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5869 TypeManager
.CSharpSignature (getter
));
5871 ec
.Report
.SymbolRelatedToPreviousError (getter
);
5872 ErrorIsInaccesible (loc
, TypeManager
.CSharpSignature (getter
), ec
.Report
);
5881 public override void SetTypeArguments (ResolveContext ec
, TypeArguments ta
)
5888 /// Fully resolved expression that evaluates to an Event
5890 public class EventExpr
: MemberExpr
{
5891 public readonly EventInfo EventInfo
;
5894 MethodInfo add_accessor
, remove_accessor
;
5896 public EventExpr (EventInfo ei
, Location loc
)
5900 eclass
= ExprClass
.EventAccess
;
5902 add_accessor
= TypeManager
.GetAddMethod (ei
);
5903 remove_accessor
= TypeManager
.GetRemoveMethod (ei
);
5904 if (add_accessor
.IsStatic
|| remove_accessor
.IsStatic
)
5907 if (EventInfo
is MyEventBuilder
){
5908 MyEventBuilder eb
= (MyEventBuilder
) EventInfo
;
5909 type
= eb
.EventType
;
5912 type
= EventInfo
.EventHandlerType
;
5915 public override string Name
{
5917 return EventInfo
.Name
;
5921 public override bool IsInstance
{
5927 public override bool IsStatic
{
5933 public override Type DeclaringType
{
5935 return EventInfo
.DeclaringType
;
5939 public void Error_AssignmentEventOnly (ResolveContext ec
)
5941 ec
.Report
.Error (79, loc
, "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5942 GetSignatureForError ());
5945 public override MemberExpr
ResolveMemberAccess (ResolveContext ec
, Expression left
, Location loc
,
5946 SimpleName original
)
5949 // If the event is local to this class, we transform ourselves into a FieldExpr
5952 if (EventInfo
.DeclaringType
== ec
.CurrentType
||
5953 TypeManager
.IsNestedChildOf(ec
.CurrentType
, EventInfo
.DeclaringType
)) {
5955 // TODO: Breaks dynamic binder as currect context fields are imported and not compiled
5956 EventField mi
= TypeManager
.GetEventField (EventInfo
);
5960 mi
.CheckObsoleteness (loc
);
5962 if ((mi
.ModFlags
& (Modifiers
.ABSTRACT
| Modifiers
.EXTERN
)) != 0 && !ec
.HasSet (ResolveContext
.Options
.CompoundAssignmentScope
))
5963 Error_AssignmentEventOnly (ec
);
5965 FieldExpr ml
= new FieldExpr (mi
.BackingField
.FieldBuilder
, loc
);
5967 InstanceExpression
= null;
5969 return ml
.ResolveMemberAccess (ec
, left
, loc
, original
);
5973 if (left
is This
&& !ec
.HasSet (ResolveContext
.Options
.CompoundAssignmentScope
))
5974 Error_AssignmentEventOnly (ec
);
5976 return base.ResolveMemberAccess (ec
, left
, loc
, original
);
5979 bool InstanceResolve (ResolveContext ec
, bool must_do_cs1540_check
)
5982 InstanceExpression
= null;
5986 if (InstanceExpression
== null) {
5987 SimpleName
.Error_ObjectRefRequired (ec
, loc
, GetSignatureForError ());
5991 InstanceExpression
= InstanceExpression
.DoResolve (ec
);
5992 if (InstanceExpression
== null)
5995 if (IsBase
&& add_accessor
.IsAbstract
) {
5996 Error_CannotCallAbstractBase (ec
, TypeManager
.CSharpSignature(add_accessor
));
6001 // This is using the same mechanism as the CS1540 check in PropertyExpr.
6002 // However, in the Event case, we reported a CS0122 instead.
6004 // TODO: Exact copy from PropertyExpr
6006 if (must_do_cs1540_check
&& InstanceExpression
!= EmptyExpression
.Null
&&
6007 !TypeManager
.IsInstantiationOfSameGenericType (InstanceExpression
.Type
, ec
.CurrentType
) &&
6008 !TypeManager
.IsNestedChildOf (ec
.CurrentType
, InstanceExpression
.Type
) &&
6009 !TypeManager
.IsSubclassOf (InstanceExpression
.Type
, ec
.CurrentType
)) {
6010 ec
.Report
.SymbolRelatedToPreviousError (EventInfo
);
6011 ErrorIsInaccesible (loc
, TypeManager
.CSharpSignature (EventInfo
), ec
.Report
);
6018 public bool IsAccessibleFrom (Type invocation_type
)
6021 return IsAccessorAccessible (invocation_type
, add_accessor
, out dummy
) &&
6022 IsAccessorAccessible (invocation_type
, remove_accessor
, out dummy
);
6025 public override Expression
CreateExpressionTree (ResolveContext ec
)
6027 throw new NotSupportedException ("ET");
6030 public override Expression
DoResolveLValue (ResolveContext ec
, Expression right_side
)
6032 // contexts where an LValue is valid have already devolved to FieldExprs
6033 Error_CannotAssign (ec
);
6037 public override Expression
DoResolve (ResolveContext ec
)
6039 bool must_do_cs1540_check
;
6040 if (!(IsAccessorAccessible (ec
.CurrentType
, add_accessor
, out must_do_cs1540_check
) &&
6041 IsAccessorAccessible (ec
.CurrentType
, remove_accessor
, out must_do_cs1540_check
))) {
6042 ec
.Report
.SymbolRelatedToPreviousError (EventInfo
);
6043 ErrorIsInaccesible (loc
, TypeManager
.CSharpSignature (EventInfo
), ec
.Report
);
6047 if (!InstanceResolve (ec
, must_do_cs1540_check
))
6050 if (!ec
.HasSet (ResolveContext
.Options
.CompoundAssignmentScope
)) {
6051 Error_CannotAssign (ec
);
6055 if (!ec
.IsObsolete
) {
6056 EventField ev
= TypeManager
.GetEventField (EventInfo
);
6058 ev
.CheckObsoleteness (loc
);
6060 ObsoleteAttribute oa
= AttributeTester
.GetMemberObsoleteAttribute (EventInfo
);
6062 AttributeTester
.Report_ObsoleteMessage (oa
, GetSignatureForError (), loc
, ec
.Report
);
6069 public override void Emit (EmitContext ec
)
6071 throw new NotSupportedException ();
6072 //Error_CannotAssign ();
6075 public void Error_CannotAssign (ResolveContext ec
)
6077 ec
.Report
.Error (70, loc
,
6078 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
6079 GetSignatureForError (), TypeManager
.CSharpName (EventInfo
.DeclaringType
));
6082 public override string GetSignatureForError ()
6084 return TypeManager
.CSharpSignature (EventInfo
);
6087 public void EmitAddOrRemove (EmitContext ec
, bool is_add
, Expression source
)
6089 Arguments args
= new Arguments (1);
6090 args
.Add (new Argument (source
));
6091 Invocation
.EmitCall (ec
, IsBase
, InstanceExpression
, is_add
? add_accessor
: remove_accessor
, args
, loc
);
6095 public class TemporaryVariable
: VariableReference
6099 public TemporaryVariable (Type type
, Location loc
)
6103 eclass
= ExprClass
.Variable
;
6106 public override Expression
CreateExpressionTree (ResolveContext ec
)
6108 throw new NotSupportedException ("ET");
6111 public override Expression
DoResolve (ResolveContext ec
)
6116 TypeExpr te
= new TypeExpression (type
, loc
);
6117 li
= ec
.CurrentBlock
.AddTemporaryVariable (te
, loc
);
6118 if (!li
.Resolve (ec
))
6122 // Don't capture temporary variables except when using
6123 // iterator redirection
6125 if (ec
.CurrentAnonymousMethod
!= null && ec
.CurrentAnonymousMethod
.IsIterator
&& ec
.IsVariableCapturingRequired
) {
6126 AnonymousMethodStorey storey
= li
.Block
.Explicit
.CreateAnonymousMethodStorey (ec
);
6127 storey
.CaptureLocalVariable (ec
, li
);
6133 public override Expression
DoResolveLValue (ResolveContext ec
, Expression right_side
)
6135 return DoResolve (ec
);
6138 public override void Emit (EmitContext ec
)
6143 public void EmitAssign (EmitContext ec
, Expression source
)
6145 EmitAssign (ec
, source
, false, false);
6148 public override HoistedVariable
GetHoistedVariable (AnonymousExpression ae
)
6150 return li
.HoistedVariant
;
6153 public override bool IsFixed
{
6154 get { return true; }
6157 public override bool IsRef
{
6158 get { return false; }
6161 public override string Name
{
6162 get { throw new NotImplementedException (); }
6165 public override void SetHasAddressTaken ()
6167 throw new NotImplementedException ();
6170 protected override ILocalVariable Variable
{
6174 public override VariableInfo VariableInfo
{
6175 get { throw new NotImplementedException (); }
6180 /// Handles `var' contextual keyword; var becomes a keyword only
6181 /// if no type called var exists in a variable scope
6183 class VarExpr
: SimpleName
6185 // Used for error reporting only
6186 ArrayList initializer
;
6188 public VarExpr (Location loc
)
6193 public ArrayList VariableInitializer
{
6195 this.initializer
= value;
6199 public bool InferType (ResolveContext ec
, Expression right_side
)
6202 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
6204 type
= right_side
.Type
;
6205 if (type
== TypeManager
.null_type
|| type
== TypeManager
.void_type
|| type
== InternalType
.AnonymousMethod
|| type
== InternalType
.MethodGroup
) {
6206 ec
.Report
.Error (815, loc
, "An implicitly typed local variable declaration cannot be initialized with `{0}'",
6207 right_side
.GetSignatureForError ());
6211 eclass
= ExprClass
.Variable
;
6215 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec
)
6217 if (RootContext
.Version
< LanguageVersion
.V_3
)
6218 base.Error_TypeOrNamespaceNotFound (ec
);
6220 ec
.Compiler
.Report
.Error (825, loc
, "The contextual keyword `var' may only appear within a local variable declaration");
6223 public override TypeExpr
ResolveAsContextualType (IMemberContext rc
, bool silent
)
6225 TypeExpr te
= base.ResolveAsContextualType (rc
, true);
6229 if (RootContext
.Version
< LanguageVersion
.V_3
)
6230 rc
.Compiler
.Report
.FeatureIsNotAvailable (loc
, "implicitly typed local variable");
6232 if (initializer
== null)
6235 if (initializer
.Count
> 1) {
6236 Location loc_init
= ((CSharpParser
.VariableDeclaration
) initializer
[1]).Location
;
6237 rc
.Compiler
.Report
.Error (819, loc_init
, "An implicitly typed local variable declaration cannot include multiple declarators");
6242 Expression variable_initializer
= ((CSharpParser
.VariableDeclaration
) initializer
[0]).expression_or_array_initializer
;
6243 if (variable_initializer
== null) {
6244 rc
.Compiler
.Report
.Error (818, loc
, "An implicitly typed local variable declarator must include an initializer");