2 // ecore.cs: Core of the Expression representation for the intermediate tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@seznam.cz)
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
13 namespace Mono.CSharp {
15 using System.Collections;
16 using System.Diagnostics;
17 using System.Reflection;
18 using System.Reflection.Emit;
22 /// The ExprClass class contains the is used to pass the
23 /// classification of an expression (value, variable, namespace,
24 /// type, method group, property access, event access, indexer access,
27 public enum ExprClass : byte {
43 /// This is used to tell Resolve in which types of expressions we're
47 public enum ResolveFlags {
48 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
51 // Returns a type expression.
54 // Returns a method group.
57 TypeParameter = 1 << 3,
59 // Mask of all the expression class flags.
60 MaskExprClass = VariableOrValue | Type | MethodGroup | TypeParameter,
62 // Disable control flow analysis while resolving the expression.
63 // This is used when resolving the instance expression of a field expression.
64 DisableFlowAnalysis = 1 << 10,
66 // Set if this is resolving the first part of a MemberAccess.
67 Intermediate = 1 << 11,
69 // Disable control flow analysis _of struct_ while resolving the expression.
70 // This is used when resolving the instance expression of a field expression.
71 DisableStructFlowAnalysis = 1 << 12,
76 // This is just as a hint to AddressOf of what will be done with the
79 public enum AddressOp {
86 /// This interface is implemented by variables
88 public interface IMemoryLocation {
90 /// The AddressOf method should generate code that loads
91 /// the address of the object and leaves it on the stack.
93 /// The `mode' argument is used to notify the expression
94 /// of whether this will be used to read from the address or
95 /// write to the address.
97 /// This is just a hint that can be used to provide good error
98 /// reporting, and should have no other side effects.
100 void AddressOf (EmitContext ec, AddressOp mode);
104 // An expressions resolved as a direct variable reference
106 public interface IVariableReference : IFixedExpression
108 bool IsHoisted { get; }
110 VariableInfo VariableInfo { get; }
112 void SetHasAddressTaken ();
116 // Implemented by an expression which could be or is always
119 public interface IFixedExpression
121 bool IsFixed { get; }
125 /// Base class for expressions
127 public abstract class Expression {
128 public ExprClass eclass;
130 protected Location loc;
134 set { type = value; }
137 public virtual Location Location {
142 /// Utility wrapper routine for Error, just to beautify the code
144 public void Error (int error, string s)
146 Report.Error (error, loc, s);
149 // Not nice but we have broken hierarchy.
150 public virtual void CheckMarshalByRefAccess (EmitContext ec)
154 public virtual bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
156 Attribute.Error_AttributeArgumentNotValid (loc);
161 public virtual string GetSignatureForError ()
163 return TypeManager.CSharpName (type);
166 public static bool IsAccessorAccessible (Type invocation_type, MethodInfo mi, out bool must_do_cs1540_check)
168 MethodAttributes ma = mi.Attributes & MethodAttributes.MemberAccessMask;
170 must_do_cs1540_check = false; // by default we do not check for this
172 if (ma == MethodAttributes.Public)
176 // If only accessible to the current class or children
178 if (ma == MethodAttributes.Private)
179 return TypeManager.IsPrivateAccessible (invocation_type, mi.DeclaringType) ||
180 TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType);
182 if (TypeManager.IsThisOrFriendAssembly (mi.DeclaringType.Assembly)) {
183 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamORAssem)
186 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamANDAssem)
190 // Family and FamANDAssem require that we derive.
191 // FamORAssem requires that we derive if in different assemblies.
192 if (!TypeManager.IsNestedFamilyAccessible (invocation_type, mi.DeclaringType))
195 if (!TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType))
196 must_do_cs1540_check = true;
201 public virtual bool IsNull {
208 /// Performs semantic analysis on the Expression
212 /// The Resolve method is invoked to perform the semantic analysis
215 /// The return value is an expression (it can be the
216 /// same expression in some cases) or a new
217 /// expression that better represents this node.
219 /// For example, optimizations of Unary (LiteralInt)
220 /// would return a new LiteralInt with a negated
223 /// If there is an error during semantic analysis,
224 /// then an error should be reported (using Report)
225 /// and a null value should be returned.
227 /// There are two side effects expected from calling
228 /// Resolve(): the the field variable "eclass" should
229 /// be set to any value of the enumeration
230 /// `ExprClass' and the type variable should be set
231 /// to a valid type (this is the type of the
234 public abstract Expression DoResolve (EmitContext ec);
236 public virtual Expression DoResolveLValue (EmitContext ec, Expression right_side)
242 // This is used if the expression should be resolved as a type or namespace name.
243 // the default implementation fails.
245 public virtual FullNamedExpression ResolveAsTypeStep (IResolveContext rc, bool silent)
249 EmitContext ec = rc as EmitContext;
253 e.Error_UnexpectedKind (ResolveFlags.Type, loc);
259 // C# 3.0 introduced contextual keywords (var) which behaves like a type if type with
260 // same name exists or as a keyword when no type was found
262 public virtual TypeExpr ResolveAsContextualType (IResolveContext rc, bool silent)
264 return ResolveAsTypeTerminal (rc, silent);
268 // This is used to resolve the expression as a type, a null
269 // value will be returned if the expression is not a type
272 public virtual TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
274 TypeExpr te = ResolveAsBaseTerminal (ec, silent);
278 if (!silent) { // && !(te is TypeParameterExpr)) {
279 ObsoleteAttribute obsolete_attr = AttributeTester.GetObsoleteAttribute (te.Type);
280 if (obsolete_attr != null && !ec.IsInObsoleteScope) {
281 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location);
285 GenericTypeExpr ct = te as GenericTypeExpr;
287 // Skip constrains check for overrides and explicit implementations
288 // TODO: they should use different overload
289 GenericMethod gm = ec.GenericDeclContainer as GenericMethod;
290 if (gm != null && ((gm.ModFlags & Modifiers.OVERRIDE) != 0 || gm.MemberName.Left != null)) {
295 // TODO: silent flag is ignored
296 ct.CheckConstraints (ec);
297 ct.VerifyVariantTypeParameters ();
303 public TypeExpr ResolveAsBaseTerminal (IResolveContext ec, bool silent)
305 int errors = Report.Errors;
307 FullNamedExpression fne = ResolveAsTypeStep (ec, silent);
312 TypeExpr te = fne as TypeExpr;
314 if (!silent && errors == Report.Errors)
315 fne.Error_UnexpectedKind (null, "type", loc);
319 if (!te.CheckAccessLevel (ec.GenericDeclContainer)) {
320 Report.SymbolRelatedToPreviousError (te.Type);
321 ErrorIsInaccesible (loc, TypeManager.CSharpName (te.Type));
329 public static void ErrorIsInaccesible (Location loc, string name)
331 Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", name);
334 protected static void Error_CannotAccessProtected (Location loc, MemberInfo m, Type qualifier, Type container)
336 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 (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 ()
352 Error_InvalidExpressionStatement (loc);
355 protected void Error_CannotAssign (string to, string roContext)
357 Report.Error (1656, loc, "Cannot assign to `{0}' because it is a `{1}'",
361 public static void Error_VoidInvalidInTheContext (Location loc)
363 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
366 public virtual void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl)
368 Error_ValueCannotBeConvertedCore (ec, loc, target, expl);
371 protected void Error_ValueCannotBeConvertedCore (EmitContext ec, Location loc, Type target, bool expl)
373 // The error was already reported as CS1660
374 if (type == TypeManager.anonymous_method_type)
377 if (TypeManager.IsGenericParameter (Type) && TypeManager.IsGenericParameter (target) && type.Name == target.Name) {
379 string sig1 = type.DeclaringMethod == null ?
380 TypeManager.CSharpName (type.DeclaringType) :
381 TypeManager.CSharpSignature (type.DeclaringMethod);
382 string sig2 = target.DeclaringMethod == null ?
383 TypeManager.CSharpName (target.DeclaringType) :
384 TypeManager.CSharpSignature (target.DeclaringMethod);
385 Report.ExtraInformation (loc,
387 "The generic parameter `{0}' of `{1}' cannot be converted to the generic parameter `{0}' of `{2}' (in the previous ",
388 Type.Name, sig1, sig2));
390 } else if (Type.FullName == target.FullName){
391 Report.ExtraInformation (loc,
393 "The type `{0}' has two conflicting definitions, one comes from `{1}' and the other from `{2}' (in the previous ",
394 Type.FullName, Type.Assembly.FullName, target.Assembly.FullName));
398 Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
399 TypeManager.CSharpName (type), TypeManager.CSharpName (target));
403 Report.DisableReporting ();
404 bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null;
405 Report.EnableReporting ();
408 Report.Error (266, loc, "Cannot implicitly convert type `{0}' to `{1}'. " +
409 "An explicit conversion exists (are you missing a cast?)",
410 TypeManager.CSharpName (Type), TypeManager.CSharpName (target));
414 Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
415 TypeManager.CSharpName (type),
416 TypeManager.CSharpName (target));
419 public virtual void Error_VariableIsUsedBeforeItIsDeclared (string name)
421 Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", name);
424 protected virtual void Error_TypeDoesNotContainDefinition (Type type, string name)
426 Error_TypeDoesNotContainDefinition (loc, type, name);
429 public static void Error_TypeDoesNotContainDefinition (Location loc, Type type, string name)
431 Report.SymbolRelatedToPreviousError (type);
432 Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
433 TypeManager.CSharpName (type), name);
436 protected static void Error_ValueAssignment (Location loc)
438 Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
441 ResolveFlags ExprClassToResolveFlags
446 case ExprClass.Namespace:
447 return ResolveFlags.Type;
449 case ExprClass.MethodGroup:
450 return ResolveFlags.MethodGroup;
452 case ExprClass.TypeParameter:
453 return ResolveFlags.TypeParameter;
455 case ExprClass.Value:
456 case ExprClass.Variable:
457 case ExprClass.PropertyAccess:
458 case ExprClass.EventAccess:
459 case ExprClass.IndexerAccess:
460 return ResolveFlags.VariableOrValue;
463 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
469 /// Resolves an expression and performs semantic analysis on it.
473 /// Currently Resolve wraps DoResolve to perform sanity
474 /// checking and assertion checking on what we expect from Resolve.
476 public Expression Resolve (EmitContext ec, ResolveFlags flags)
478 if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type)
479 return ResolveAsTypeStep (ec, false);
481 bool do_flow_analysis = ec.DoFlowAnalysis;
482 bool omit_struct_analysis = ec.OmitStructFlowAnalysis;
483 if ((flags & ResolveFlags.DisableFlowAnalysis) != 0)
484 do_flow_analysis = false;
485 if ((flags & ResolveFlags.DisableStructFlowAnalysis) != 0)
486 omit_struct_analysis = true;
489 using (ec.WithFlowAnalysis (do_flow_analysis, omit_struct_analysis)) {
490 if (this is SimpleName) {
491 bool intermediate = (flags & ResolveFlags.Intermediate) == ResolveFlags.Intermediate;
492 e = ((SimpleName) this).DoResolve (ec, intermediate);
501 if ((flags & e.ExprClassToResolveFlags) == 0) {
502 e.Error_UnexpectedKind (flags, loc);
506 if (e.type == null && !(e is Namespace)) {
507 throw new Exception (
508 "Expression " + e.GetType () +
509 " did not set its type after Resolve\n" +
510 "called from: " + this.GetType ());
517 /// Resolves an expression and performs semantic analysis on it.
519 public Expression Resolve (EmitContext ec)
521 Expression e = Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
523 if (e != null && e.eclass == ExprClass.MethodGroup && RootContext.Version == LanguageVersion.ISO_1) {
524 ((MethodGroupExpr) e).ReportUsageError ();
530 public Constant ResolveAsConstant (EmitContext ec, MemberCore mc)
532 Expression e = Resolve (ec);
536 Constant c = e as Constant;
540 if (type != null && TypeManager.IsReferenceType (type))
541 Const.Error_ConstantCanBeInitializedWithNullOnly (type, loc, mc.GetSignatureForError ());
543 Const.Error_ExpressionMustBeConstant (loc, mc.GetSignatureForError ());
549 /// Resolves an expression for LValue assignment
553 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
554 /// checking and assertion checking on what we expect from Resolve
556 public Expression ResolveLValue (EmitContext ec, Expression right_side, Location loc)
558 int errors = Report.Errors;
559 bool out_access = right_side == EmptyExpression.OutAccess;
561 Expression e = DoResolveLValue (ec, right_side);
563 if (e != null && out_access && !(e is IMemoryLocation)) {
564 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
565 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
567 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
568 // e.GetType () + " " + e.GetSignatureForError ());
573 if (errors == Report.Errors) {
575 Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
577 Error_ValueAssignment (loc);
582 if (e.eclass == ExprClass.Invalid)
583 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
585 if ((e.type == null) && !(e is GenericTypeExpr))
586 throw new Exception ("Expression " + e + " did not set its type after Resolve");
592 /// Emits the code for the expression
596 /// The Emit method is invoked to generate the code
597 /// for the expression.
599 public abstract void Emit (EmitContext ec);
601 // Emit code to branch to @target if this expression is equivalent to @on_true.
602 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
603 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
604 // including the use of conditional branches. Note also that a branch MUST be emitted
605 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
608 ec.ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
611 // Emit this expression for its side effects, not for its value.
612 // The default implementation is to emit the value, and then throw it away.
613 // Subclasses can provide more efficient implementations, but those MUST be equivalent
614 public virtual void EmitSideEffect (EmitContext ec)
617 ec.ig.Emit (OpCodes.Pop);
621 /// Protected constructor. Only derivate types should
622 /// be able to be created
625 protected Expression ()
627 eclass = ExprClass.Invalid;
632 /// Returns a fully formed expression after a MemberLookup
635 public static Expression ExprClassFromMemberInfo (Type container_type, MemberInfo mi, Location loc)
638 return new EventExpr ((EventInfo) mi, loc);
639 else if (mi is FieldInfo) {
640 FieldInfo fi = (FieldInfo) mi;
641 if (fi.IsLiteral || (fi.IsInitOnly && fi.FieldType == TypeManager.decimal_type))
642 return new ConstantExpr (fi, loc);
643 return new FieldExpr (fi, loc);
644 } else if (mi is PropertyInfo)
645 return new PropertyExpr (container_type, (PropertyInfo) mi, loc);
646 else if (mi is Type) {
647 return new TypeExpression ((System.Type) mi, loc);
653 // TODO: [Obsolete ("Can be removed")]
654 protected static ArrayList almost_matched_members = new ArrayList (4);
657 // FIXME: Probably implement a cache for (t,name,current_access_set)?
659 // This code could use some optimizations, but we need to do some
660 // measurements. For example, we could use a delegate to `flag' when
661 // something can not any longer be a method-group (because it is something
665 // If the return value is an Array, then it is an array of
668 // If the return value is an MemberInfo, it is anything, but a Method
672 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
673 // the arguments here and have MemberLookup return only the methods that
674 // match the argument count/type, unlike we are doing now (we delay this
677 // This is so we can catch correctly attempts to invoke instance methods
678 // from a static body (scan for error 120 in ResolveSimpleName).
681 // FIXME: Potential optimization, have a static ArrayList
684 public static Expression MemberLookup (Type container_type, Type queried_type, string name,
685 MemberTypes mt, BindingFlags bf, Location loc)
687 return MemberLookup (container_type, null, queried_type, name, mt, bf, loc);
691 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
692 // `qualifier_type' or null to lookup members in the current class.
695 public static Expression MemberLookup (Type container_type,
696 Type qualifier_type, Type queried_type,
697 string name, MemberTypes mt,
698 BindingFlags bf, Location loc)
700 almost_matched_members.Clear ();
702 MemberInfo [] mi = TypeManager.MemberLookup (container_type, qualifier_type,
703 queried_type, mt, bf, name, almost_matched_members);
709 bool is_interface = qualifier_type != null && qualifier_type.IsInterface;
710 ArrayList methods = new ArrayList (2);
711 ArrayList non_methods = null;
713 foreach (MemberInfo m in mi) {
714 if (m is MethodBase) {
719 if (non_methods == null) {
720 non_methods = new ArrayList (2);
725 foreach (MemberInfo n_m in non_methods) {
726 if (m.DeclaringType.IsInterface && TypeManager.ImplementsInterface (m.DeclaringType, n_m.DeclaringType))
729 Report.SymbolRelatedToPreviousError (m);
730 Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
731 TypeManager.GetFullNameSignature (m), TypeManager.GetFullNameSignature (n_m));
736 if (methods.Count == 0)
737 return ExprClassFromMemberInfo (container_type, (MemberInfo)non_methods [0], loc);
739 if (non_methods != null) {
740 MethodBase method = (MethodBase) methods [0];
741 MemberInfo non_method = (MemberInfo) non_methods [0];
742 if (method.DeclaringType == non_method.DeclaringType) {
743 // Cannot happen with C# code, but is valid in IL
744 Report.SymbolRelatedToPreviousError (method);
745 Report.SymbolRelatedToPreviousError (non_method);
746 Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
747 TypeManager.GetFullNameSignature (non_method),
748 TypeManager.CSharpSignature (method));
753 Report.SymbolRelatedToPreviousError (method);
754 Report.SymbolRelatedToPreviousError (non_method);
755 Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and non-method `{1}'. Using method `{0}'",
756 TypeManager.CSharpSignature (method), TypeManager.GetFullNameSignature (non_method));
760 return new MethodGroupExpr (methods, queried_type, loc);
763 if (mi [0] is MethodBase)
764 return new MethodGroupExpr (mi, queried_type, loc);
766 return ExprClassFromMemberInfo (container_type, mi [0], loc);
769 public const MemberTypes AllMemberTypes =
770 MemberTypes.Constructor |
774 MemberTypes.NestedType |
775 MemberTypes.Property;
777 public const BindingFlags AllBindingFlags =
778 BindingFlags.Public |
779 BindingFlags.Static |
780 BindingFlags.Instance;
782 public static Expression MemberLookup (Type container_type, Type queried_type,
783 string name, Location loc)
785 return MemberLookup (container_type, null, queried_type, name,
786 AllMemberTypes, AllBindingFlags, loc);
789 public static Expression MemberLookup (Type container_type, Type qualifier_type,
790 Type queried_type, string name, Location loc)
792 return MemberLookup (container_type, qualifier_type, queried_type,
793 name, AllMemberTypes, AllBindingFlags, loc);
796 public static MethodGroupExpr MethodLookup (Type container_type, Type queried_type,
797 string name, Location loc)
799 return (MethodGroupExpr)MemberLookup (container_type, null, queried_type, name,
800 MemberTypes.Method, AllBindingFlags, loc);
804 /// This is a wrapper for MemberLookup that is not used to "probe", but
805 /// to find a final definition. If the final definition is not found, we
806 /// look for private members and display a useful debugging message if we
809 protected Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
810 Type queried_type, string name,
811 MemberTypes mt, BindingFlags bf,
816 int errors = Report.Errors;
817 e = MemberLookup (ec.ContainerType, qualifier_type, queried_type, name, mt, bf, loc);
819 if (e != null || errors != Report.Errors)
822 // No errors were reported by MemberLookup, but there was an error.
823 return Error_MemberLookupFailed (ec.ContainerType, qualifier_type, queried_type,
827 protected virtual Expression Error_MemberLookupFailed (Type container_type, Type qualifier_type,
828 Type queried_type, string name, string class_name,
829 MemberTypes mt, BindingFlags bf)
831 MemberInfo[] lookup = null;
832 if (queried_type == null) {
833 class_name = "global::";
835 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
836 mt, (bf & ~BindingFlags.Public) | BindingFlags.NonPublic,
839 if (lookup != null) {
840 Expression e = Error_MemberLookupFailed (queried_type, lookup);
843 // FIXME: This is still very wrong, it should be done inside
844 // OverloadResolve to do correct arguments matching.
845 // Requires MemberLookup accessiblity check removal
847 if (e == null || (mt & (MemberTypes.Method | MemberTypes.Constructor)) == 0) {
848 MemberInfo mi = lookup[0];
849 Report.SymbolRelatedToPreviousError (mi);
850 if (qualifier_type != null && container_type != null && qualifier_type != container_type &&
851 TypeManager.IsNestedFamilyAccessible (container_type, mi.DeclaringType)) {
852 // Although a derived class can access protected members of
853 // its base class it cannot do so through an instance of the
854 // base class (CS1540). If the qualifier_type is a base of the
855 // ec.ContainerType and the lookup succeeds with the latter one,
856 // then we are in this situation.
857 Error_CannotAccessProtected (loc, mi, qualifier_type, container_type);
859 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (mi));
866 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
867 AllMemberTypes, AllBindingFlags | BindingFlags.NonPublic,
871 if (lookup == null) {
872 if (class_name != null) {
873 Report.Error (103, loc, "The name `{0}' does not exist in the current context",
876 Error_TypeDoesNotContainDefinition (queried_type, name);
881 if (TypeManager.MemberLookup (queried_type, null, queried_type,
882 AllMemberTypes, AllBindingFlags |
883 BindingFlags.NonPublic, name, null) == null) {
884 if ((lookup.Length == 1) && (lookup [0] is Type)) {
885 Type t = (Type) lookup [0];
887 Report.Error (305, loc,
888 "Using the generic type `{0}' " +
889 "requires {1} type arguments",
890 TypeManager.CSharpName (t),
891 TypeManager.GetNumberOfTypeArguments (t).ToString ());
896 return Error_MemberLookupFailed (queried_type, lookup);
899 protected virtual Expression Error_MemberLookupFailed (Type type, MemberInfo[] members)
901 for (int i = 0; i < members.Length; ++i) {
902 if (!(members [i] is MethodBase))
906 // By default propagate the closest candidates upwards
907 return new MethodGroupExpr (members, type, loc, true);
910 protected virtual void Error_NegativeArrayIndex (Location loc)
912 throw new NotImplementedException ();
915 protected void Error_PointerInsideExpressionTree ()
917 Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
921 /// Returns an expression that can be used to invoke operator true
922 /// on the expression if it exists.
924 static public Expression GetOperatorTrue (EmitContext ec, Expression e, Location loc)
926 return GetOperatorTrueOrFalse (ec, e, true, loc);
930 /// Returns an expression that can be used to invoke operator false
931 /// on the expression if it exists.
933 static public Expression GetOperatorFalse (EmitContext ec, Expression e, Location loc)
935 return GetOperatorTrueOrFalse (ec, e, false, loc);
938 static Expression GetOperatorTrueOrFalse (EmitContext ec, Expression e, bool is_true, Location loc)
940 MethodGroupExpr operator_group;
941 string mname = Operator.GetMetadataName (is_true ? Operator.OpType.True : Operator.OpType.False);
942 operator_group = MethodLookup (ec.ContainerType, e.Type, mname, loc) as MethodGroupExpr;
943 if (operator_group == null)
946 ArrayList arguments = new ArrayList (1);
947 arguments.Add (new Argument (e, Argument.AType.Expression));
948 operator_group = operator_group.OverloadResolve (
949 ec, ref arguments, false, loc);
951 if (operator_group == null)
954 return new UserOperatorCall (operator_group, arguments, null, loc);
958 /// Resolves the expression `e' into a boolean expression: either through
959 /// an implicit conversion, or through an `operator true' invocation
961 public static Expression ResolveBoolean (EmitContext ec, Expression e, Location loc)
967 if (e.Type == TypeManager.bool_type)
970 Expression converted = Convert.ImplicitConversion (ec, e, TypeManager.bool_type, Location.Null);
972 if (converted != null)
976 // If no implicit conversion to bool exists, try using `operator true'
978 converted = Expression.GetOperatorTrue (ec, e, loc);
979 if (converted == null){
980 e.Error_ValueCannotBeConverted (ec, loc, TypeManager.bool_type, false);
986 public virtual string ExprClassName
990 case ExprClass.Invalid:
992 case ExprClass.Value:
994 case ExprClass.Variable:
996 case ExprClass.Namespace:
1000 case ExprClass.MethodGroup:
1001 return "method group";
1002 case ExprClass.PropertyAccess:
1003 return "property access";
1004 case ExprClass.EventAccess:
1005 return "event access";
1006 case ExprClass.IndexerAccess:
1007 return "indexer access";
1008 case ExprClass.Nothing:
1010 case ExprClass.TypeParameter:
1011 return "type parameter";
1013 throw new Exception ("Should not happen");
1018 /// Reports that we were expecting `expr' to be of class `expected'
1020 public void Error_UnexpectedKind (DeclSpace ds, string expected, Location loc)
1022 Error_UnexpectedKind (ds, expected, ExprClassName, loc);
1025 public void Error_UnexpectedKind (DeclSpace ds, string expected, string was, Location loc)
1027 string name = GetSignatureForError ();
1029 name = ds.GetSignatureForError () + '.' + name;
1031 Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
1032 name, was, expected);
1035 public void Error_UnexpectedKind (ResolveFlags flags, Location loc)
1037 string [] valid = new string [4];
1040 if ((flags & ResolveFlags.VariableOrValue) != 0) {
1041 valid [count++] = "variable";
1042 valid [count++] = "value";
1045 if ((flags & ResolveFlags.Type) != 0)
1046 valid [count++] = "type";
1048 if ((flags & ResolveFlags.MethodGroup) != 0)
1049 valid [count++] = "method group";
1052 valid [count++] = "unknown";
1054 StringBuilder sb = new StringBuilder (valid [0]);
1055 for (int i = 1; i < count - 1; i++) {
1057 sb.Append (valid [i]);
1060 sb.Append ("' or `");
1061 sb.Append (valid [count - 1]);
1064 Report.Error (119, loc,
1065 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1068 public static void UnsafeError (Location loc)
1070 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1074 // Load the object from the pointer.
1076 public static void LoadFromPtr (ILGenerator ig, Type t)
1078 if (t == TypeManager.int32_type)
1079 ig.Emit (OpCodes.Ldind_I4);
1080 else if (t == TypeManager.uint32_type)
1081 ig.Emit (OpCodes.Ldind_U4);
1082 else if (t == TypeManager.short_type)
1083 ig.Emit (OpCodes.Ldind_I2);
1084 else if (t == TypeManager.ushort_type)
1085 ig.Emit (OpCodes.Ldind_U2);
1086 else if (t == TypeManager.char_type)
1087 ig.Emit (OpCodes.Ldind_U2);
1088 else if (t == TypeManager.byte_type)
1089 ig.Emit (OpCodes.Ldind_U1);
1090 else if (t == TypeManager.sbyte_type)
1091 ig.Emit (OpCodes.Ldind_I1);
1092 else if (t == TypeManager.uint64_type)
1093 ig.Emit (OpCodes.Ldind_I8);
1094 else if (t == TypeManager.int64_type)
1095 ig.Emit (OpCodes.Ldind_I8);
1096 else if (t == TypeManager.float_type)
1097 ig.Emit (OpCodes.Ldind_R4);
1098 else if (t == TypeManager.double_type)
1099 ig.Emit (OpCodes.Ldind_R8);
1100 else if (t == TypeManager.bool_type)
1101 ig.Emit (OpCodes.Ldind_I1);
1102 else if (t == TypeManager.intptr_type)
1103 ig.Emit (OpCodes.Ldind_I);
1104 else if (TypeManager.IsEnumType (t)) {
1105 if (t == TypeManager.enum_type)
1106 ig.Emit (OpCodes.Ldind_Ref);
1108 LoadFromPtr (ig, TypeManager.GetEnumUnderlyingType (t));
1109 } else if (TypeManager.IsStruct (t) || TypeManager.IsGenericParameter (t))
1110 ig.Emit (OpCodes.Ldobj, t);
1111 else if (t.IsPointer)
1112 ig.Emit (OpCodes.Ldind_I);
1114 ig.Emit (OpCodes.Ldind_Ref);
1118 // The stack contains the pointer and the value of type `type'
1120 public static void StoreFromPtr (ILGenerator ig, Type type)
1122 if (TypeManager.IsEnumType (type))
1123 type = TypeManager.GetEnumUnderlyingType (type);
1124 if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
1125 ig.Emit (OpCodes.Stind_I4);
1126 else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
1127 ig.Emit (OpCodes.Stind_I8);
1128 else if (type == TypeManager.char_type || type == TypeManager.short_type ||
1129 type == TypeManager.ushort_type)
1130 ig.Emit (OpCodes.Stind_I2);
1131 else if (type == TypeManager.float_type)
1132 ig.Emit (OpCodes.Stind_R4);
1133 else if (type == TypeManager.double_type)
1134 ig.Emit (OpCodes.Stind_R8);
1135 else if (type == TypeManager.byte_type || type == TypeManager.sbyte_type ||
1136 type == TypeManager.bool_type)
1137 ig.Emit (OpCodes.Stind_I1);
1138 else if (type == TypeManager.intptr_type)
1139 ig.Emit (OpCodes.Stind_I);
1140 else if (TypeManager.IsStruct (type) || TypeManager.IsGenericParameter (type))
1141 ig.Emit (OpCodes.Stobj, type);
1143 ig.Emit (OpCodes.Stind_Ref);
1147 // Returns the size of type `t' if known, otherwise, 0
1149 public static int GetTypeSize (Type t)
1151 t = TypeManager.TypeToCoreType (t);
1152 if (t == TypeManager.int32_type ||
1153 t == TypeManager.uint32_type ||
1154 t == TypeManager.float_type)
1156 else if (t == TypeManager.int64_type ||
1157 t == TypeManager.uint64_type ||
1158 t == TypeManager.double_type)
1160 else if (t == TypeManager.byte_type ||
1161 t == TypeManager.sbyte_type ||
1162 t == TypeManager.bool_type)
1164 else if (t == TypeManager.short_type ||
1165 t == TypeManager.char_type ||
1166 t == TypeManager.ushort_type)
1168 else if (t == TypeManager.decimal_type)
1174 protected void Error_CannotCallAbstractBase (string name)
1176 Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
1179 protected void Error_CannotModifyIntermediateExpressionValue (EmitContext ec)
1181 Report.SymbolRelatedToPreviousError (type);
1182 if (ec.CurrentInitializerVariable != null) {
1183 Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
1184 TypeManager.CSharpName (type), GetSignatureForError ());
1186 Report.Error (1612, loc, "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
1187 GetSignatureForError ());
1191 public void Error_ExpressionCannotBeGeneric (Location loc)
1193 Report.Error (307, loc, "The {0} `{1}' cannot be used with type arguments",
1194 ExprClassName, GetSignatureForError ());
1198 // Converts `source' to an int, uint, long or ulong.
1200 public Expression ConvertExpressionToArrayIndex (EmitContext ec, Expression source)
1202 Expression converted;
1204 using (ec.With (EmitContext.Flags.CheckState, true)) {
1205 converted = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, source.loc);
1206 if (converted == null)
1207 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, source.loc);
1208 if (converted == null)
1209 converted = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, source.loc);
1210 if (converted == null)
1211 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, source.loc);
1213 if (converted == null) {
1214 source.Error_ValueCannotBeConverted (ec, source.loc, TypeManager.int32_type, false);
1220 // Only positive constants are allowed at compile time
1222 Constant c = converted as Constant;
1225 Error_NegativeArrayIndex (source.loc);
1230 return new ArrayIndexCast (converted).Resolve (ec);
1234 // Derived classes implement this method by cloning the fields that
1235 // could become altered during the Resolve stage
1237 // Only expressions that are created for the parser need to implement
1240 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1242 throw new NotImplementedException (
1244 "CloneTo not implemented for expression {0}", this.GetType ()));
1248 // Clones an expression created by the parser.
1250 // We only support expressions created by the parser so far, not
1251 // expressions that have been resolved (many more classes would need
1252 // to implement CloneTo).
1254 // This infrastructure is here merely for Lambda expressions which
1255 // compile the same code using different type values for the same
1256 // arguments to find the correct overload
1258 public Expression Clone (CloneContext clonectx)
1260 Expression cloned = (Expression) MemberwiseClone ();
1261 CloneTo (clonectx, cloned);
1267 // Implementation of expression to expression tree conversion
1269 public abstract Expression CreateExpressionTree (EmitContext ec);
1271 protected Expression CreateExpressionFactoryCall (string name, ArrayList args)
1273 return CreateExpressionFactoryCall (name, null, args, loc);
1276 protected Expression CreateExpressionFactoryCall (string name, TypeArguments typeArguments, ArrayList args)
1278 return CreateExpressionFactoryCall (name, typeArguments, args, loc);
1281 public static Expression CreateExpressionFactoryCall (string name, TypeArguments typeArguments, ArrayList args, Location loc)
1283 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (loc), name, typeArguments, loc), args);
1286 protected static TypeExpr CreateExpressionTypeExpression (Location loc)
1288 TypeExpr texpr = TypeManager.expression_type_expr;
1289 if (texpr == null) {
1290 Type t = TypeManager.CoreLookupType ("System.Linq.Expressions", "Expression", Kind.Class, true);
1294 TypeManager.expression_type_expr = texpr = new TypeExpression (t, Location.Null);
1300 public virtual void MutateHoistedGenericType (AnonymousMethodStorey storey)
1302 // TODO: It should probably be type = storey.MutateType (type);
1307 /// This is just a base class for expressions that can
1308 /// appear on statements (invocations, object creation,
1309 /// assignments, post/pre increment and decrement). The idea
1310 /// being that they would support an extra Emition interface that
1311 /// does not leave a result on the stack.
1313 public abstract class ExpressionStatement : Expression {
1315 public virtual ExpressionStatement ResolveStatement (EmitContext ec)
1317 Expression e = Resolve (ec);
1321 ExpressionStatement es = e as ExpressionStatement;
1323 Error_InvalidExpressionStatement ();
1329 /// Requests the expression to be emitted in a `statement'
1330 /// context. This means that no new value is left on the
1331 /// stack after invoking this method (constrasted with
1332 /// Emit that will always leave a value on the stack).
1334 public abstract void EmitStatement (EmitContext ec);
1336 public override void EmitSideEffect (EmitContext ec)
1343 /// This kind of cast is used to encapsulate the child
1344 /// whose type is child.Type into an expression that is
1345 /// reported to return "return_type". This is used to encapsulate
1346 /// expressions which have compatible types, but need to be dealt
1347 /// at higher levels with.
1349 /// For example, a "byte" expression could be encapsulated in one
1350 /// of these as an "unsigned int". The type for the expression
1351 /// would be "unsigned int".
1354 public abstract class TypeCast : Expression
1356 protected readonly Expression child;
1358 protected TypeCast (Expression child, Type return_type)
1360 eclass = child.eclass;
1361 loc = child.Location;
1366 public override Expression CreateExpressionTree (EmitContext ec)
1368 ArrayList args = new ArrayList (2);
1369 args.Add (new Argument (child.CreateExpressionTree (ec)));
1370 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1372 if (type.IsPointer || child.Type.IsPointer)
1373 Error_PointerInsideExpressionTree ();
1375 return CreateExpressionFactoryCall (ec.CheckState ? "ConvertChecked" : "Convert", args);
1378 public override Expression DoResolve (EmitContext ec)
1380 // This should never be invoked, we are born in fully
1381 // initialized state.
1386 public override void Emit (EmitContext ec)
1391 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
1393 return child.GetAttributableValue (ec, value_type, out value);
1396 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1398 type = storey.MutateType (type);
1399 child.MutateHoistedGenericType (storey);
1402 protected override void CloneTo (CloneContext clonectx, Expression t)
1407 public override bool IsNull {
1408 get { return child.IsNull; }
1412 public class EmptyCast : TypeCast {
1413 EmptyCast (Expression child, Type target_type)
1414 : base (child, target_type)
1418 public static Expression Create (Expression child, Type type)
1420 Constant c = child as Constant;
1422 return new EmptyConstantCast (c, type);
1424 EmptyCast e = child as EmptyCast;
1426 return new EmptyCast (e.child, type);
1428 return new EmptyCast (child, type);
1431 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1433 child.EmitBranchable (ec, label, on_true);
1436 public override void EmitSideEffect (EmitContext ec)
1438 child.EmitSideEffect (ec);
1443 // Used for predefined class library user casts (no obsolete check, etc.)
1445 public class OperatorCast : TypeCast {
1446 MethodInfo conversion_operator;
1448 public OperatorCast (Expression child, Type target_type)
1449 : this (child, target_type, false)
1453 public OperatorCast (Expression child, Type target_type, bool find_explicit)
1454 : base (child, target_type)
1456 conversion_operator = GetConversionOperator (find_explicit);
1457 if (conversion_operator == null)
1458 throw new InternalErrorException ("Outer conversion routine is out of sync");
1461 // Returns the implicit operator that converts from
1462 // 'child.Type' to our target type (type)
1463 MethodInfo GetConversionOperator (bool find_explicit)
1465 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1469 mi = TypeManager.MemberLookup (child.Type, child.Type, child.Type, MemberTypes.Method,
1470 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1473 mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1474 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1477 foreach (MethodInfo oper in mi) {
1478 AParametersCollection pd = TypeManager.GetParameterData (oper);
1480 if (pd.Types [0] == child.Type && TypeManager.TypeToCoreType (oper.ReturnType) == type)
1487 public override void Emit (EmitContext ec)
1490 ec.ig.Emit (OpCodes.Call, conversion_operator);
1495 /// This is a numeric cast to a Decimal
1497 public class CastToDecimal : OperatorCast {
1498 public CastToDecimal (Expression child)
1499 : this (child, false)
1503 public CastToDecimal (Expression child, bool find_explicit)
1504 : base (child, TypeManager.decimal_type, find_explicit)
1510 /// This is an explicit numeric cast from a Decimal
1512 public class CastFromDecimal : TypeCast
1514 static IDictionary operators;
1516 public CastFromDecimal (Expression child, Type return_type)
1517 : base (child, return_type)
1519 if (child.Type != TypeManager.decimal_type)
1520 throw new InternalErrorException (
1521 "The expected type is Decimal, instead it is " + child.Type.FullName);
1524 // Returns the explicit operator that converts from an
1525 // express of type System.Decimal to 'type'.
1526 public Expression Resolve ()
1528 if (operators == null) {
1529 MemberInfo[] all_oper = TypeManager.MemberLookup (TypeManager.decimal_type,
1530 TypeManager.decimal_type, TypeManager.decimal_type, MemberTypes.Method,
1531 BindingFlags.Static | BindingFlags.Public, "op_Explicit", null);
1533 operators = new System.Collections.Specialized.HybridDictionary ();
1534 foreach (MethodInfo oper in all_oper) {
1535 AParametersCollection pd = TypeManager.GetParameterData (oper);
1536 if (pd.Types [0] == TypeManager.decimal_type)
1537 operators.Add (TypeManager.TypeToCoreType (oper.ReturnType), oper);
1541 return operators.Contains (type) ? this : null;
1544 public override void Emit (EmitContext ec)
1546 ILGenerator ig = ec.ig;
1549 ig.Emit (OpCodes.Call, (MethodInfo)operators [type]);
1555 // Constant specialization of EmptyCast.
1556 // We need to special case this since an empty cast of
1557 // a constant is still a constant.
1559 public class EmptyConstantCast : Constant
1561 public readonly Constant child;
1563 public EmptyConstantCast(Constant child, Type type)
1564 : base (child.Location)
1566 eclass = child.eclass;
1571 public override string AsString ()
1573 return child.AsString ();
1576 public override object GetValue ()
1578 return child.GetValue ();
1581 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
1583 // FIXME: check that 'type' can be converted to 'target_type' first
1584 return child.ConvertExplicitly (in_checked_context, target_type);
1587 public override Expression CreateExpressionTree (EmitContext ec)
1589 ArrayList args = new ArrayList (2);
1590 args.Add (new Argument (child.CreateExpressionTree (ec)));
1591 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1593 Error_PointerInsideExpressionTree ();
1595 return CreateExpressionFactoryCall ("Convert", args);
1598 public override Constant Increment ()
1600 return child.Increment ();
1603 public override bool IsDefaultValue {
1604 get { return child.IsDefaultValue; }
1607 public override bool IsNegative {
1608 get { return child.IsNegative; }
1611 public override bool IsNull {
1612 get { return child.IsNull; }
1615 public override bool IsZeroInteger {
1616 get { return child.IsZeroInteger; }
1619 public override void Emit (EmitContext ec)
1624 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1626 child.EmitBranchable (ec, label, on_true);
1629 // Only to make verifier happy
1630 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1631 ec.ig.Emit (OpCodes.Unbox_Any, type);
1635 public override void EmitSideEffect (EmitContext ec)
1637 child.EmitSideEffect (ec);
1640 public override Constant ConvertImplicitly (Type target_type)
1642 // FIXME: Do we need to check user conversions?
1643 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1645 return child.ConvertImplicitly (target_type);
1648 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1650 child.MutateHoistedGenericType (storey);
1656 /// This class is used to wrap literals which belong inside Enums
1658 public class EnumConstant : Constant {
1659 public Constant Child;
1661 public EnumConstant (Constant child, Type enum_type):
1662 base (child.Location)
1664 eclass = child.eclass;
1669 public override Expression DoResolve (EmitContext ec)
1671 // This should never be invoked, we are born in fully
1672 // initialized state.
1677 public override void Emit (EmitContext ec)
1682 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1684 Child.EmitBranchable (ec, label, on_true);
1687 public override void EmitSideEffect (EmitContext ec)
1689 Child.EmitSideEffect (ec);
1692 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
1694 value = GetTypedValue ();
1698 public override string GetSignatureForError()
1700 return TypeManager.CSharpName (Type);
1703 public override object GetValue ()
1705 return Child.GetValue ();
1708 public override object GetTypedValue ()
1710 // FIXME: runtime is not ready to work with just emited enums
1711 if (!RootContext.StdLib) {
1712 return Child.GetValue ();
1716 // Small workaround for big problem
1717 // System.Enum.ToObject cannot be called on dynamic types
1718 // EnumBuilder has to be used, but we cannot use EnumBuilder
1719 // because it does not properly support generics
1721 // This works only sometimes
1723 if (type.Module == RootContext.ToplevelTypes.Builder)
1724 return Child.GetValue ();
1727 return System.Enum.ToObject (type, Child.GetValue ());
1730 public override string AsString ()
1732 return Child.AsString ();
1735 public override Constant Increment()
1737 return new EnumConstant (Child.Increment (), type);
1740 public override bool IsDefaultValue {
1742 return Child.IsDefaultValue;
1746 public override bool IsZeroInteger {
1747 get { return Child.IsZeroInteger; }
1750 public override bool IsNegative {
1752 return Child.IsNegative;
1756 public override Constant ConvertExplicitly(bool in_checked_context, Type target_type)
1758 if (Child.Type == target_type)
1761 return Child.ConvertExplicitly (in_checked_context, target_type);
1764 public override Constant ConvertImplicitly (Type type)
1766 Type this_type = TypeManager.DropGenericTypeArguments (Type);
1767 type = TypeManager.DropGenericTypeArguments (type);
1769 if (this_type == type) {
1770 // This is workaround of mono bug. It can be removed when the latest corlib spreads enough
1771 if (TypeManager.IsEnumType (type.UnderlyingSystemType))
1774 Type child_type = TypeManager.DropGenericTypeArguments (Child.Type);
1775 if (type.UnderlyingSystemType != child_type)
1776 Child = Child.ConvertImplicitly (type.UnderlyingSystemType);
1780 if (!Convert.ImplicitStandardConversionExists (this, type)){
1784 return Child.ConvertImplicitly(type);
1790 /// This kind of cast is used to encapsulate Value Types in objects.
1792 /// The effect of it is to box the value type emitted by the previous
1795 public class BoxedCast : TypeCast {
1797 public BoxedCast (Expression expr, Type target_type)
1798 : base (expr, target_type)
1800 eclass = ExprClass.Value;
1803 public override Expression DoResolve (EmitContext ec)
1805 // This should never be invoked, we are born in fully
1806 // initialized state.
1811 public override void Emit (EmitContext ec)
1815 ec.ig.Emit (OpCodes.Box, child.Type);
1818 public override void EmitSideEffect (EmitContext ec)
1820 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1821 // so, we need to emit the box+pop instructions in most cases
1822 if (TypeManager.IsStruct (child.Type) &&
1823 (type == TypeManager.object_type || type == TypeManager.value_type))
1824 child.EmitSideEffect (ec);
1826 base.EmitSideEffect (ec);
1830 public class UnboxCast : TypeCast {
1831 public UnboxCast (Expression expr, Type return_type)
1832 : base (expr, return_type)
1836 public override Expression DoResolve (EmitContext ec)
1838 // This should never be invoked, we are born in fully
1839 // initialized state.
1844 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1846 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
1847 Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
1848 return base.DoResolveLValue (ec, right_side);
1851 public override void Emit (EmitContext ec)
1855 ILGenerator ig = ec.ig;
1858 ig.Emit (OpCodes.Unbox_Any, type);
1860 ig.Emit (OpCodes.Unbox, type);
1861 LoadFromPtr (ig, type);
1865 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1867 type = storey.MutateType (type);
1868 base.MutateHoistedGenericType (storey);
1873 /// This is used to perform explicit numeric conversions.
1875 /// Explicit numeric conversions might trigger exceptions in a checked
1876 /// context, so they should generate the conv.ovf opcodes instead of
1879 public class ConvCast : TypeCast {
1880 public enum Mode : byte {
1881 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1883 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1884 U2_I1, U2_U1, U2_I2, U2_CH,
1885 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1886 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1887 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH,
1888 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH,
1889 CH_I1, CH_U1, CH_I2,
1890 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1891 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4
1896 public ConvCast (Expression child, Type return_type, Mode m)
1897 : base (child, return_type)
1902 public override Expression DoResolve (EmitContext ec)
1904 // This should never be invoked, we are born in fully
1905 // initialized state.
1910 public override string ToString ()
1912 return String.Format ("ConvCast ({0}, {1})", mode, child);
1915 public override void Emit (EmitContext ec)
1917 ILGenerator ig = ec.ig;
1923 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1924 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1925 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1926 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1927 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1929 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1930 case Mode.U1_CH: /* nothing */ break;
1932 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1933 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1934 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1935 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1936 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1937 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1939 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1940 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1941 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1942 case Mode.U2_CH: /* nothing */ break;
1944 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1945 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1946 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1947 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1948 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1949 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1950 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1952 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1953 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1954 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1955 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1956 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1957 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1959 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1960 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1961 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1962 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1963 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1964 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1965 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1966 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1968 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1969 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1970 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1971 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1972 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1973 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1974 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1975 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1977 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1978 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1979 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1981 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1982 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1983 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1984 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1985 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1986 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1987 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1988 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1989 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1991 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1992 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1993 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1994 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1995 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1996 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1997 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1998 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1999 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
2000 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
2004 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
2005 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
2006 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
2007 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
2008 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
2010 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
2011 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
2013 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
2014 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
2015 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
2016 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
2017 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
2018 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
2020 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
2021 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
2022 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
2023 case Mode.U2_CH: /* nothing */ break;
2025 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
2026 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
2027 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
2028 case Mode.I4_U4: /* nothing */ break;
2029 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
2030 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
2031 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
2033 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
2034 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
2035 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
2036 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
2037 case Mode.U4_I4: /* nothing */ break;
2038 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
2040 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
2041 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
2042 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
2043 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
2044 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
2045 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
2046 case Mode.I8_U8: /* nothing */ break;
2047 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
2049 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
2050 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
2051 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
2052 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
2053 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
2054 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
2055 case Mode.U8_I8: /* nothing */ break;
2056 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
2058 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
2059 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
2060 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
2062 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
2063 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
2064 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
2065 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
2066 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
2067 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
2068 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
2069 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
2070 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
2072 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
2073 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
2074 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
2075 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
2076 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
2077 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
2078 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
2079 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
2080 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
2081 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
2087 public class OpcodeCast : TypeCast {
2090 public OpcodeCast (Expression child, Type return_type, OpCode op)
2091 : base (child, return_type)
2096 public override Expression DoResolve (EmitContext ec)
2098 // This should never be invoked, we are born in fully
2099 // initialized state.
2104 public override void Emit (EmitContext ec)
2110 public Type UnderlyingType {
2111 get { return child.Type; }
2116 /// This kind of cast is used to encapsulate a child and cast it
2117 /// to the class requested
2119 public sealed class ClassCast : TypeCast {
2120 readonly bool forced;
2122 public ClassCast (Expression child, Type return_type)
2123 : base (child, return_type)
2127 public ClassCast (Expression child, Type return_type, bool forced)
2128 : base (child, return_type)
2130 this.forced = forced;
2133 public override void Emit (EmitContext ec)
2138 bool gen = TypeManager.IsGenericParameter (child.Type);
2140 ec.ig.Emit (OpCodes.Box, child.Type);
2142 if (type.IsGenericParameter) {
2143 ec.ig.Emit (OpCodes.Unbox_Any, type);
2151 ec.ig.Emit (OpCodes.Castclass, type);
2156 // Created during resolving pahse when an expression is wrapped or constantified
2157 // and original expression can be used later (e.g. for expression trees)
2159 public class ReducedExpression : Expression
2161 sealed class ReducedConstantExpression : EmptyConstantCast
2163 readonly Expression orig_expr;
2165 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2166 : base (expr, expr.Type)
2168 this.orig_expr = orig_expr;
2171 public override Constant ConvertImplicitly (Type target_type)
2173 Constant c = base.ConvertImplicitly (target_type);
2175 c = new ReducedConstantExpression (c, orig_expr);
2179 public override Expression CreateExpressionTree (EmitContext ec)
2181 return orig_expr.CreateExpressionTree (ec);
2184 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
2187 // Even if resolved result is a constant original expression was not
2188 // and attribute accepts constants only
2190 Attribute.Error_AttributeArgumentNotValid (orig_expr.Location);
2195 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
2197 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
2199 c = new ReducedConstantExpression (c, orig_expr);
2204 sealed class ReducedExpressionStatement : ExpressionStatement
2206 readonly Expression orig_expr;
2207 readonly ExpressionStatement stm;
2209 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
2211 this.orig_expr = orig;
2213 this.loc = orig.Location;
2216 public override Expression CreateExpressionTree (EmitContext ec)
2218 return orig_expr.CreateExpressionTree (ec);
2221 public override Expression DoResolve (EmitContext ec)
2223 eclass = stm.eclass;
2228 public override void Emit (EmitContext ec)
2233 public override void EmitStatement (EmitContext ec)
2235 stm.EmitStatement (ec);
2238 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2240 stm.MutateHoistedGenericType (storey);
2244 readonly Expression expr, orig_expr;
2246 private ReducedExpression (Expression expr, Expression orig_expr)
2249 this.orig_expr = orig_expr;
2250 this.loc = orig_expr.Location;
2253 public static Constant Create (Constant expr, Expression original_expr)
2255 return new ReducedConstantExpression (expr, original_expr);
2258 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
2260 return new ReducedExpressionStatement (s, orig);
2263 public static Expression Create (Expression expr, Expression original_expr)
2265 Constant c = expr as Constant;
2267 return Create (c, original_expr);
2269 ExpressionStatement s = expr as ExpressionStatement;
2271 return Create (s, original_expr);
2273 return new ReducedExpression (expr, original_expr);
2276 public override Expression CreateExpressionTree (EmitContext ec)
2278 return orig_expr.CreateExpressionTree (ec);
2281 public override Expression DoResolve (EmitContext ec)
2283 eclass = expr.eclass;
2288 public override void Emit (EmitContext ec)
2293 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2295 expr.EmitBranchable (ec, target, on_true);
2298 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2300 expr.MutateHoistedGenericType (storey);
2305 // Unresolved type name expressions
2307 public abstract class ATypeNameExpression : FullNamedExpression
2309 public readonly string Name;
2310 protected TypeArguments targs;
2312 protected ATypeNameExpression (string name, Location l)
2318 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2325 public bool HasTypeArguments {
2327 return targs != null;
2331 public override bool Equals (object obj)
2333 ATypeNameExpression atne = obj as ATypeNameExpression;
2334 return atne != null && atne.Name == Name &&
2335 (targs == null || targs.Equals (atne.targs));
2338 public override int GetHashCode ()
2340 return Name.GetHashCode ();
2343 public override string GetSignatureForError ()
2345 if (targs != null) {
2346 return TypeManager.RemoveGenericArity (Name) + "<" +
2347 targs.GetSignatureForError () + ">";
2355 /// SimpleName expressions are formed of a single word and only happen at the beginning
2356 /// of a dotted-name.
2358 public class SimpleName : ATypeNameExpression {
2361 public SimpleName (string name, Location l)
2366 public SimpleName (string name, TypeArguments args, Location l)
2367 : base (name, args, l)
2371 public SimpleName (string name, TypeParameter[] type_params, Location l)
2374 targs = new TypeArguments ();
2375 foreach (TypeParameter type_param in type_params)
2376 targs.Add (new TypeParameterExpr (type_param, l));
2379 public static string RemoveGenericArity (string name)
2382 StringBuilder sb = null;
2384 int pos = name.IndexOf ('`', start);
2389 sb.Append (name.Substring (start));
2394 sb = new StringBuilder ();
2395 sb.Append (name.Substring (start, pos-start));
2398 while ((pos < name.Length) && Char.IsNumber (name [pos]))
2402 } while (start < name.Length);
2404 return sb.ToString ();
2407 public SimpleName GetMethodGroup ()
2409 return new SimpleName (RemoveGenericArity (Name), targs, loc);
2412 public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
2414 if (ec.IsInFieldInitializer)
2415 Report.Error (236, l,
2416 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2419 Report.Error (120, l,
2420 "An object reference is required to access non-static member `{0}'",
2424 public bool IdenticalNameAndTypeName (EmitContext ec, Expression resolved_to, Location loc)
2426 return resolved_to != null && resolved_to.Type != null &&
2427 resolved_to.Type.Name == Name &&
2428 (ec.DeclContainer.LookupNamespaceOrType (Name, loc, /* ignore_cs0104 = */ true) != null);
2431 public override Expression DoResolve (EmitContext ec)
2433 return SimpleNameResolve (ec, null, false);
2436 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
2438 return SimpleNameResolve (ec, right_side, false);
2442 public Expression DoResolve (EmitContext ec, bool intermediate)
2444 return SimpleNameResolve (ec, null, intermediate);
2447 static bool IsNestedChild (Type t, Type parent)
2449 while (parent != null) {
2450 if (TypeManager.IsNestedChildOf (t, TypeManager.DropGenericTypeArguments (parent)))
2453 parent = parent.BaseType;
2459 FullNamedExpression ResolveNested (IResolveContext ec, Type t)
2461 if (!TypeManager.IsGenericTypeDefinition (t) && !TypeManager.IsGenericType (t))
2464 DeclSpace ds = ec.DeclContainer;
2465 while (ds != null && !IsNestedChild (t, ds.TypeBuilder))
2471 Type[] gen_params = TypeManager.GetTypeArguments (t);
2473 int arg_count = targs != null ? targs.Count : 0;
2475 for (; (ds != null) && ds.IsGeneric; ds = ds.Parent) {
2476 if (arg_count + ds.CountTypeParameters == gen_params.Length) {
2477 TypeArguments new_args = new TypeArguments ();
2478 foreach (TypeParameter param in ds.TypeParameters)
2479 new_args.Add (new TypeParameterExpr (param, loc));
2482 new_args.Add (targs);
2484 return new GenericTypeExpr (t, new_args, loc);
2491 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2493 FullNamedExpression fne = ec.GenericDeclContainer.LookupGeneric (Name, loc);
2495 return fne.ResolveAsTypeStep (ec, silent);
2497 int errors = Report.Errors;
2498 fne = ec.DeclContainer.LookupNamespaceOrType (Name, loc, /*ignore_cs0104=*/ false);
2501 if (fne.Type == null)
2504 FullNamedExpression nested = ResolveNested (ec, fne.Type);
2506 return nested.ResolveAsTypeStep (ec, false);
2508 if (targs != null) {
2509 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2510 return ct.ResolveAsTypeStep (ec, false);
2516 if (silent || errors != Report.Errors)
2519 Error_TypeOrNamespaceNotFound (ec);
2523 protected virtual void Error_TypeOrNamespaceNotFound (IResolveContext ec)
2525 MemberCore mc = ec.DeclContainer.GetDefinition (Name);
2527 Error_UnexpectedKind (ec.DeclContainer, "type", GetMemberType (mc), loc);
2531 string ns = ec.DeclContainer.NamespaceEntry.NS.Name;
2532 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2533 foreach (Assembly a in GlobalRootNamespace.Instance.Assemblies) {
2534 Type type = a.GetType (fullname);
2536 Report.SymbolRelatedToPreviousError (type);
2537 Expression.ErrorIsInaccesible (loc, TypeManager.CSharpName (type));
2542 Type t = ec.DeclContainer.LookupAnyGeneric (Name);
2544 Namespace.Error_InvalidNumberOfTypeArguments (t, loc);
2548 if (targs != null) {
2549 FullNamedExpression retval = ec.DeclContainer.LookupNamespaceOrType (SimpleName.RemoveGenericArity (Name), loc, true);
2550 if (retval != null) {
2551 Namespace.Error_TypeArgumentsCannotBeUsed (retval, loc);
2556 NamespaceEntry.Error_NamespaceNotFound (loc, Name);
2559 // TODO: I am still not convinced about this. If someone else will need it
2560 // implement this as virtual property in MemberCore hierarchy
2561 public static string GetMemberType (MemberCore mc)
2567 if (mc is FieldBase)
2569 if (mc is MethodCore)
2571 if (mc is EnumMember)
2579 Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2585 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2591 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2598 /// 7.5.2: Simple Names.
2600 /// Local Variables and Parameters are handled at
2601 /// parse time, so they never occur as SimpleNames.
2603 /// The `intermediate' flag is used by MemberAccess only
2604 /// and it is used to inform us that it is ok for us to
2605 /// avoid the static check, because MemberAccess might end
2606 /// up resolving the Name as a Type name and the access as
2607 /// a static type access.
2609 /// ie: Type Type; .... { Type.GetType (""); }
2611 /// Type is both an instance variable and a Type; Type.GetType
2612 /// is the static method not an instance method of type.
2614 Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2616 Expression e = null;
2619 // Stage 1: Performed by the parser (binding to locals or parameters).
2621 Block current_block = ec.CurrentBlock;
2622 if (current_block != null){
2623 LocalInfo vi = current_block.GetLocalInfo (Name);
2625 LocalVariableReference var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2626 if (right_side != null) {
2627 return var.ResolveLValue (ec, right_side, loc);
2629 ResolveFlags rf = ResolveFlags.VariableOrValue;
2631 rf |= ResolveFlags.DisableFlowAnalysis;
2632 return var.Resolve (ec, rf);
2636 Expression expr = current_block.Toplevel.GetParameterReference (Name, loc);
2638 if (right_side != null)
2639 return expr.ResolveLValue (ec, right_side, loc);
2641 return expr.Resolve (ec);
2646 // Stage 2: Lookup members
2649 Type almost_matched_type = null;
2650 ArrayList almost_matched = null;
2651 for (DeclSpace lookup_ds = ec.DeclContainer; lookup_ds != null; lookup_ds = lookup_ds.Parent) {
2652 // either RootDeclSpace or GenericMethod
2653 if (lookup_ds.TypeBuilder == null)
2656 e = MemberLookup (ec.ContainerType, lookup_ds.TypeBuilder, Name, loc);
2658 PropertyExpr pe = e as PropertyExpr;
2660 AParametersCollection param = TypeManager.GetParameterData (pe.PropertyInfo);
2662 // since TypeManager.MemberLookup doesn't know if we're doing a lvalue access or not,
2663 // it doesn't know which accessor to check permissions against
2664 if (param.IsEmpty && pe.IsAccessibleFrom (ec.ContainerType, right_side != null))
2666 } else if (e is EventExpr) {
2667 if (((EventExpr) e).IsAccessibleFrom (ec.ContainerType))
2669 } else if (targs != null && e is TypeExpression) {
2670 e = new GenericTypeExpr (e.Type, targs, loc).ResolveAsTypeStep (ec, false);
2678 if (almost_matched == null && almost_matched_members.Count > 0) {
2679 almost_matched_type = lookup_ds.TypeBuilder;
2680 almost_matched = (ArrayList) almost_matched_members.Clone ();
2685 if (almost_matched == null && almost_matched_members.Count > 0) {
2686 almost_matched_type = ec.ContainerType;
2687 almost_matched = (ArrayList) almost_matched_members.Clone ();
2689 e = ResolveAsTypeStep (ec, true);
2693 if (current_block != null) {
2694 IKnownVariable ikv = current_block.Explicit.GetKnownVariable (Name);
2696 LocalInfo li = ikv as LocalInfo;
2697 // Supress CS0219 warning
2701 Error_VariableIsUsedBeforeItIsDeclared (Name);
2706 if (RootContext.EvalMode){
2707 FieldInfo fi = Evaluator.LookupField (Name);
2709 return new FieldExpr (fi, loc).Resolve (ec);
2712 if (almost_matched != null)
2713 almost_matched_members = almost_matched;
2714 if (almost_matched_type == null)
2715 almost_matched_type = ec.ContainerType;
2716 return Error_MemberLookupFailed (ec.ContainerType, null, almost_matched_type, Name,
2717 ec.DeclContainer.Name, AllMemberTypes, AllBindingFlags);
2720 if (e is MemberExpr) {
2721 MemberExpr me = (MemberExpr) e;
2724 if (me.IsInstance) {
2725 if (ec.IsStatic || ec.IsInFieldInitializer) {
2727 // Note that an MemberExpr can be both IsInstance and IsStatic.
2728 // An unresolved MethodGroupExpr can contain both kinds of methods
2729 // and each predicate is true if the MethodGroupExpr contains
2730 // at least one of that kind of method.
2734 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2735 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2740 // Pass the buck to MemberAccess and Invocation.
2742 left = EmptyExpression.Null;
2744 left = ec.GetThis (loc);
2747 left = new TypeExpression (ec.ContainerType, loc);
2750 me = me.ResolveMemberAccess (ec, left, loc, null);
2754 if (targs != null) {
2755 if (!targs.Resolve (ec))
2758 me.SetTypeArguments (targs);
2761 if (!me.IsStatic && (me.InstanceExpression != null && me.InstanceExpression != EmptyExpression.Null) &&
2762 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2763 me.InstanceExpression.Type != me.DeclaringType &&
2764 !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2765 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2766 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2767 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2771 return (right_side != null)
2772 ? me.DoResolveLValue (ec, right_side)
2773 : me.DoResolve (ec);
2781 /// Represents a namespace or a type. The name of the class was inspired by
2782 /// section 10.8.1 (Fully Qualified Names).
2784 public abstract class FullNamedExpression : Expression
2786 protected override void CloneTo (CloneContext clonectx, Expression target)
2788 // Do nothing, most unresolved type expressions cannot be
2789 // resolved to different type
2792 public override Expression CreateExpressionTree (EmitContext ec)
2794 throw new NotSupportedException ("ET");
2797 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2799 throw new NotSupportedException ();
2802 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2807 public override void Emit (EmitContext ec)
2809 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2810 GetSignatureForError ());
2815 /// Expression that evaluates to a type
2817 public abstract class TypeExpr : FullNamedExpression {
2818 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2820 TypeExpr t = DoResolveAsTypeStep (ec);
2824 eclass = ExprClass.Type;
2828 override public Expression DoResolve (EmitContext ec)
2830 return ResolveAsTypeTerminal (ec, false);
2833 public virtual bool CheckAccessLevel (DeclSpace ds)
2835 return ds.CheckAccessLevel (Type);
2838 public virtual bool IsClass {
2839 get { return Type.IsClass; }
2842 public virtual bool IsValueType {
2843 get { return TypeManager.IsStruct (Type); }
2846 public virtual bool IsInterface {
2847 get { return Type.IsInterface; }
2850 public virtual bool IsSealed {
2851 get { return Type.IsSealed; }
2854 public virtual bool CanInheritFrom ()
2856 if (Type == TypeManager.enum_type ||
2857 (Type == TypeManager.value_type && RootContext.StdLib) ||
2858 Type == TypeManager.multicast_delegate_type ||
2859 Type == TypeManager.delegate_type ||
2860 Type == TypeManager.array_type)
2866 protected abstract TypeExpr DoResolveAsTypeStep (IResolveContext ec);
2868 public override bool Equals (object obj)
2870 TypeExpr tobj = obj as TypeExpr;
2874 return Type == tobj.Type;
2877 public override int GetHashCode ()
2879 return Type.GetHashCode ();
2882 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2884 type = storey.MutateType (type);
2889 /// Fully resolved Expression that already evaluated to a type
2891 public class TypeExpression : TypeExpr {
2892 public TypeExpression (Type t, Location l)
2895 eclass = ExprClass.Type;
2899 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2904 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2911 // Used to create types from a fully qualified name. These are just used
2912 // by the parser to setup the core types.
2914 public sealed class TypeLookupExpression : TypeExpr {
2915 readonly string ns_name;
2916 readonly string name;
2918 public TypeLookupExpression (string ns, string name)
2922 eclass = ExprClass.Type;
2925 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2928 // It's null only during mscorlib bootstrap when DefineType
2929 // nees to resolve base type of same type
2931 // For instance struct Char : IComparable<char>
2933 // TODO: it could be removed when Resolve starts to use
2934 // DeclSpace instead of Type
2937 Namespace ns = GlobalRootNamespace.Instance.GetNamespace (ns_name, false);
2938 FullNamedExpression fne = ns.Lookup (null, name, loc);
2946 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2951 public override string GetSignatureForError ()
2954 return TypeManager.CSharpName (ns_name + "." + name, null);
2956 return base.GetSignatureForError ();
2961 /// This class denotes an expression which evaluates to a member
2962 /// of a struct or a class.
2964 public abstract class MemberExpr : Expression
2966 protected bool is_base;
2969 /// The name of this member.
2971 public abstract string Name {
2976 // When base.member is used
2978 public bool IsBase {
2979 get { return is_base; }
2980 set { is_base = value; }
2984 /// Whether this is an instance member.
2986 public abstract bool IsInstance {
2991 /// Whether this is a static member.
2993 public abstract bool IsStatic {
2998 /// The type which declares this member.
3000 public abstract Type DeclaringType {
3005 /// The instance expression associated with this member, if it's a
3006 /// non-static member.
3008 public Expression InstanceExpression;
3010 public static void error176 (Location loc, string name)
3012 Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
3013 "with an instance reference, qualify it with a type name instead", name);
3016 public static void Error_BaseAccessInExpressionTree (Location loc)
3018 Report.Error (831, loc, "An expression tree may not contain a base access");
3021 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3023 if (InstanceExpression != null)
3024 InstanceExpression.MutateHoistedGenericType (storey);
3027 // TODO: possible optimalization
3028 // Cache resolved constant result in FieldBuilder <-> expression map
3029 public virtual MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3030 SimpleName original)
3034 // original == null || original.Resolve (...) ==> left
3037 if (left is TypeExpr) {
3038 left = left.ResolveAsBaseTerminal (ec, false);
3042 // TODO: Same problem as in class.cs, TypeTerminal does not
3043 // always do all necessary checks
3044 ObsoleteAttribute oa = AttributeTester.GetObsoleteAttribute (left.Type);
3045 if (oa != null && !ec.IsInObsoleteScope) {
3046 AttributeTester.Report_ObsoleteMessage (oa, left.GetSignatureForError (), loc);
3049 GenericTypeExpr ct = left as GenericTypeExpr;
3050 if (ct != null && !ct.CheckConstraints (ec))
3055 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3063 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3066 return ResolveExtensionMemberAccess (left);
3069 InstanceExpression = left;
3073 protected virtual MemberExpr ResolveExtensionMemberAccess (Expression left)
3075 error176 (loc, GetSignatureForError ());
3079 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3084 if (InstanceExpression == EmptyExpression.Null) {
3085 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3089 if (TypeManager.IsValueType (InstanceExpression.Type)) {
3090 if (InstanceExpression is IMemoryLocation) {
3091 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
3093 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
3094 InstanceExpression.Emit (ec);
3096 t.AddressOf (ec, AddressOp.Store);
3099 InstanceExpression.Emit (ec);
3101 if (prepare_for_load)
3102 ec.ig.Emit (OpCodes.Dup);
3105 public virtual void SetTypeArguments (TypeArguments ta)
3107 // TODO: need to get correct member type
3108 Report.Error (307, loc, "The property `{0}' cannot be used with type arguments",
3109 GetSignatureForError ());
3114 /// Represents group of extension methods
3116 public class ExtensionMethodGroupExpr : MethodGroupExpr
3118 readonly NamespaceEntry namespace_entry;
3119 public Expression ExtensionExpression;
3120 Argument extension_argument;
3122 public ExtensionMethodGroupExpr (ArrayList list, NamespaceEntry n, Type extensionType, Location l)
3123 : base (list, extensionType, l)
3125 this.namespace_entry = n;
3128 public override bool IsStatic {
3129 get { return true; }
3132 public bool IsTopLevel {
3133 get { return namespace_entry == null; }
3136 public override void EmitArguments (EmitContext ec, ArrayList arguments)
3138 if (arguments == null)
3139 arguments = new ArrayList (1);
3140 arguments.Insert (0, extension_argument);
3141 base.EmitArguments (ec, arguments);
3144 public override void EmitCall (EmitContext ec, ArrayList arguments)
3146 if (arguments == null)
3147 arguments = new ArrayList (1);
3148 arguments.Insert (0, extension_argument);
3149 base.EmitCall (ec, arguments);
3152 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3154 extension_argument.Expr.MutateHoistedGenericType (storey);
3155 base.MutateHoistedGenericType (storey);
3158 public override MethodGroupExpr OverloadResolve (EmitContext ec, ref ArrayList arguments, bool may_fail, Location loc)
3160 if (arguments == null)
3161 arguments = new ArrayList (1);
3163 arguments.Insert (0, new Argument (ExtensionExpression));
3164 MethodGroupExpr mg = ResolveOverloadExtensions (ec, arguments, namespace_entry, loc);
3166 // Store resolved argument and restore original arguments
3168 ((ExtensionMethodGroupExpr)mg).extension_argument = (Argument)arguments [0];
3169 arguments.RemoveAt (0);
3174 MethodGroupExpr ResolveOverloadExtensions (EmitContext ec, ArrayList arguments, NamespaceEntry ns, Location loc)
3176 // Use normal resolve rules
3177 MethodGroupExpr mg = base.OverloadResolve (ec, ref arguments, ns != null, loc);
3185 ExtensionMethodGroupExpr e = ns.LookupExtensionMethod (type, null, Name, loc);
3187 return base.OverloadResolve (ec, ref arguments, false, loc);
3189 e.ExtensionExpression = ExtensionExpression;
3190 e.SetTypeArguments (type_arguments);
3191 return e.ResolveOverloadExtensions (ec, arguments, e.namespace_entry, loc);
3196 /// MethodGroupExpr represents a group of method candidates which
3197 /// can be resolved to the best method overload
3199 public class MethodGroupExpr : MemberExpr
3201 public interface IErrorHandler
3203 bool AmbiguousCall (MethodBase ambiguous);
3204 bool NoExactMatch (EmitContext ec, MethodBase method);
3207 public IErrorHandler CustomErrorHandler;
3208 public MethodBase [] Methods;
3209 MethodBase best_candidate;
3210 // TODO: make private
3211 public TypeArguments type_arguments;
3212 bool identical_type_name;
3213 bool has_inaccessible_candidates_only;
3217 public MethodGroupExpr (MemberInfo [] mi, Type type, Location l)
3220 Methods = new MethodBase [mi.Length];
3221 mi.CopyTo (Methods, 0);
3224 public MethodGroupExpr (MemberInfo[] mi, Type type, Location l, bool inacessibleCandidatesOnly)
3225 : this (mi, type, l)
3227 has_inaccessible_candidates_only = inacessibleCandidatesOnly;
3230 public MethodGroupExpr (ArrayList list, Type type, Location l)
3234 Methods = (MethodBase[])list.ToArray (typeof (MethodBase));
3236 foreach (MemberInfo m in list){
3237 if (!(m is MethodBase)){
3238 Console.WriteLine ("Name " + m.Name);
3239 Console.WriteLine ("Found a: " + m.GetType ().FullName);
3248 protected MethodGroupExpr (Type type, Location loc)
3251 eclass = ExprClass.MethodGroup;
3252 this.type = typeof (MethodGroupExpr);
3253 queried_type = type;
3256 public override Type DeclaringType {
3258 return queried_type;
3262 public Type DelegateType {
3264 delegate_type = value;
3268 public bool IdenticalTypeName {
3270 return identical_type_name;
3274 public override string GetSignatureForError ()
3276 if (best_candidate != null)
3277 return TypeManager.CSharpSignature (best_candidate);
3279 return TypeManager.CSharpSignature (Methods [0]);
3282 public override string Name {
3284 return Methods [0].Name;
3288 public override bool IsInstance {
3290 if (best_candidate != null)
3291 return !best_candidate.IsStatic;
3293 foreach (MethodBase mb in Methods)
3301 public override bool IsStatic {
3303 if (best_candidate != null)
3304 return best_candidate.IsStatic;
3306 foreach (MethodBase mb in Methods)
3314 public static explicit operator ConstructorInfo (MethodGroupExpr mg)
3316 return (ConstructorInfo)mg.best_candidate;
3319 public static explicit operator MethodInfo (MethodGroupExpr mg)
3321 return (MethodInfo)mg.best_candidate;
3325 // 7.4.3.3 Better conversion from expression
3326 // Returns : 1 if a->p is better,
3327 // 2 if a->q is better,
3328 // 0 if neither is better
3330 static int BetterExpressionConversion (EmitContext ec, Argument a, Type p, Type q)
3332 Type argument_type = TypeManager.TypeToCoreType (a.Type);
3333 if (argument_type == TypeManager.anonymous_method_type && RootContext.Version > LanguageVersion.ISO_2) {
3335 // Uwrap delegate from Expression<T>
3337 if (TypeManager.DropGenericTypeArguments (p) == TypeManager.expression_type) {
3338 p = TypeManager.GetTypeArguments (p) [0];
3340 if (TypeManager.DropGenericTypeArguments (q) == TypeManager.expression_type) {
3341 q = TypeManager.GetTypeArguments (q) [0];
3344 p = Delegate.GetInvokeMethod (null, p).ReturnType;
3345 q = Delegate.GetInvokeMethod (null, q).ReturnType;
3346 if (p == TypeManager.void_type && q != TypeManager.void_type)
3348 if (q == TypeManager.void_type && p != TypeManager.void_type)
3351 if (argument_type == p)
3354 if (argument_type == q)
3358 return BetterTypeConversion (ec, p, q);
3362 // 7.4.3.4 Better conversion from type
3364 public static int BetterTypeConversion (EmitContext ec, Type p, Type q)
3366 if (p == null || q == null)
3367 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3369 if (p == TypeManager.int32_type) {
3370 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3372 } else if (p == TypeManager.int64_type) {
3373 if (q == TypeManager.uint64_type)
3375 } else if (p == TypeManager.sbyte_type) {
3376 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3377 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3379 } else if (p == TypeManager.short_type) {
3380 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3381 q == TypeManager.uint64_type)
3385 if (q == TypeManager.int32_type) {
3386 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3388 } if (q == TypeManager.int64_type) {
3389 if (p == TypeManager.uint64_type)
3391 } else if (q == TypeManager.sbyte_type) {
3392 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3393 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3395 } if (q == TypeManager.short_type) {
3396 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3397 p == TypeManager.uint64_type)
3401 // TODO: this is expensive
3402 Expression p_tmp = new EmptyExpression (p);
3403 Expression q_tmp = new EmptyExpression (q);
3405 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3406 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3408 if (p_to_q && !q_to_p)
3411 if (q_to_p && !p_to_q)
3418 /// Determines "Better function" between candidate
3419 /// and the current best match
3422 /// Returns a boolean indicating :
3423 /// false if candidate ain't better
3424 /// true if candidate is better than the current best match
3426 static bool BetterFunction (EmitContext ec, ArrayList args, int argument_count,
3427 MethodBase candidate, bool candidate_params,
3428 MethodBase best, bool best_params)
3430 AParametersCollection candidate_pd = TypeManager.GetParameterData (candidate);
3431 AParametersCollection best_pd = TypeManager.GetParameterData (best);
3433 bool better_at_least_one = false;
3435 for (int j = 0, c_idx = 0, b_idx = 0; j < argument_count; ++j, ++c_idx, ++b_idx)
3437 Argument a = (Argument) args [j];
3439 Type ct = candidate_pd.Types [c_idx];
3440 Type bt = best_pd.Types [b_idx];
3442 if (candidate_params && candidate_pd.FixedParameters [c_idx].ModFlags == Parameter.Modifier.PARAMS)
3444 ct = TypeManager.GetElementType (ct);
3448 if (best_params && best_pd.FixedParameters [b_idx].ModFlags == Parameter.Modifier.PARAMS)
3450 bt = TypeManager.GetElementType (bt);
3458 int result = BetterExpressionConversion (ec, a, ct, bt);
3460 // for each argument, the conversion to 'ct' should be no worse than
3461 // the conversion to 'bt'.
3465 // for at least one argument, the conversion to 'ct' should be better than
3466 // the conversion to 'bt'.
3468 better_at_least_one = true;
3471 if (better_at_least_one)
3475 // This handles the case
3477 // Add (float f1, float f2, float f3);
3478 // Add (params decimal [] foo);
3480 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3481 // first candidate would've chosen as better.
3487 // The two methods have equal parameter types. Now apply tie-breaking rules
3489 if (TypeManager.IsGenericMethod (best)) {
3490 if (!TypeManager.IsGenericMethod (candidate))
3492 } else if (TypeManager.IsGenericMethod (candidate)) {
3497 // This handles the following cases:
3499 // Trim () is better than Trim (params char[] chars)
3500 // Concat (string s1, string s2, string s3) is better than
3501 // Concat (string s1, params string [] srest)
3502 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3504 if (!candidate_params && best_params)
3506 if (candidate_params && !best_params)
3509 int candidate_param_count = candidate_pd.Count;
3510 int best_param_count = best_pd.Count;
3512 if (candidate_param_count != best_param_count)
3513 // can only happen if (candidate_params && best_params)
3514 return candidate_param_count > best_param_count;
3517 // now, both methods have the same number of parameters, and the parameters have the same types
3518 // Pick the "more specific" signature
3521 MethodBase orig_candidate = TypeManager.DropGenericMethodArguments (candidate);
3522 MethodBase orig_best = TypeManager.DropGenericMethodArguments (best);
3524 AParametersCollection orig_candidate_pd = TypeManager.GetParameterData (orig_candidate);
3525 AParametersCollection orig_best_pd = TypeManager.GetParameterData (orig_best);
3527 bool specific_at_least_once = false;
3528 for (int j = 0; j < candidate_param_count; ++j)
3530 Type ct = orig_candidate_pd.Types [j];
3531 Type bt = orig_best_pd.Types [j];
3534 Type specific = MoreSpecific (ct, bt);
3538 specific_at_least_once = true;
3541 if (specific_at_least_once)
3544 // FIXME: handle lifted operators
3550 protected override MemberExpr ResolveExtensionMemberAccess (Expression left)
3553 return base.ResolveExtensionMemberAccess (left);
3556 // When left side is an expression and at least one candidate method is
3557 // static, it can be extension method
3559 InstanceExpression = left;
3563 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3564 SimpleName original)
3566 if (!(left is TypeExpr) &&
3567 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3568 identical_type_name = true;
3570 return base.ResolveMemberAccess (ec, left, loc, original);
3573 public override Expression CreateExpressionTree (EmitContext ec)
3575 if (best_candidate == null) {
3576 Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3580 if (best_candidate.IsConstructor)
3581 return new TypeOfConstructorInfo (best_candidate, loc);
3583 IMethodData md = TypeManager.GetMethod (best_candidate);
3584 if (md != null && md.IsExcluded ())
3585 Report.Error (765, loc,
3586 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3588 return new TypeOfMethodInfo (best_candidate, loc);
3591 override public Expression DoResolve (EmitContext ec)
3593 if (InstanceExpression != null) {
3594 InstanceExpression = InstanceExpression.DoResolve (ec);
3595 if (InstanceExpression == null)
3602 public void ReportUsageError ()
3604 Report.Error (654, loc, "Method `" + DeclaringType + "." +
3605 Name + "()' is referenced without parentheses");
3608 override public void Emit (EmitContext ec)
3610 ReportUsageError ();
3613 public virtual void EmitArguments (EmitContext ec, ArrayList arguments)
3615 Invocation.EmitArguments (ec, arguments, false, null);
3618 public virtual void EmitCall (EmitContext ec, ArrayList arguments)
3620 Invocation.EmitCall (ec, IsBase, InstanceExpression, best_candidate, arguments, loc);
3623 void Error_AmbiguousCall (MethodBase ambiguous)
3625 if (CustomErrorHandler != null && CustomErrorHandler.AmbiguousCall (ambiguous))
3628 Report.SymbolRelatedToPreviousError (best_candidate);
3629 Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
3630 TypeManager.CSharpSignature (ambiguous), TypeManager.CSharpSignature (best_candidate));
3633 protected virtual void Error_InvalidArguments (EmitContext ec, Location loc, int idx, MethodBase method,
3634 Argument a, AParametersCollection expected_par, Type paramType)
3636 ExtensionMethodGroupExpr emg = this as ExtensionMethodGroupExpr;
3638 if (a is CollectionElementInitializer.ElementInitializerArgument) {
3639 Report.SymbolRelatedToPreviousError (method);
3640 if ((expected_par.FixedParameters [idx].ModFlags & Parameter.Modifier.ISBYREF) != 0) {
3641 Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
3642 TypeManager.CSharpSignature (method));
3645 Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
3646 TypeManager.CSharpSignature (method));
3647 } else if (TypeManager.IsDelegateType (method.DeclaringType)) {
3648 Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
3649 TypeManager.CSharpName (method.DeclaringType));
3651 Report.SymbolRelatedToPreviousError (method);
3653 Report.Error (1928, loc,
3654 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3655 emg.ExtensionExpression.GetSignatureForError (),
3656 emg.Name, TypeManager.CSharpSignature (method));
3658 Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
3659 TypeManager.CSharpSignature (method));
3663 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters [idx].ModFlags;
3665 string index = (idx + 1).ToString ();
3666 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
3667 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
3668 if ((mod & Parameter.Modifier.ISBYREF) == 0)
3669 Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
3670 index, Parameter.GetModifierSignature (a.Modifier));
3672 Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
3673 index, Parameter.GetModifierSignature (mod));
3675 string p1 = a.GetSignatureForError ();
3676 string p2 = TypeManager.CSharpName (paramType);
3679 Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
3680 Report.SymbolRelatedToPreviousError (a.Expr.Type);
3681 Report.SymbolRelatedToPreviousError (paramType);
3684 if (idx == 0 && emg != null) {
3685 Report.Error (1929, loc,
3686 "Extension method instance type `{0}' cannot be converted to `{1}'", p1, p2);
3688 Report.Error (1503, loc,
3689 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
3694 public override void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl)
3696 Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3697 Name, TypeManager.CSharpName (target));
3700 void Error_ArgumentCountWrong (int arg_count)
3702 Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
3703 Name, arg_count.ToString ());
3706 protected virtual int GetApplicableParametersCount (MethodBase method, AParametersCollection parameters)
3708 return parameters.Count;
3711 public static bool IsAncestralType (Type first_type, Type second_type)
3713 return first_type != second_type &&
3714 (TypeManager.IsSubclassOf (second_type, first_type) ||
3715 TypeManager.ImplementsInterface (second_type, first_type));
3719 /// Determines if the candidate method is applicable (section 14.4.2.1)
3720 /// to the given set of arguments
3721 /// A return value rates candidate method compatibility,
3722 /// 0 = the best, int.MaxValue = the worst
3724 public int IsApplicable (EmitContext ec,
3725 ArrayList arguments, int arg_count, ref MethodBase method, ref bool params_expanded_form)
3727 MethodBase candidate = method;
3729 AParametersCollection pd = TypeManager.GetParameterData (candidate);
3730 int param_count = GetApplicableParametersCount (candidate, pd);
3732 if (arg_count != param_count) {
3734 return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
3735 if (arg_count < param_count - 1)
3736 return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
3738 // Initialize expanded form of a method with 1 params parameter
3739 params_expanded_form = param_count == 1 && pd.HasParams;
3744 // 1. Handle generic method using type arguments when specified or type inference
3746 if (TypeManager.IsGenericMethod (candidate)) {
3747 if (type_arguments != null) {
3748 Type [] g_args = candidate.GetGenericArguments ();
3749 if (g_args.Length != type_arguments.Count)
3750 return int.MaxValue - 20000 + Math.Abs (type_arguments.Count - g_args.Length);
3752 // TODO: Don't create new method, create Parameters only
3753 method = ((MethodInfo) candidate).MakeGenericMethod (type_arguments.Arguments);
3755 pd = TypeManager.GetParameterData (candidate);
3757 int score = TypeManager.InferTypeArguments (ec, arguments, ref candidate);
3759 return score - 20000;
3761 if (TypeManager.IsGenericMethodDefinition (candidate))
3762 throw new InternalErrorException ("A generic method `{0}' definition took part in overload resolution",
3763 TypeManager.CSharpSignature (candidate));
3765 pd = TypeManager.GetParameterData (candidate);
3768 if (type_arguments != null)
3769 return int.MaxValue - 15000;
3774 // 2. Each argument has to be implicitly convertible to method parameter
3777 Parameter.Modifier p_mod = 0;
3779 for (int i = 0; i < arg_count; i++) {
3780 Argument a = (Argument) arguments [i];
3781 Parameter.Modifier a_mod = a.Modifier &
3782 ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3784 if (p_mod != Parameter.Modifier.PARAMS) {
3785 p_mod = pd.FixedParameters [i].ModFlags & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3787 if (p_mod == Parameter.Modifier.ARGLIST) {
3788 if (a.Type == TypeManager.runtime_argument_handle_type)
3796 params_expanded_form = true;
3800 if (!params_expanded_form)
3801 score = IsArgumentCompatible (ec, a_mod, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
3803 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && delegate_type == null) {
3804 // It can be applicable in expanded form
3805 score = IsArgumentCompatible (ec, a_mod, a, 0, TypeManager.GetElementType (pt));
3807 params_expanded_form = true;
3811 if (params_expanded_form)
3813 return (arg_count - i) * 2 + score;
3817 if (arg_count != param_count)
3818 params_expanded_form = true;
3823 int IsArgumentCompatible (EmitContext ec, Parameter.Modifier arg_mod, Argument argument, Parameter.Modifier param_mod, Type parameter)
3826 // Types have to be identical when ref or out modifer is used
3828 if (arg_mod != 0 || param_mod != 0) {
3829 if (TypeManager.HasElementType (parameter))
3830 parameter = TypeManager.GetElementType (parameter);
3832 Type a_type = argument.Type;
3833 if (TypeManager.HasElementType (a_type))
3834 a_type = TypeManager.GetElementType (a_type);
3836 if (a_type != parameter)
3839 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter))
3843 if (arg_mod != param_mod)
3849 public static bool IsOverride (MethodBase cand_method, MethodBase base_method)
3851 if (!IsAncestralType (base_method.DeclaringType, cand_method.DeclaringType))
3854 AParametersCollection cand_pd = TypeManager.GetParameterData (cand_method);
3855 AParametersCollection base_pd = TypeManager.GetParameterData (base_method);
3857 if (cand_pd.Count != base_pd.Count)
3860 for (int j = 0; j < cand_pd.Count; ++j)
3862 Parameter.Modifier cm = cand_pd.FixedParameters [j].ModFlags;
3863 Parameter.Modifier bm = base_pd.FixedParameters [j].ModFlags;
3864 Type ct = cand_pd.Types [j];
3865 Type bt = base_pd.Types [j];
3867 if (cm != bm || ct != bt)
3874 public static MethodGroupExpr MakeUnionSet (MethodGroupExpr mg1, MethodGroupExpr mg2, Location loc)
3885 ArrayList all = new ArrayList (mg1.Methods);
3886 foreach (MethodBase m in mg2.Methods){
3887 if (!TypeManager.ArrayContainsMethod (mg1.Methods, m, false))
3891 return new MethodGroupExpr (all, null, loc);
3894 static Type MoreSpecific (Type p, Type q)
3896 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
3898 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
3901 if (TypeManager.HasElementType (p))
3903 Type pe = TypeManager.GetElementType (p);
3904 Type qe = TypeManager.GetElementType (q);
3905 Type specific = MoreSpecific (pe, qe);
3911 else if (TypeManager.IsGenericType (p))
3913 Type[] pargs = TypeManager.GetTypeArguments (p);
3914 Type[] qargs = TypeManager.GetTypeArguments (q);
3916 bool p_specific_at_least_once = false;
3917 bool q_specific_at_least_once = false;
3919 for (int i = 0; i < pargs.Length; i++)
3921 Type specific = MoreSpecific (pargs [i], qargs [i]);
3922 if (specific == pargs [i])
3923 p_specific_at_least_once = true;
3924 if (specific == qargs [i])
3925 q_specific_at_least_once = true;
3928 if (p_specific_at_least_once && !q_specific_at_least_once)
3930 if (!p_specific_at_least_once && q_specific_at_least_once)
3937 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3939 base.MutateHoistedGenericType (storey);
3941 MethodInfo mi = best_candidate as MethodInfo;
3943 best_candidate = storey.MutateGenericMethod (mi);
3947 best_candidate = storey.MutateConstructor ((ConstructorInfo) this);
3951 /// Find the Applicable Function Members (7.4.2.1)
3953 /// me: Method Group expression with the members to select.
3954 /// it might contain constructors or methods (or anything
3955 /// that maps to a method).
3957 /// Arguments: ArrayList containing resolved Argument objects.
3959 /// loc: The location if we want an error to be reported, or a Null
3960 /// location for "probing" purposes.
3962 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3963 /// that is the best match of me on Arguments.
3966 public virtual MethodGroupExpr OverloadResolve (EmitContext ec, ref ArrayList Arguments,
3967 bool may_fail, Location loc)
3969 bool method_params = false;
3970 Type applicable_type = null;
3972 ArrayList candidates = new ArrayList (2);
3973 ArrayList candidate_overrides = null;
3976 // Used to keep a map between the candidate
3977 // and whether it is being considered in its
3978 // normal or expanded form
3980 // false is normal form, true is expanded form
3982 Hashtable candidate_to_form = null;
3984 if (Arguments != null)
3985 arg_count = Arguments.Count;
3987 if (RootContext.Version == LanguageVersion.ISO_1 && Name == "Invoke" && TypeManager.IsDelegateType (DeclaringType)) {
3989 Report.Error (1533, loc, "Invoke cannot be called directly on a delegate");
3993 int nmethods = Methods.Length;
3997 // Methods marked 'override' don't take part in 'applicable_type'
3998 // computation, nor in the actual overload resolution.
3999 // However, they still need to be emitted instead of a base virtual method.
4000 // So, we salt them away into the 'candidate_overrides' array.
4002 // In case of reflected methods, we replace each overriding method with
4003 // its corresponding base virtual method. This is to improve compatibility
4004 // with non-C# libraries which change the visibility of overrides (#75636)
4007 for (int i = 0; i < Methods.Length; ++i) {
4008 MethodBase m = Methods [i];
4009 if (TypeManager.IsOverride (m)) {
4010 if (candidate_overrides == null)
4011 candidate_overrides = new ArrayList ();
4012 candidate_overrides.Add (m);
4013 m = TypeManager.TryGetBaseDefinition (m);
4022 // Enable message recording, it's used mainly by lambda expressions
4024 Report.IMessageRecorder msg_recorder = new Report.MessageRecorder ();
4025 Report.IMessageRecorder prev_recorder = Report.SetMessageRecorder (msg_recorder);
4028 // First we construct the set of applicable methods
4030 bool is_sorted = true;
4031 int best_candidate_rate = int.MaxValue;
4032 for (int i = 0; i < nmethods; i++) {
4033 Type decl_type = Methods [i].DeclaringType;
4036 // If we have already found an applicable method
4037 // we eliminate all base types (Section 14.5.5.1)
4039 if (applicable_type != null && IsAncestralType (decl_type, applicable_type))
4043 // Check if candidate is applicable (section 14.4.2.1)
4045 bool params_expanded_form = false;
4046 int candidate_rate = IsApplicable (ec, Arguments, arg_count, ref Methods [i], ref params_expanded_form);
4048 if (candidate_rate < best_candidate_rate) {
4049 best_candidate_rate = candidate_rate;
4050 best_candidate = Methods [i];
4053 if (params_expanded_form) {
4054 if (candidate_to_form == null)
4055 candidate_to_form = new PtrHashtable ();
4056 MethodBase candidate = Methods [i];
4057 candidate_to_form [candidate] = candidate;
4060 if (candidate_rate != 0 || has_inaccessible_candidates_only) {
4061 if (msg_recorder != null)
4062 msg_recorder.EndSession ();
4066 msg_recorder = null;
4067 candidates.Add (Methods [i]);
4069 if (applicable_type == null)
4070 applicable_type = decl_type;
4071 else if (applicable_type != decl_type) {
4073 if (IsAncestralType (applicable_type, decl_type))
4074 applicable_type = decl_type;
4078 Report.SetMessageRecorder (prev_recorder);
4079 if (msg_recorder != null && !msg_recorder.IsEmpty) {
4081 msg_recorder.PrintMessages ();
4086 int candidate_top = candidates.Count;
4088 if (applicable_type == null) {
4090 // When we found a top level method which does not match and it's
4091 // not an extension method. We start extension methods lookup from here
4093 if (InstanceExpression != null) {
4094 ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (type, Name, loc);
4095 if (ex_method_lookup != null) {
4096 ex_method_lookup.ExtensionExpression = InstanceExpression;
4097 ex_method_lookup.SetTypeArguments (type_arguments);
4098 return ex_method_lookup.OverloadResolve (ec, ref Arguments, may_fail, loc);
4106 // Okay so we have failed to find exact match so we
4107 // return error info about the closest match
4109 if (best_candidate != null) {
4110 if (CustomErrorHandler != null && CustomErrorHandler.NoExactMatch (ec, best_candidate))
4113 AParametersCollection pd = TypeManager.GetParameterData (best_candidate);
4114 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4115 if (arg_count == pd.Count || pd.HasParams) {
4116 if (TypeManager.IsGenericMethodDefinition (best_candidate)) {
4117 if (type_arguments == null) {
4118 Report.Error (411, loc,
4119 "The type arguments for method `{0}' cannot be inferred from " +
4120 "the usage. Try specifying the type arguments explicitly",
4121 TypeManager.CSharpSignature (best_candidate));
4125 Type[] g_args = TypeManager.GetGenericArguments (best_candidate);
4126 if (type_arguments.Count != g_args.Length) {
4127 Report.SymbolRelatedToPreviousError (best_candidate);
4128 Report.Error (305, loc, "Using the generic method `{0}' requires `{1}' type argument(s)",
4129 TypeManager.CSharpSignature (best_candidate),
4130 g_args.Length.ToString ());
4134 if (type_arguments != null && !TypeManager.IsGenericMethod (best_candidate)) {
4135 Namespace.Error_TypeArgumentsCannotBeUsed (best_candidate, loc);
4140 if (has_inaccessible_candidates_only) {
4141 if (InstanceExpression != null && type != ec.ContainerType && TypeManager.IsNestedFamilyAccessible (ec.ContainerType, best_candidate.DeclaringType)) {
4142 // Although a derived class can access protected members of
4143 // its base class it cannot do so through an instance of the
4144 // base class (CS1540). If the qualifier_type is a base of the
4145 // ec.ContainerType and the lookup succeeds with the latter one,
4146 // then we are in this situation.
4147 Error_CannotAccessProtected (loc, best_candidate, queried_type, ec.ContainerType);
4149 Report.SymbolRelatedToPreviousError (best_candidate);
4150 ErrorIsInaccesible (loc, GetSignatureForError ());
4154 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate, cand_params, may_fail, loc))
4157 if (has_inaccessible_candidates_only)
4160 throw new InternalErrorException ("VerifyArgumentsCompat didn't find any problem with rejected candidate " + best_candidate);
4165 // We failed to find any method with correct argument count
4167 if (Name == ConstructorInfo.ConstructorName) {
4168 Report.SymbolRelatedToPreviousError (queried_type);
4169 Report.Error (1729, loc,
4170 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4171 TypeManager.CSharpName (queried_type), arg_count);
4173 Error_ArgumentCountWrong (arg_count);
4181 // At this point, applicable_type is _one_ of the most derived types
4182 // in the set of types containing the methods in this MethodGroup.
4183 // Filter the candidates so that they only contain methods from the
4184 // most derived types.
4187 int finalized = 0; // Number of finalized candidates
4190 // Invariant: applicable_type is a most derived type
4192 // We'll try to complete Section 14.5.5.1 for 'applicable_type' by
4193 // eliminating all it's base types. At the same time, we'll also move
4194 // every unrelated type to the end of the array, and pick the next
4195 // 'applicable_type'.
4197 Type next_applicable_type = null;
4198 int j = finalized; // where to put the next finalized candidate
4199 int k = finalized; // where to put the next undiscarded candidate
4200 for (int i = finalized; i < candidate_top; ++i) {
4201 MethodBase candidate = (MethodBase) candidates [i];
4202 Type decl_type = candidate.DeclaringType;
4204 if (decl_type == applicable_type) {
4205 candidates [k++] = candidates [j];
4206 candidates [j++] = candidates [i];
4210 if (IsAncestralType (decl_type, applicable_type))
4213 if (next_applicable_type != null &&
4214 IsAncestralType (decl_type, next_applicable_type))
4217 candidates [k++] = candidates [i];
4219 if (next_applicable_type == null ||
4220 IsAncestralType (next_applicable_type, decl_type))
4221 next_applicable_type = decl_type;
4224 applicable_type = next_applicable_type;
4227 } while (applicable_type != null);
4231 // Now we actually find the best method
4234 best_candidate = (MethodBase) candidates [0];
4235 method_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4237 for (int ix = 1; ix < candidate_top; ix++) {
4238 MethodBase candidate = (MethodBase) candidates [ix];
4240 if (candidate == best_candidate)
4243 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4245 if (BetterFunction (ec, Arguments, arg_count,
4246 candidate, cand_params,
4247 best_candidate, method_params)) {
4248 best_candidate = candidate;
4249 method_params = cand_params;
4253 // Now check that there are no ambiguities i.e the selected method
4254 // should be better than all the others
4256 MethodBase ambiguous = null;
4257 for (int ix = 1; ix < candidate_top; ix++) {
4258 MethodBase candidate = (MethodBase) candidates [ix];
4260 if (candidate == best_candidate)
4263 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4264 if (!BetterFunction (ec, Arguments, arg_count,
4265 best_candidate, method_params,
4266 candidate, cand_params))
4269 Report.SymbolRelatedToPreviousError (candidate);
4270 ambiguous = candidate;
4274 if (ambiguous != null) {
4275 Error_AmbiguousCall (ambiguous);
4280 // If the method is a virtual function, pick an override closer to the LHS type.
4282 if (!IsBase && best_candidate.IsVirtual) {
4283 if (TypeManager.IsOverride (best_candidate))
4284 throw new InternalErrorException (
4285 "Should not happen. An 'override' method took part in overload resolution: " + best_candidate);
4287 if (candidate_overrides != null) {
4288 Type[] gen_args = null;
4289 bool gen_override = false;
4290 if (TypeManager.IsGenericMethod (best_candidate))
4291 gen_args = TypeManager.GetGenericArguments (best_candidate);
4293 foreach (MethodBase candidate in candidate_overrides) {
4294 if (TypeManager.IsGenericMethod (candidate)) {
4295 if (gen_args == null)
4298 if (gen_args.Length != TypeManager.GetGenericArguments (candidate).Length)
4301 if (gen_args != null)
4305 if (IsOverride (candidate, best_candidate)) {
4306 gen_override = true;
4307 best_candidate = candidate;
4311 if (gen_override && gen_args != null) {
4313 best_candidate = ((MethodInfo) best_candidate).MakeGenericMethod (gen_args);
4320 // And now check if the arguments are all
4321 // compatible, perform conversions if
4322 // necessary etc. and return if everything is
4325 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate,
4326 method_params, may_fail, loc))
4329 if (best_candidate == null)
4332 MethodBase the_method = TypeManager.DropGenericMethodArguments (best_candidate);
4333 if (TypeManager.IsGenericMethodDefinition (the_method) &&
4334 !ConstraintChecker.CheckConstraints (ec, the_method, best_candidate, loc))
4338 // Check ObsoleteAttribute on the best method
4340 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (the_method);
4341 if (oa != null && !ec.IsInObsoleteScope)
4342 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc);
4344 IMethodData data = TypeManager.GetMethod (the_method);
4346 data.SetMemberIsUsed ();
4351 public override void SetTypeArguments (TypeArguments ta)
4353 type_arguments = ta;
4356 public bool VerifyArgumentsCompat (EmitContext ec, ref ArrayList arguments,
4357 int arg_count, MethodBase method,
4358 bool chose_params_expanded,
4359 bool may_fail, Location loc)
4361 AParametersCollection pd = TypeManager.GetParameterData (method);
4363 int errors = Report.Errors;
4364 Parameter.Modifier p_mod = 0;
4366 int a_idx = 0, a_pos = 0;
4368 ArrayList params_initializers = null;
4369 bool has_unsafe_arg = false;
4371 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4372 a = (Argument) arguments [a_idx];
4373 if (p_mod != Parameter.Modifier.PARAMS) {
4374 p_mod = pd.FixedParameters [a_idx].ModFlags;
4375 pt = pd.Types [a_idx];
4376 has_unsafe_arg |= pt.IsPointer;
4378 if (p_mod == Parameter.Modifier.ARGLIST) {
4379 if (a.Type != TypeManager.runtime_argument_handle_type)
4384 if (p_mod == Parameter.Modifier.PARAMS) {
4385 if (chose_params_expanded) {
4386 params_initializers = new ArrayList (arg_count - a_idx);
4387 pt = TypeManager.GetElementType (pt);
4393 // Types have to be identical when ref or out modifer is used
4395 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4396 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4399 if (!TypeManager.IsEqual (a.Expr.Type, pt))
4405 if (delegate_type != null && !Delegate.IsTypeCovariant (a.Expr, pt))
4408 Expression conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4413 // Convert params arguments to an array initializer
4415 if (params_initializers != null) {
4416 // we choose to use 'a.Expr' rather than 'conv' so that
4417 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
4418 params_initializers.Add (a.Expr);
4419 arguments.RemoveAt (a_idx--);
4424 // Update the argument with the implicit conversion
4428 if (a_idx != arg_count) {
4429 if (!may_fail && Report.Errors == errors) {
4430 if (CustomErrorHandler != null)
4431 CustomErrorHandler.NoExactMatch (ec, best_candidate);
4433 Error_InvalidArguments (ec, loc, a_pos, method, a, pd, pt);
4439 // Fill not provided arguments required by params modifier
4441 int param_count = GetApplicableParametersCount (method, pd);
4442 if (params_initializers == null && pd.HasParams && arg_count + 1 == param_count) {
4443 if (arguments == null)
4444 arguments = new ArrayList (1);
4446 pt = pd.Types [param_count - 1];
4447 pt = TypeManager.GetElementType (pt);
4448 has_unsafe_arg |= pt.IsPointer;
4449 params_initializers = new ArrayList (0);
4453 // Append an array argument with all params arguments
4455 if (params_initializers != null) {
4456 arguments.Add (new Argument (
4457 new ArrayCreation (new TypeExpression (pt, loc), "[]",
4458 params_initializers, loc).Resolve (ec)));
4462 if (arg_count < param_count) {
4464 Error_ArgumentCountWrong (arg_count);
4468 if (has_unsafe_arg && !ec.InUnsafe) {
4478 public class ConstantExpr : MemberExpr
4482 public ConstantExpr (FieldInfo constant, Location loc)
4484 this.constant = constant;
4488 public override string Name {
4489 get { throw new NotImplementedException (); }
4492 public override bool IsInstance {
4493 get { return !IsStatic; }
4496 public override bool IsStatic {
4497 get { return constant.IsStatic; }
4500 public override Type DeclaringType {
4501 get { return constant.DeclaringType; }
4504 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc, SimpleName original)
4506 constant = TypeManager.GetGenericFieldDefinition (constant);
4508 IConstant ic = TypeManager.GetConstant (constant);
4510 if (constant.IsLiteral) {
4511 ic = new ExternalConstant (constant);
4513 ic = ExternalConstant.CreateDecimal (constant);
4514 // HACK: decimal field was not resolved as constant
4516 return new FieldExpr (constant, loc).ResolveMemberAccess (ec, left, loc, original);
4518 TypeManager.RegisterConstant (constant, ic);
4521 return base.ResolveMemberAccess (ec, left, loc, original);
4524 public override Expression CreateExpressionTree (EmitContext ec)
4526 throw new NotSupportedException ("ET");
4529 public override Expression DoResolve (EmitContext ec)
4531 IConstant ic = TypeManager.GetConstant (constant);
4532 if (ic.ResolveValue ()) {
4533 if (!ec.IsInObsoleteScope)
4534 ic.CheckObsoleteness (loc);
4537 return ic.CreateConstantReference (loc);
4540 public override void Emit (EmitContext ec)
4542 throw new NotSupportedException ();
4545 public override string GetSignatureForError ()
4547 return TypeManager.GetFullNameSignature (constant);
4552 /// Fully resolved expression that evaluates to a Field
4554 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariableReference {
4555 public FieldInfo FieldInfo;
4556 readonly Type constructed_generic_type;
4557 VariableInfo variable_info;
4559 LocalTemporary temp;
4562 protected FieldExpr (Location l)
4567 public FieldExpr (FieldInfo fi, Location l)
4570 type = TypeManager.TypeToCoreType (fi.FieldType);
4574 public FieldExpr (FieldInfo fi, Type genericType, Location l)
4577 if (TypeManager.IsGenericTypeDefinition (genericType))
4579 this.constructed_generic_type = genericType;
4582 public override string Name {
4584 return FieldInfo.Name;
4588 public override bool IsInstance {
4590 return !FieldInfo.IsStatic;
4594 public override bool IsStatic {
4596 return FieldInfo.IsStatic;
4600 public override Type DeclaringType {
4602 return FieldInfo.DeclaringType;
4606 public override string GetSignatureForError ()
4608 return TypeManager.GetFullNameSignature (FieldInfo);
4611 public VariableInfo VariableInfo {
4613 return variable_info;
4617 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
4618 SimpleName original)
4620 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
4621 Type t = fi.FieldType;
4623 if (t.IsPointer && !ec.InUnsafe) {
4627 return base.ResolveMemberAccess (ec, left, loc, original);
4630 public void SetHasAddressTaken ()
4632 IVariableReference vr = InstanceExpression as IVariableReference;
4634 vr.SetHasAddressTaken ();
4637 public override Expression CreateExpressionTree (EmitContext ec)
4639 Expression instance;
4640 if (InstanceExpression == null) {
4641 instance = new NullLiteral (loc);
4643 instance = InstanceExpression.CreateExpressionTree (ec);
4646 ArrayList args = new ArrayList (2);
4647 args.Add (new Argument (instance));
4648 args.Add (new Argument (CreateTypeOfExpression ()));
4649 return CreateExpressionFactoryCall ("Field", args);
4652 public Expression CreateTypeOfExpression ()
4654 return new TypeOfField (GetConstructedFieldInfo (), loc);
4657 override public Expression DoResolve (EmitContext ec)
4659 return DoResolve (ec, false, false);
4662 Expression DoResolve (EmitContext ec, bool lvalue_instance, bool out_access)
4664 if (!FieldInfo.IsStatic){
4665 if (InstanceExpression == null){
4667 // This can happen when referencing an instance field using
4668 // a fully qualified type expression: TypeName.InstanceField = xxx
4670 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4674 // Resolve the field's instance expression while flow analysis is turned
4675 // off: when accessing a field "a.b", we must check whether the field
4676 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4678 if (lvalue_instance) {
4679 using (ec.With (EmitContext.Flags.DoFlowAnalysis, false)) {
4680 Expression right_side =
4681 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4683 if (InstanceExpression != EmptyExpression.Null)
4684 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side, loc);
4687 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
4689 if (InstanceExpression != EmptyExpression.Null)
4690 InstanceExpression = InstanceExpression.Resolve (ec, rf);
4693 if (InstanceExpression == null)
4696 using (ec.Set (EmitContext.Flags.OmitStructFlowAnalysis)) {
4697 InstanceExpression.CheckMarshalByRefAccess (ec);
4701 // TODO: the code above uses some non-standard multi-resolve rules
4702 if (eclass != ExprClass.Invalid)
4705 if (!ec.IsInObsoleteScope) {
4706 FieldBase f = TypeManager.GetField (FieldInfo);
4708 f.CheckObsoleteness (loc);
4710 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
4712 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
4716 IFixedBuffer fb = AttributeTester.GetFixedBuffer (FieldInfo);
4717 IVariableReference var = InstanceExpression as IVariableReference;
4720 IFixedExpression fe = InstanceExpression as IFixedExpression;
4721 if (!ec.InFixedInitializer && (fe == null || !fe.IsFixed)) {
4722 Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4725 if (InstanceExpression.eclass != ExprClass.Variable) {
4726 Report.SymbolRelatedToPreviousError (FieldInfo);
4727 Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4728 TypeManager.GetFullNameSignature (FieldInfo));
4729 } else if (var != null && var.IsHoisted) {
4730 AnonymousMethodExpression.Error_AddressOfCapturedVar (var, loc);
4733 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4736 eclass = ExprClass.Variable;
4738 // If the instance expression is a local variable or parameter.
4739 if (var == null || var.VariableInfo == null)
4742 VariableInfo vi = var.VariableInfo;
4743 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
4746 variable_info = vi.GetSubStruct (FieldInfo.Name);
4747 eclass = ExprClass.Variable;
4751 static readonly int [] codes = {
4752 191, // instance, write access
4753 192, // instance, out access
4754 198, // static, write access
4755 199, // static, out access
4756 1648, // member of value instance, write access
4757 1649, // member of value instance, out access
4758 1650, // member of value static, write access
4759 1651 // member of value static, out access
4762 static readonly string [] msgs = {
4763 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4764 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4765 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4766 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4767 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4768 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4769 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4770 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4773 // The return value is always null. Returning a value simplifies calling code.
4774 Expression Report_AssignToReadonly (Expression right_side)
4777 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4781 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4783 Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4788 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4790 IVariableReference var = InstanceExpression as IVariableReference;
4791 if (var != null && var.VariableInfo != null)
4792 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
4794 bool lvalue_instance = !FieldInfo.IsStatic && TypeManager.IsValueType (FieldInfo.DeclaringType);
4795 bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
4797 Expression e = DoResolve (ec, lvalue_instance, out_access);
4802 FieldBase fb = TypeManager.GetField (FieldInfo);
4806 if (FieldInfo.IsInitOnly) {
4807 // InitOnly fields can only be assigned in constructors or initializers
4808 if (!ec.IsInFieldInitializer && !ec.IsConstructor)
4809 return Report_AssignToReadonly (right_side);
4811 if (ec.IsConstructor) {
4812 Type ctype = ec.TypeContainer.CurrentType;
4814 ctype = ec.ContainerType;
4816 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4817 if (!TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
4818 return Report_AssignToReadonly (right_side);
4819 // static InitOnly fields cannot be assigned-to in an instance constructor
4820 if (IsStatic && !ec.IsStatic)
4821 return Report_AssignToReadonly (right_side);
4822 // instance constructors can't modify InitOnly fields of other instances of the same type
4823 if (!IsStatic && !(InstanceExpression is This))
4824 return Report_AssignToReadonly (right_side);
4828 if (right_side == EmptyExpression.OutAccess &&
4829 !IsStatic && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type)) {
4830 Report.SymbolRelatedToPreviousError (DeclaringType);
4831 Report.Warning (197, 1, loc,
4832 "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",
4833 GetSignatureForError ());
4836 eclass = ExprClass.Variable;
4840 bool is_marshal_by_ref ()
4842 return !IsStatic && TypeManager.IsStruct (Type) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type);
4845 public override void CheckMarshalByRefAccess (EmitContext ec)
4847 if (is_marshal_by_ref () && !(InstanceExpression is This)) {
4848 Report.SymbolRelatedToPreviousError (DeclaringType);
4849 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",
4850 GetSignatureForError ());
4854 public override int GetHashCode ()
4856 return FieldInfo.GetHashCode ();
4859 public bool IsFixed {
4862 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
4864 IVariableReference variable = InstanceExpression as IVariableReference;
4865 if (variable != null)
4866 return TypeManager.IsStruct (InstanceExpression.Type) && variable.IsFixed;
4868 IFixedExpression fe = InstanceExpression as IFixedExpression;
4869 return fe != null && fe.IsFixed;
4873 public bool IsHoisted {
4875 IVariableReference hv = InstanceExpression as IVariableReference;
4876 return hv != null && hv.IsHoisted;
4880 public override bool Equals (object obj)
4882 FieldExpr fe = obj as FieldExpr;
4886 if (FieldInfo != fe.FieldInfo)
4889 if (InstanceExpression == null || fe.InstanceExpression == null)
4892 return InstanceExpression.Equals (fe.InstanceExpression);
4895 public void Emit (EmitContext ec, bool leave_copy)
4897 ILGenerator ig = ec.ig;
4898 bool is_volatile = false;
4900 FieldBase f = TypeManager.GetField (FieldInfo);
4902 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4905 f.SetMemberIsUsed ();
4908 if (FieldInfo.IsStatic){
4910 ig.Emit (OpCodes.Volatile);
4912 ig.Emit (OpCodes.Ldsfld, GetConstructedFieldInfo ());
4915 EmitInstance (ec, false);
4917 // Optimization for build-in types
4918 // TODO: Iterators don't set current container
4919 if (TypeManager.IsStruct (type) && type == ec.DeclContainer.TypeBuilder && ec.CurrentIterator == null) {
4920 LoadFromPtr (ig, type);
4922 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
4924 ig.Emit (OpCodes.Ldflda, GetConstructedFieldInfo ());
4925 ig.Emit (OpCodes.Ldflda, ff.Element);
4928 ig.Emit (OpCodes.Volatile);
4930 ig.Emit (OpCodes.Ldfld, GetConstructedFieldInfo ());
4936 ec.ig.Emit (OpCodes.Dup);
4937 if (!FieldInfo.IsStatic) {
4938 temp = new LocalTemporary (this.Type);
4944 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4946 FieldAttributes fa = FieldInfo.Attributes;
4947 bool is_static = (fa & FieldAttributes.Static) != 0;
4948 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
4949 ILGenerator ig = ec.ig;
4951 if (is_readonly && !ec.IsConstructor){
4952 Report_AssignToReadonly (source);
4956 prepared = prepare_for_load;
4957 EmitInstance (ec, prepared);
4961 ec.ig.Emit (OpCodes.Dup);
4962 if (!FieldInfo.IsStatic) {
4963 temp = new LocalTemporary (this.Type);
4968 FieldBase f = TypeManager.GetField (FieldInfo);
4970 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4971 ig.Emit (OpCodes.Volatile);
4977 ig.Emit (OpCodes.Stsfld, GetConstructedFieldInfo ());
4979 ig.Emit (OpCodes.Stfld, GetConstructedFieldInfo ());
4988 public override void Emit (EmitContext ec)
4993 public override void EmitSideEffect (EmitContext ec)
4995 FieldBase f = TypeManager.GetField (FieldInfo);
4996 bool is_volatile = f != null && (f.ModFlags & Modifiers.VOLATILE) != 0;
4998 if (is_volatile || is_marshal_by_ref ())
4999 base.EmitSideEffect (ec);
5002 public override void Error_VariableIsUsedBeforeItIsDeclared (string name)
5004 Report.Error (844, loc,
5005 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the field `{1}'",
5006 name, GetSignatureForError ());
5009 public void AddressOf (EmitContext ec, AddressOp mode)
5011 ILGenerator ig = ec.ig;
5013 FieldBase f = TypeManager.GetField (FieldInfo);
5015 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
5016 Report.Warning (420, 1, loc, "`{0}': A volatile field references will not be treated as volatile",
5017 f.GetSignatureForError ());
5020 if ((mode & AddressOp.Store) != 0)
5022 if ((mode & AddressOp.Load) != 0)
5023 f.SetMemberIsUsed ();
5027 // Handle initonly fields specially: make a copy and then
5028 // get the address of the copy.
5031 if (FieldInfo.IsInitOnly){
5033 if (ec.IsConstructor){
5034 if (FieldInfo.IsStatic){
5046 local = ig.DeclareLocal (type);
5047 ig.Emit (OpCodes.Stloc, local);
5048 ig.Emit (OpCodes.Ldloca, local);
5053 if (FieldInfo.IsStatic){
5054 ig.Emit (OpCodes.Ldsflda, GetConstructedFieldInfo ());
5057 EmitInstance (ec, false);
5058 ig.Emit (OpCodes.Ldflda, GetConstructedFieldInfo ());
5062 FieldInfo GetConstructedFieldInfo ()
5064 if (constructed_generic_type == null)
5067 return TypeBuilder.GetField (constructed_generic_type, FieldInfo);
5069 throw new NotSupportedException ();
5073 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5075 FieldInfo = storey.MutateField (FieldInfo);
5076 base.MutateHoistedGenericType (storey);
5082 /// Expression that evaluates to a Property. The Assign class
5083 /// might set the `Value' expression if we are in an assignment.
5085 /// This is not an LValue because we need to re-write the expression, we
5086 /// can not take data from the stack and store it.
5088 public class PropertyExpr : MemberExpr, IAssignMethod {
5089 public readonly PropertyInfo PropertyInfo;
5090 MethodInfo getter, setter;
5095 LocalTemporary temp;
5098 public PropertyExpr (Type container_type, PropertyInfo pi, Location l)
5101 eclass = ExprClass.PropertyAccess;
5105 type = TypeManager.TypeToCoreType (pi.PropertyType);
5107 ResolveAccessors (container_type);
5110 public override string Name {
5112 return PropertyInfo.Name;
5116 public override bool IsInstance {
5122 public override bool IsStatic {
5128 public override Expression CreateExpressionTree (EmitContext ec)
5131 if (IsSingleDimensionalArrayLength ()) {
5132 args = new ArrayList (1);
5133 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5134 return CreateExpressionFactoryCall ("ArrayLength", args);
5138 Error_BaseAccessInExpressionTree (loc);
5142 args = new ArrayList (2);
5143 if (InstanceExpression == null)
5144 args.Add (new Argument (new NullLiteral (loc)));
5146 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5147 args.Add (new Argument (new TypeOfMethodInfo (getter, loc)));
5148 return CreateExpressionFactoryCall ("Property", args);
5151 public Expression CreateSetterTypeOfExpression ()
5153 return new TypeOfMethodInfo (setter, loc);
5156 public override Type DeclaringType {
5158 return PropertyInfo.DeclaringType;
5162 public override string GetSignatureForError ()
5164 return TypeManager.GetFullNameSignature (PropertyInfo);
5167 void FindAccessors (Type invocation_type)
5169 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
5170 BindingFlags.Static | BindingFlags.Instance |
5171 BindingFlags.DeclaredOnly;
5173 Type current = PropertyInfo.DeclaringType;
5174 for (; current != null; current = current.BaseType) {
5175 MemberInfo[] group = TypeManager.MemberLookup (
5176 invocation_type, invocation_type, current,
5177 MemberTypes.Property, flags, PropertyInfo.Name, null);
5182 if (group.Length != 1)
5183 // Oooops, can this ever happen ?
5186 PropertyInfo pi = (PropertyInfo) group [0];
5189 getter = pi.GetGetMethod (true);
5192 setter = pi.GetSetMethod (true);
5194 MethodInfo accessor = getter != null ? getter : setter;
5196 if (!accessor.IsVirtual)
5202 // We also perform the permission checking here, as the PropertyInfo does not
5203 // hold the information for the accessibility of its setter/getter
5205 // TODO: Refactor to use some kind of cache together with GetPropertyFromAccessor
5206 void ResolveAccessors (Type container_type)
5208 FindAccessors (container_type);
5210 if (getter != null) {
5211 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
5212 IMethodData md = TypeManager.GetMethod (the_getter);
5214 md.SetMemberIsUsed ();
5216 is_static = getter.IsStatic;
5219 if (setter != null) {
5220 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
5221 IMethodData md = TypeManager.GetMethod (the_setter);
5223 md.SetMemberIsUsed ();
5225 is_static = setter.IsStatic;
5229 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5231 if (InstanceExpression != null)
5232 InstanceExpression.MutateHoistedGenericType (storey);
5234 type = storey.MutateType (type);
5236 getter = storey.MutateGenericMethod (getter);
5238 setter = storey.MutateGenericMethod (setter);
5241 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
5244 InstanceExpression = null;
5248 if (InstanceExpression == null) {
5249 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5253 InstanceExpression = InstanceExpression.DoResolve (ec);
5254 if (lvalue_instance && InstanceExpression != null)
5255 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
5257 if (InstanceExpression == null)
5260 InstanceExpression.CheckMarshalByRefAccess (ec);
5262 if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) &&
5263 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
5264 !TypeManager.IsNestedChildOf (ec.ContainerType, InstanceExpression.Type) &&
5265 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.ContainerType)) {
5266 Report.SymbolRelatedToPreviousError (PropertyInfo);
5267 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
5274 void Error_PropertyNotFound (MethodInfo mi, bool getter)
5276 // TODO: correctly we should compare arguments but it will lead to bigger changes
5277 if (mi is MethodBuilder) {
5278 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
5282 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
5284 AParametersCollection iparams = TypeManager.GetParameterData (mi);
5285 sig.Append (getter ? "get_" : "set_");
5287 sig.Append (iparams.GetSignatureForError ());
5289 Report.SymbolRelatedToPreviousError (mi);
5290 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
5291 Name, sig.ToString ());
5294 public bool IsAccessibleFrom (Type invocation_type, bool lvalue)
5297 MethodInfo accessor = lvalue ? setter : getter;
5298 if (accessor == null && lvalue)
5300 return accessor != null && IsAccessorAccessible (invocation_type, accessor, out dummy);
5303 bool IsSingleDimensionalArrayLength ()
5305 if (DeclaringType != TypeManager.array_type || getter == null || Name != "Length")
5308 string t_name = InstanceExpression.Type.Name;
5309 int t_name_len = t_name.Length;
5310 return t_name_len > 2 && t_name [t_name_len - 2] == '[';
5313 override public Expression DoResolve (EmitContext ec)
5318 if (getter != null){
5319 if (TypeManager.GetParameterData (getter).Count != 0){
5320 Error_PropertyNotFound (getter, true);
5325 if (getter == null){
5327 // The following condition happens if the PropertyExpr was
5328 // created, but is invalid (ie, the property is inaccessible),
5329 // and we did not want to embed the knowledge about this in
5330 // the caller routine. This only avoids double error reporting.
5335 if (InstanceExpression != EmptyExpression.Null) {
5336 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5337 TypeManager.GetFullNameSignature (PropertyInfo));
5342 bool must_do_cs1540_check = false;
5343 if (getter != null &&
5344 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
5345 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
5346 if (pm != null && pm.HasCustomAccessModifier) {
5347 Report.SymbolRelatedToPreviousError (pm);
5348 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5349 TypeManager.CSharpSignature (getter));
5352 Report.SymbolRelatedToPreviousError (getter);
5353 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
5358 if (!InstanceResolve (ec, false, must_do_cs1540_check))
5362 // Only base will allow this invocation to happen.
5364 if (IsBase && getter.IsAbstract) {
5365 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5368 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
5372 if (!ec.IsInObsoleteScope) {
5373 PropertyBase pb = TypeManager.GetProperty (PropertyInfo);
5375 pb.CheckObsoleteness (loc);
5377 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (PropertyInfo);
5379 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc);
5388 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
5390 if (right_side == EmptyExpression.OutAccess) {
5391 if (ec.CurrentBlock.Toplevel.GetParameterReference (PropertyInfo.Name, loc) is MemberAccess) {
5392 Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5395 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as `ref' or `out' parameter",
5396 GetSignatureForError ());
5401 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5402 Error_CannotModifyIntermediateExpressionValue (ec);
5405 if (setter == null){
5407 // The following condition happens if the PropertyExpr was
5408 // created, but is invalid (ie, the property is inaccessible),
5409 // and we did not want to embed the knowledge about this in
5410 // the caller routine. This only avoids double error reporting.
5415 if (ec.CurrentBlock.Toplevel.GetParameterReference (PropertyInfo.Name, loc) is MemberAccess) {
5416 Report.Error (1947, loc, "A range variable `{0}' cannot be assigned to. Consider using `let' clause to store the value",
5419 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
5420 GetSignatureForError ());
5425 if (TypeManager.GetParameterData (setter).Count != 1){
5426 Error_PropertyNotFound (setter, false);
5430 bool must_do_cs1540_check;
5431 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
5432 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
5433 if (pm != null && pm.HasCustomAccessModifier) {
5434 Report.SymbolRelatedToPreviousError (pm);
5435 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5436 TypeManager.CSharpSignature (setter));
5439 Report.SymbolRelatedToPreviousError (setter);
5440 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
5445 if (!InstanceResolve (ec, TypeManager.IsStruct (PropertyInfo.DeclaringType), must_do_cs1540_check))
5449 // Only base will allow this invocation to happen.
5451 if (IsBase && setter.IsAbstract){
5452 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5455 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe) {
5459 if (!ec.IsInObsoleteScope) {
5460 PropertyBase pb = TypeManager.GetProperty (PropertyInfo);
5462 pb.CheckObsoleteness (loc);
5464 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (PropertyInfo);
5466 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc);
5473 public override void Emit (EmitContext ec)
5478 public void Emit (EmitContext ec, bool leave_copy)
5481 // Special case: length of single dimension array property is turned into ldlen
5483 if (IsSingleDimensionalArrayLength ()) {
5485 EmitInstance (ec, false);
5486 ec.ig.Emit (OpCodes.Ldlen);
5487 ec.ig.Emit (OpCodes.Conv_I4);
5491 Invocation.EmitCall (ec, IsBase, InstanceExpression, getter, null, loc, prepared, false);
5494 ec.ig.Emit (OpCodes.Dup);
5496 temp = new LocalTemporary (this.Type);
5503 // Implements the IAssignMethod interface for assignments
5505 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5507 Expression my_source = source;
5509 if (prepare_for_load) {
5514 ec.ig.Emit (OpCodes.Dup);
5516 temp = new LocalTemporary (this.Type);
5520 } else if (leave_copy) {
5522 temp = new LocalTemporary (this.Type);
5527 ArrayList args = new ArrayList (1);
5528 args.Add (new Argument (my_source, Argument.AType.Expression));
5530 Invocation.EmitCall (ec, IsBase, InstanceExpression, setter, args, loc, false, prepared);
5540 /// Fully resolved expression that evaluates to an Event
5542 public class EventExpr : MemberExpr {
5543 public readonly EventInfo EventInfo;
5546 MethodInfo add_accessor, remove_accessor;
5548 public EventExpr (EventInfo ei, Location loc)
5552 eclass = ExprClass.EventAccess;
5554 add_accessor = TypeManager.GetAddMethod (ei);
5555 remove_accessor = TypeManager.GetRemoveMethod (ei);
5556 if (add_accessor.IsStatic || remove_accessor.IsStatic)
5559 if (EventInfo is MyEventBuilder){
5560 MyEventBuilder eb = (MyEventBuilder) EventInfo;
5561 type = eb.EventType;
5564 type = EventInfo.EventHandlerType;
5567 public override string Name {
5569 return EventInfo.Name;
5573 public override bool IsInstance {
5579 public override bool IsStatic {
5585 public override Type DeclaringType {
5587 return EventInfo.DeclaringType;
5591 void Error_AssignmentEventOnly ()
5593 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5594 GetSignatureForError ());
5597 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
5598 SimpleName original)
5601 // If the event is local to this class, we transform ourselves into a FieldExpr
5604 if (EventInfo.DeclaringType == ec.ContainerType ||
5605 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
5606 EventField mi = TypeManager.GetEventField (EventInfo);
5609 if (!ec.IsInObsoleteScope)
5610 mi.CheckObsoleteness (loc);
5612 if ((mi.ModFlags & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0 && !ec.IsInCompoundAssignment)
5613 Error_AssignmentEventOnly ();
5615 FieldExpr ml = new FieldExpr (mi.BackingField.FieldBuilder, loc);
5617 InstanceExpression = null;
5619 return ml.ResolveMemberAccess (ec, left, loc, original);
5623 if (left is This && !ec.IsInCompoundAssignment)
5624 Error_AssignmentEventOnly ();
5626 return base.ResolveMemberAccess (ec, left, loc, original);
5629 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
5632 InstanceExpression = null;
5636 if (InstanceExpression == null) {
5637 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5641 InstanceExpression = InstanceExpression.DoResolve (ec);
5642 if (InstanceExpression == null)
5645 if (IsBase && add_accessor.IsAbstract) {
5646 Error_CannotCallAbstractBase(TypeManager.CSharpSignature(add_accessor));
5651 // This is using the same mechanism as the CS1540 check in PropertyExpr.
5652 // However, in the Event case, we reported a CS0122 instead.
5654 // TODO: Exact copy from PropertyExpr
5656 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
5657 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
5658 !TypeManager.IsNestedChildOf (ec.ContainerType, InstanceExpression.Type) &&
5659 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.ContainerType)) {
5660 Report.SymbolRelatedToPreviousError (EventInfo);
5661 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5668 public bool IsAccessibleFrom (Type invocation_type)
5671 return IsAccessorAccessible (invocation_type, add_accessor, out dummy) &&
5672 IsAccessorAccessible (invocation_type, remove_accessor, out dummy);
5675 public override Expression CreateExpressionTree (EmitContext ec)
5677 throw new NotSupportedException ("ET");
5680 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5682 // contexts where an LValue is valid have already devolved to FieldExprs
5683 Error_CannotAssign ();
5687 public override Expression DoResolve (EmitContext ec)
5689 bool must_do_cs1540_check;
5690 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
5691 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
5692 Report.SymbolRelatedToPreviousError (EventInfo);
5693 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5697 if (!InstanceResolve (ec, must_do_cs1540_check))
5700 if (!ec.IsInCompoundAssignment) {
5701 Error_CannotAssign ();
5705 if (!ec.IsInObsoleteScope) {
5706 EventField ev = TypeManager.GetEventField (EventInfo);
5708 ev.CheckObsoleteness (loc);
5710 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (EventInfo);
5712 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc);
5719 public override void Emit (EmitContext ec)
5721 Error_CannotAssign ();
5724 public void Error_CannotAssign ()
5726 Report.Error (70, loc,
5727 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
5728 GetSignatureForError (), TypeManager.CSharpName (EventInfo.DeclaringType));
5731 public override string GetSignatureForError ()
5733 return TypeManager.CSharpSignature (EventInfo);
5736 public void EmitAddOrRemove (EmitContext ec, bool is_add, Expression source)
5738 ArrayList args = new ArrayList (1);
5739 args.Add (new Argument (source, Argument.AType.Expression));
5740 Invocation.EmitCall (ec, IsBase, InstanceExpression, is_add ? add_accessor : remove_accessor, args, loc);
5744 public class TemporaryVariable : VariableReference
5748 public TemporaryVariable (Type type, Location loc)
5752 eclass = ExprClass.Variable;
5755 public override Expression CreateExpressionTree (EmitContext ec)
5757 throw new NotSupportedException ("ET");
5760 public override Expression DoResolve (EmitContext ec)
5765 TypeExpr te = new TypeExpression (type, loc);
5766 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
5767 if (!li.Resolve (ec))
5771 // Don't capture temporary variables except when using
5772 // iterator redirection
5774 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.IsIterator && ec.IsVariableCapturingRequired) {
5775 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
5776 storey.CaptureLocalVariable (ec, li);
5782 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5784 return DoResolve (ec);
5787 public override void Emit (EmitContext ec)
5792 public void EmitAssign (EmitContext ec, Expression source)
5794 EmitAssign (ec, source, false, false);
5797 public override HoistedVariable GetHoistedVariable (EmitContext ec)
5799 return li.HoistedVariableReference;
5802 public override bool IsFixed {
5803 get { return true; }
5806 public override bool IsRef {
5807 get { return false; }
5810 public override string Name {
5811 get { throw new NotImplementedException (); }
5814 public override void SetHasAddressTaken ()
5816 throw new NotImplementedException ();
5819 protected override ILocalVariable Variable {
5823 public override VariableInfo VariableInfo {
5824 get { throw new NotImplementedException (); }
5829 /// Handles `var' contextual keyword; var becomes a keyword only
5830 /// if no type called var exists in a variable scope
5832 public class VarExpr : SimpleName
5834 // Used for error reporting only
5835 ArrayList initializer;
5837 public VarExpr (Location loc)
5842 public ArrayList VariableInitializer {
5844 this.initializer = value;
5848 public bool InferType (EmitContext ec, Expression right_side)
5851 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
5853 type = right_side.Type;
5854 if (type == TypeManager.null_type || type == TypeManager.void_type || type == TypeManager.anonymous_method_type) {
5855 Report.Error (815, loc, "An implicitly typed local variable declaration cannot be initialized with `{0}'",
5856 right_side.GetSignatureForError ());
5860 eclass = ExprClass.Variable;
5864 protected override void Error_TypeOrNamespaceNotFound (IResolveContext ec)
5866 Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");
5869 public override TypeExpr ResolveAsContextualType (IResolveContext rc, bool silent)
5871 TypeExpr te = base.ResolveAsContextualType (rc, true);
5875 if (initializer == null)
5878 if (initializer.Count > 1) {
5879 Location loc = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [1]).Location;
5880 Report.Error (819, loc, "An implicitly typed local variable declaration cannot include multiple declarators");
5885 Expression variable_initializer = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [0]).expression_or_array_initializer;
5886 if (variable_initializer == null) {
5887 Report.Error (818, loc, "An implicitly typed local variable declarator must include an initializer");