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);
302 public TypeExpr ResolveAsBaseTerminal (IResolveContext ec, bool silent)
304 int errors = Report.Errors;
306 FullNamedExpression fne = ResolveAsTypeStep (ec, silent);
311 TypeExpr te = fne as TypeExpr;
313 if (!silent && errors == Report.Errors)
314 fne.Error_UnexpectedKind (null, "type", loc);
318 if (!te.CheckAccessLevel (ec.GenericDeclContainer)) {
319 Report.SymbolRelatedToPreviousError (te.Type);
320 ErrorIsInaccesible (loc, TypeManager.CSharpName (te.Type));
328 public static void ErrorIsInaccesible (Location loc, string name)
330 Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", name);
333 protected static void Error_CannotAccessProtected (Location loc, MemberInfo m, Type qualifier, Type container)
335 Report.Error (1540, loc, "Cannot access protected member `{0}' via a qualifier of type `{1}'."
336 + " The qualifier must be of type `{2}' or derived from it",
337 TypeManager.GetFullNameSignature (m),
338 TypeManager.CSharpName (qualifier),
339 TypeManager.CSharpName (container));
343 public static void Error_InvalidExpressionStatement (Location loc)
345 Report.Error (201, loc, "Only assignment, call, increment, decrement, and new object " +
346 "expressions can be used as a statement");
349 public void Error_InvalidExpressionStatement ()
351 Error_InvalidExpressionStatement (loc);
354 protected void Error_CannotAssign (string to, string roContext)
356 Report.Error (1656, loc, "Cannot assign to `{0}' because it is a `{1}'",
360 public static void Error_VoidInvalidInTheContext (Location loc)
362 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
365 public virtual void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl)
367 // The error was already reported as CS1660
368 if (type == TypeManager.anonymous_method_type)
371 if (TypeManager.IsGenericParameter (Type) && TypeManager.IsGenericParameter (target) && type.Name == target.Name) {
373 string sig1 = type.DeclaringMethod == null ?
374 TypeManager.CSharpName (type.DeclaringType) :
375 TypeManager.CSharpSignature (type.DeclaringMethod);
376 string sig2 = target.DeclaringMethod == null ?
377 TypeManager.CSharpName (target.DeclaringType) :
378 TypeManager.CSharpSignature (target.DeclaringMethod);
379 Report.ExtraInformation (loc,
381 "The generic parameter `{0}' of `{1}' cannot be converted to the generic parameter `{0}' of `{2}' (in the previous ",
382 Type.Name, sig1, sig2));
384 } else if (Type.FullName == target.FullName){
385 Report.ExtraInformation (loc,
387 "The type `{0}' has two conflicting definitions, one comes from `{1}' and the other from `{2}' (in the previous ",
388 Type.FullName, Type.Assembly.FullName, target.Assembly.FullName));
392 Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
393 TypeManager.CSharpName (type), TypeManager.CSharpName (target));
397 Report.DisableReporting ();
398 bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null;
399 Report.EnableReporting ();
402 Report.Error (266, loc, "Cannot implicitly convert type `{0}' to `{1}'. " +
403 "An explicit conversion exists (are you missing a cast?)",
404 TypeManager.CSharpName (Type), TypeManager.CSharpName (target));
408 Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
409 TypeManager.CSharpName (type),
410 TypeManager.CSharpName (target));
413 public virtual void Error_VariableIsUsedBeforeItIsDeclared (string name)
415 Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", name);
418 protected virtual void Error_TypeDoesNotContainDefinition (Type type, string name)
420 Error_TypeDoesNotContainDefinition (loc, type, name);
423 public static void Error_TypeDoesNotContainDefinition (Location loc, Type type, string name)
425 Report.SymbolRelatedToPreviousError (type);
426 Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
427 TypeManager.CSharpName (type), name);
430 protected static void Error_ValueAssignment (Location loc)
432 Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
435 ResolveFlags ExprClassToResolveFlags
440 case ExprClass.Namespace:
441 return ResolveFlags.Type;
443 case ExprClass.MethodGroup:
444 return ResolveFlags.MethodGroup;
446 case ExprClass.TypeParameter:
447 return ResolveFlags.TypeParameter;
449 case ExprClass.Value:
450 case ExprClass.Variable:
451 case ExprClass.PropertyAccess:
452 case ExprClass.EventAccess:
453 case ExprClass.IndexerAccess:
454 return ResolveFlags.VariableOrValue;
457 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
463 /// Resolves an expression and performs semantic analysis on it.
467 /// Currently Resolve wraps DoResolve to perform sanity
468 /// checking and assertion checking on what we expect from Resolve.
470 public Expression Resolve (EmitContext ec, ResolveFlags flags)
472 if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type)
473 return ResolveAsTypeStep (ec, false);
475 bool do_flow_analysis = ec.DoFlowAnalysis;
476 bool omit_struct_analysis = ec.OmitStructFlowAnalysis;
477 if ((flags & ResolveFlags.DisableFlowAnalysis) != 0)
478 do_flow_analysis = false;
479 if ((flags & ResolveFlags.DisableStructFlowAnalysis) != 0)
480 omit_struct_analysis = true;
483 using (ec.WithFlowAnalysis (do_flow_analysis, omit_struct_analysis)) {
484 if (this is SimpleName) {
485 bool intermediate = (flags & ResolveFlags.Intermediate) == ResolveFlags.Intermediate;
486 e = ((SimpleName) this).DoResolve (ec, intermediate);
495 if ((flags & e.ExprClassToResolveFlags) == 0) {
496 e.Error_UnexpectedKind (flags, loc);
500 if (e.type == null && !(e is Namespace)) {
501 throw new Exception (
502 "Expression " + e.GetType () +
503 " did not set its type after Resolve\n" +
504 "called from: " + this.GetType ());
511 /// Resolves an expression and performs semantic analysis on it.
513 public Expression Resolve (EmitContext ec)
515 Expression e = Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
517 if (e != null && e.eclass == ExprClass.MethodGroup && RootContext.Version == LanguageVersion.ISO_1) {
518 ((MethodGroupExpr) e).ReportUsageError ();
524 public Constant ResolveAsConstant (EmitContext ec, MemberCore mc)
526 Expression e = Resolve (ec);
530 Constant c = e as Constant;
534 if (type != null && TypeManager.IsReferenceType (type))
535 Const.Error_ConstantCanBeInitializedWithNullOnly (type, loc, mc.GetSignatureForError ());
537 Const.Error_ExpressionMustBeConstant (loc, mc.GetSignatureForError ());
543 /// Resolves an expression for LValue assignment
547 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
548 /// checking and assertion checking on what we expect from Resolve
550 public Expression ResolveLValue (EmitContext ec, Expression right_side, Location loc)
552 int errors = Report.Errors;
553 bool out_access = right_side == EmptyExpression.OutAccess;
555 Expression e = DoResolveLValue (ec, right_side);
557 if (e != null && out_access && !(e is IMemoryLocation)) {
558 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
559 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
561 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
562 // e.GetType () + " " + e.GetSignatureForError ());
567 if (errors == Report.Errors) {
569 Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
571 Error_ValueAssignment (loc);
576 if (e.eclass == ExprClass.Invalid)
577 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
579 if ((e.type == null) && !(e is GenericTypeExpr))
580 throw new Exception ("Expression " + e + " did not set its type after Resolve");
586 /// Emits the code for the expression
590 /// The Emit method is invoked to generate the code
591 /// for the expression.
593 public abstract void Emit (EmitContext ec);
595 // Emit code to branch to @target if this expression is equivalent to @on_true.
596 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
597 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
598 // including the use of conditional branches. Note also that a branch MUST be emitted
599 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
602 ec.ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
605 // Emit this expression for its side effects, not for its value.
606 // The default implementation is to emit the value, and then throw it away.
607 // Subclasses can provide more efficient implementations, but those MUST be equivalent
608 public virtual void EmitSideEffect (EmitContext ec)
611 ec.ig.Emit (OpCodes.Pop);
615 /// Protected constructor. Only derivate types should
616 /// be able to be created
619 protected Expression ()
621 eclass = ExprClass.Invalid;
626 /// Returns a fully formed expression after a MemberLookup
629 public static Expression ExprClassFromMemberInfo (Type container_type, MemberInfo mi, Location loc)
632 return new EventExpr ((EventInfo) mi, loc);
633 else if (mi is FieldInfo) {
634 FieldInfo fi = (FieldInfo) mi;
635 if (fi.IsLiteral || (fi.IsInitOnly && fi.FieldType == TypeManager.decimal_type))
636 return new ConstantExpr (fi, loc);
637 return new FieldExpr (fi, loc);
638 } else if (mi is PropertyInfo)
639 return new PropertyExpr (container_type, (PropertyInfo) mi, loc);
640 else if (mi is Type) {
641 return new TypeExpression ((System.Type) mi, loc);
647 // TODO: [Obsolete ("Can be removed")]
648 protected static ArrayList almost_matched_members = new ArrayList (4);
651 // FIXME: Probably implement a cache for (t,name,current_access_set)?
653 // This code could use some optimizations, but we need to do some
654 // measurements. For example, we could use a delegate to `flag' when
655 // something can not any longer be a method-group (because it is something
659 // If the return value is an Array, then it is an array of
662 // If the return value is an MemberInfo, it is anything, but a Method
666 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
667 // the arguments here and have MemberLookup return only the methods that
668 // match the argument count/type, unlike we are doing now (we delay this
671 // This is so we can catch correctly attempts to invoke instance methods
672 // from a static body (scan for error 120 in ResolveSimpleName).
675 // FIXME: Potential optimization, have a static ArrayList
678 public static Expression MemberLookup (Type container_type, Type queried_type, string name,
679 MemberTypes mt, BindingFlags bf, Location loc)
681 return MemberLookup (container_type, null, queried_type, name, mt, bf, loc);
685 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
686 // `qualifier_type' or null to lookup members in the current class.
689 public static Expression MemberLookup (Type container_type,
690 Type qualifier_type, Type queried_type,
691 string name, MemberTypes mt,
692 BindingFlags bf, Location loc)
694 almost_matched_members.Clear ();
696 MemberInfo [] mi = TypeManager.MemberLookup (container_type, qualifier_type,
697 queried_type, mt, bf, name, almost_matched_members);
703 bool is_interface = qualifier_type != null && qualifier_type.IsInterface;
704 ArrayList methods = new ArrayList (2);
705 ArrayList non_methods = null;
707 foreach (MemberInfo m in mi) {
708 if (m is MethodBase) {
713 if (non_methods == null) {
714 non_methods = new ArrayList (2);
719 foreach (MemberInfo n_m in non_methods) {
720 if (m.DeclaringType.IsInterface && TypeManager.ImplementsInterface (m.DeclaringType, n_m.DeclaringType))
723 Report.SymbolRelatedToPreviousError (m);
724 Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
725 TypeManager.GetFullNameSignature (m), TypeManager.GetFullNameSignature (n_m));
730 if (methods.Count == 0)
731 return ExprClassFromMemberInfo (container_type, (MemberInfo)non_methods [0], loc);
733 if (non_methods != null) {
734 MethodBase method = (MethodBase) methods [0];
735 MemberInfo non_method = (MemberInfo) non_methods [0];
736 if (method.DeclaringType == non_method.DeclaringType) {
737 // Cannot happen with C# code, but is valid in IL
738 Report.SymbolRelatedToPreviousError (method);
739 Report.SymbolRelatedToPreviousError (non_method);
740 Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
741 TypeManager.GetFullNameSignature (non_method),
742 TypeManager.CSharpSignature (method));
747 Report.SymbolRelatedToPreviousError (method);
748 Report.SymbolRelatedToPreviousError (non_method);
749 Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and non-method `{1}'. Using method `{0}'",
750 TypeManager.CSharpSignature (method), TypeManager.GetFullNameSignature (non_method));
754 return new MethodGroupExpr (methods, queried_type, loc);
757 if (mi [0] is MethodBase)
758 return new MethodGroupExpr (mi, queried_type, loc);
760 return ExprClassFromMemberInfo (container_type, mi [0], loc);
763 public const MemberTypes AllMemberTypes =
764 MemberTypes.Constructor |
768 MemberTypes.NestedType |
769 MemberTypes.Property;
771 public const BindingFlags AllBindingFlags =
772 BindingFlags.Public |
773 BindingFlags.Static |
774 BindingFlags.Instance;
776 public static Expression MemberLookup (Type container_type, Type queried_type,
777 string name, Location loc)
779 return MemberLookup (container_type, null, queried_type, name,
780 AllMemberTypes, AllBindingFlags, loc);
783 public static Expression MemberLookup (Type container_type, Type qualifier_type,
784 Type queried_type, string name, Location loc)
786 return MemberLookup (container_type, qualifier_type, queried_type,
787 name, AllMemberTypes, AllBindingFlags, loc);
790 public static MethodGroupExpr MethodLookup (Type container_type, Type queried_type,
791 string name, Location loc)
793 return (MethodGroupExpr)MemberLookup (container_type, null, queried_type, name,
794 MemberTypes.Method, AllBindingFlags, loc);
798 /// This is a wrapper for MemberLookup that is not used to "probe", but
799 /// to find a final definition. If the final definition is not found, we
800 /// look for private members and display a useful debugging message if we
803 protected Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
804 Type queried_type, string name,
805 MemberTypes mt, BindingFlags bf,
810 int errors = Report.Errors;
811 e = MemberLookup (ec.ContainerType, qualifier_type, queried_type, name, mt, bf, loc);
813 if (e != null || errors != Report.Errors)
816 // No errors were reported by MemberLookup, but there was an error.
817 return Error_MemberLookupFailed (ec.ContainerType, qualifier_type, queried_type,
821 protected virtual Expression Error_MemberLookupFailed (Type container_type, Type qualifier_type,
822 Type queried_type, string name, string class_name,
823 MemberTypes mt, BindingFlags bf)
825 MemberInfo[] lookup = null;
826 if (queried_type == null) {
827 class_name = "global::";
829 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
830 mt, (bf & ~BindingFlags.Public) | BindingFlags.NonPublic,
833 if (lookup != null) {
834 Expression e = Error_MemberLookupFailed (queried_type, lookup);
837 // FIXME: This is still very wrong, it should be done inside
838 // OverloadResolve to do correct arguments matching.
839 // Requires MemberLookup accessiblity check removal
841 if (e == null || (mt & (MemberTypes.Method | MemberTypes.Constructor)) == 0) {
842 MemberInfo mi = lookup[0];
843 Report.SymbolRelatedToPreviousError (mi);
844 if (qualifier_type != null && container_type != null && qualifier_type != container_type &&
845 TypeManager.IsNestedFamilyAccessible (container_type, mi.DeclaringType)) {
846 // Although a derived class can access protected members of
847 // its base class it cannot do so through an instance of the
848 // base class (CS1540). If the qualifier_type is a base of the
849 // ec.ContainerType and the lookup succeeds with the latter one,
850 // then we are in this situation.
851 Error_CannotAccessProtected (loc, mi, qualifier_type, container_type);
853 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (mi));
860 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
861 AllMemberTypes, AllBindingFlags | BindingFlags.NonPublic,
865 if (lookup == null) {
866 if (class_name != null) {
867 Report.Error (103, loc, "The name `{0}' does not exist in the current context",
870 Error_TypeDoesNotContainDefinition (queried_type, name);
875 if (TypeManager.MemberLookup (queried_type, null, queried_type,
876 AllMemberTypes, AllBindingFlags |
877 BindingFlags.NonPublic, name, null) == null) {
878 if ((lookup.Length == 1) && (lookup [0] is Type)) {
879 Type t = (Type) lookup [0];
881 Report.Error (305, loc,
882 "Using the generic type `{0}' " +
883 "requires {1} type arguments",
884 TypeManager.CSharpName (t),
885 TypeManager.GetNumberOfTypeArguments (t).ToString ());
890 return Error_MemberLookupFailed (queried_type, lookup);
893 protected virtual Expression Error_MemberLookupFailed (Type type, MemberInfo[] members)
895 for (int i = 0; i < members.Length; ++i) {
896 if (!(members [i] is MethodBase))
900 // By default propagate the closest candidates upwards
901 return new MethodGroupExpr (members, type, loc, true);
904 protected virtual void Error_NegativeArrayIndex (Location loc)
906 throw new NotImplementedException ();
909 protected void Error_PointerInsideExpressionTree ()
911 Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
915 /// Returns an expression that can be used to invoke operator true
916 /// on the expression if it exists.
918 static public Expression GetOperatorTrue (EmitContext ec, Expression e, Location loc)
920 return GetOperatorTrueOrFalse (ec, e, true, loc);
924 /// Returns an expression that can be used to invoke operator false
925 /// on the expression if it exists.
927 static public Expression GetOperatorFalse (EmitContext ec, Expression e, Location loc)
929 return GetOperatorTrueOrFalse (ec, e, false, loc);
932 static Expression GetOperatorTrueOrFalse (EmitContext ec, Expression e, bool is_true, Location loc)
934 MethodGroupExpr operator_group;
935 string mname = Operator.GetMetadataName (is_true ? Operator.OpType.True : Operator.OpType.False);
936 operator_group = MethodLookup (ec.ContainerType, e.Type, mname, loc) as MethodGroupExpr;
937 if (operator_group == null)
940 ArrayList arguments = new ArrayList (1);
941 arguments.Add (new Argument (e, Argument.AType.Expression));
942 operator_group = operator_group.OverloadResolve (
943 ec, ref arguments, false, loc);
945 if (operator_group == null)
948 return new UserOperatorCall (operator_group, arguments, null, loc);
952 /// Resolves the expression `e' into a boolean expression: either through
953 /// an implicit conversion, or through an `operator true' invocation
955 public static Expression ResolveBoolean (EmitContext ec, Expression e, Location loc)
961 if (e.Type == TypeManager.bool_type)
964 Expression converted = Convert.ImplicitConversion (ec, e, TypeManager.bool_type, Location.Null);
966 if (converted != null)
970 // If no implicit conversion to bool exists, try using `operator true'
972 converted = Expression.GetOperatorTrue (ec, e, loc);
973 if (converted == null){
974 e.Error_ValueCannotBeConverted (ec, loc, TypeManager.bool_type, false);
980 public virtual string ExprClassName
984 case ExprClass.Invalid:
986 case ExprClass.Value:
988 case ExprClass.Variable:
990 case ExprClass.Namespace:
994 case ExprClass.MethodGroup:
995 return "method group";
996 case ExprClass.PropertyAccess:
997 return "property access";
998 case ExprClass.EventAccess:
999 return "event access";
1000 case ExprClass.IndexerAccess:
1001 return "indexer access";
1002 case ExprClass.Nothing:
1004 case ExprClass.TypeParameter:
1005 return "type parameter";
1007 throw new Exception ("Should not happen");
1012 /// Reports that we were expecting `expr' to be of class `expected'
1014 public void Error_UnexpectedKind (DeclSpace ds, string expected, Location loc)
1016 Error_UnexpectedKind (ds, expected, ExprClassName, loc);
1019 public void Error_UnexpectedKind (DeclSpace ds, string expected, string was, Location loc)
1021 string name = GetSignatureForError ();
1023 name = ds.GetSignatureForError () + '.' + name;
1025 Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
1026 name, was, expected);
1029 public void Error_UnexpectedKind (ResolveFlags flags, Location loc)
1031 string [] valid = new string [4];
1034 if ((flags & ResolveFlags.VariableOrValue) != 0) {
1035 valid [count++] = "variable";
1036 valid [count++] = "value";
1039 if ((flags & ResolveFlags.Type) != 0)
1040 valid [count++] = "type";
1042 if ((flags & ResolveFlags.MethodGroup) != 0)
1043 valid [count++] = "method group";
1046 valid [count++] = "unknown";
1048 StringBuilder sb = new StringBuilder (valid [0]);
1049 for (int i = 1; i < count - 1; i++) {
1051 sb.Append (valid [i]);
1054 sb.Append ("' or `");
1055 sb.Append (valid [count - 1]);
1058 Report.Error (119, loc,
1059 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1062 public static void UnsafeError (Location loc)
1064 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1068 // Load the object from the pointer.
1070 public static void LoadFromPtr (ILGenerator ig, Type t)
1072 if (t == TypeManager.int32_type)
1073 ig.Emit (OpCodes.Ldind_I4);
1074 else if (t == TypeManager.uint32_type)
1075 ig.Emit (OpCodes.Ldind_U4);
1076 else if (t == TypeManager.short_type)
1077 ig.Emit (OpCodes.Ldind_I2);
1078 else if (t == TypeManager.ushort_type)
1079 ig.Emit (OpCodes.Ldind_U2);
1080 else if (t == TypeManager.char_type)
1081 ig.Emit (OpCodes.Ldind_U2);
1082 else if (t == TypeManager.byte_type)
1083 ig.Emit (OpCodes.Ldind_U1);
1084 else if (t == TypeManager.sbyte_type)
1085 ig.Emit (OpCodes.Ldind_I1);
1086 else if (t == TypeManager.uint64_type)
1087 ig.Emit (OpCodes.Ldind_I8);
1088 else if (t == TypeManager.int64_type)
1089 ig.Emit (OpCodes.Ldind_I8);
1090 else if (t == TypeManager.float_type)
1091 ig.Emit (OpCodes.Ldind_R4);
1092 else if (t == TypeManager.double_type)
1093 ig.Emit (OpCodes.Ldind_R8);
1094 else if (t == TypeManager.bool_type)
1095 ig.Emit (OpCodes.Ldind_I1);
1096 else if (t == TypeManager.intptr_type)
1097 ig.Emit (OpCodes.Ldind_I);
1098 else if (TypeManager.IsEnumType (t)) {
1099 if (t == TypeManager.enum_type)
1100 ig.Emit (OpCodes.Ldind_Ref);
1102 LoadFromPtr (ig, TypeManager.GetEnumUnderlyingType (t));
1103 } else if (TypeManager.IsStruct (t) || TypeManager.IsGenericParameter (t))
1104 ig.Emit (OpCodes.Ldobj, t);
1105 else if (t.IsPointer)
1106 ig.Emit (OpCodes.Ldind_I);
1108 ig.Emit (OpCodes.Ldind_Ref);
1112 // The stack contains the pointer and the value of type `type'
1114 public static void StoreFromPtr (ILGenerator ig, Type type)
1116 if (TypeManager.IsEnumType (type))
1117 type = TypeManager.GetEnumUnderlyingType (type);
1118 if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
1119 ig.Emit (OpCodes.Stind_I4);
1120 else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
1121 ig.Emit (OpCodes.Stind_I8);
1122 else if (type == TypeManager.char_type || type == TypeManager.short_type ||
1123 type == TypeManager.ushort_type)
1124 ig.Emit (OpCodes.Stind_I2);
1125 else if (type == TypeManager.float_type)
1126 ig.Emit (OpCodes.Stind_R4);
1127 else if (type == TypeManager.double_type)
1128 ig.Emit (OpCodes.Stind_R8);
1129 else if (type == TypeManager.byte_type || type == TypeManager.sbyte_type ||
1130 type == TypeManager.bool_type)
1131 ig.Emit (OpCodes.Stind_I1);
1132 else if (type == TypeManager.intptr_type)
1133 ig.Emit (OpCodes.Stind_I);
1134 else if (TypeManager.IsStruct (type) || TypeManager.IsGenericParameter (type))
1135 ig.Emit (OpCodes.Stobj, type);
1137 ig.Emit (OpCodes.Stind_Ref);
1141 // Returns the size of type `t' if known, otherwise, 0
1143 public static int GetTypeSize (Type t)
1145 t = TypeManager.TypeToCoreType (t);
1146 if (t == TypeManager.int32_type ||
1147 t == TypeManager.uint32_type ||
1148 t == TypeManager.float_type)
1150 else if (t == TypeManager.int64_type ||
1151 t == TypeManager.uint64_type ||
1152 t == TypeManager.double_type)
1154 else if (t == TypeManager.byte_type ||
1155 t == TypeManager.sbyte_type ||
1156 t == TypeManager.bool_type)
1158 else if (t == TypeManager.short_type ||
1159 t == TypeManager.char_type ||
1160 t == TypeManager.ushort_type)
1162 else if (t == TypeManager.decimal_type)
1168 protected void Error_CannotCallAbstractBase (string name)
1170 Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
1173 protected void Error_CannotModifyIntermediateExpressionValue (EmitContext ec)
1175 Report.SymbolRelatedToPreviousError (type);
1176 if (ec.CurrentInitializerVariable != null) {
1177 Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
1178 TypeManager.CSharpName (type), GetSignatureForError ());
1180 Report.Error (1612, loc, "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
1181 GetSignatureForError ());
1185 public void Error_ExpressionCannotBeGeneric (Location loc)
1187 Report.Error (307, loc, "The {0} `{1}' cannot be used with type arguments",
1188 ExprClassName, GetSignatureForError ());
1192 // Converts `source' to an int, uint, long or ulong.
1194 public Expression ConvertExpressionToArrayIndex (EmitContext ec, Expression source)
1196 Expression converted;
1198 using (ec.With (EmitContext.Flags.CheckState, true)) {
1199 converted = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, source.loc);
1200 if (converted == null)
1201 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, source.loc);
1202 if (converted == null)
1203 converted = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, source.loc);
1204 if (converted == null)
1205 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, source.loc);
1207 if (converted == null) {
1208 source.Error_ValueCannotBeConverted (ec, source.loc, TypeManager.int32_type, false);
1214 // Only positive constants are allowed at compile time
1216 Constant c = converted as Constant;
1219 Error_NegativeArrayIndex (source.loc);
1224 return new ArrayIndexCast (converted).Resolve (ec);
1228 // Derived classes implement this method by cloning the fields that
1229 // could become altered during the Resolve stage
1231 // Only expressions that are created for the parser need to implement
1234 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1236 throw new NotImplementedException (
1238 "CloneTo not implemented for expression {0}", this.GetType ()));
1242 // Clones an expression created by the parser.
1244 // We only support expressions created by the parser so far, not
1245 // expressions that have been resolved (many more classes would need
1246 // to implement CloneTo).
1248 // This infrastructure is here merely for Lambda expressions which
1249 // compile the same code using different type values for the same
1250 // arguments to find the correct overload
1252 public Expression Clone (CloneContext clonectx)
1254 Expression cloned = (Expression) MemberwiseClone ();
1255 CloneTo (clonectx, cloned);
1261 // Implementation of expression to expression tree conversion
1263 public abstract Expression CreateExpressionTree (EmitContext ec);
1265 protected Expression CreateExpressionFactoryCall (string name, ArrayList args)
1267 return CreateExpressionFactoryCall (name, null, args, loc);
1270 protected Expression CreateExpressionFactoryCall (string name, TypeArguments typeArguments, ArrayList args)
1272 return CreateExpressionFactoryCall (name, typeArguments, args, loc);
1275 public static Expression CreateExpressionFactoryCall (string name, TypeArguments typeArguments, ArrayList args, Location loc)
1277 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (loc), name, typeArguments, loc), args);
1280 protected static TypeExpr CreateExpressionTypeExpression (Location loc)
1282 TypeExpr texpr = TypeManager.expression_type_expr;
1283 if (texpr == null) {
1284 Type t = TypeManager.CoreLookupType ("System.Linq.Expressions", "Expression", Kind.Class, true);
1288 TypeManager.expression_type_expr = texpr = new TypeExpression (t, Location.Null);
1294 public virtual void MutateHoistedGenericType (AnonymousMethodStorey storey)
1296 // TODO: It should probably be type = storey.MutateType (type);
1301 /// This is just a base class for expressions that can
1302 /// appear on statements (invocations, object creation,
1303 /// assignments, post/pre increment and decrement). The idea
1304 /// being that they would support an extra Emition interface that
1305 /// does not leave a result on the stack.
1307 public abstract class ExpressionStatement : Expression {
1309 public virtual ExpressionStatement ResolveStatement (EmitContext ec)
1311 Expression e = Resolve (ec);
1315 ExpressionStatement es = e as ExpressionStatement;
1317 Error_InvalidExpressionStatement ();
1323 /// Requests the expression to be emitted in a `statement'
1324 /// context. This means that no new value is left on the
1325 /// stack after invoking this method (constrasted with
1326 /// Emit that will always leave a value on the stack).
1328 public abstract void EmitStatement (EmitContext ec);
1330 public override void EmitSideEffect (EmitContext ec)
1337 /// This kind of cast is used to encapsulate the child
1338 /// whose type is child.Type into an expression that is
1339 /// reported to return "return_type". This is used to encapsulate
1340 /// expressions which have compatible types, but need to be dealt
1341 /// at higher levels with.
1343 /// For example, a "byte" expression could be encapsulated in one
1344 /// of these as an "unsigned int". The type for the expression
1345 /// would be "unsigned int".
1348 public abstract class TypeCast : Expression
1350 protected readonly Expression child;
1352 protected TypeCast (Expression child, Type return_type)
1354 eclass = child.eclass;
1355 loc = child.Location;
1360 public override Expression CreateExpressionTree (EmitContext ec)
1362 ArrayList args = new ArrayList (2);
1363 args.Add (new Argument (child.CreateExpressionTree (ec)));
1364 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1366 if (type.IsPointer || child.Type.IsPointer)
1367 Error_PointerInsideExpressionTree ();
1369 return CreateExpressionFactoryCall (ec.CheckState ? "ConvertChecked" : "Convert", args);
1372 public override Expression DoResolve (EmitContext ec)
1374 // This should never be invoked, we are born in fully
1375 // initialized state.
1380 public override void Emit (EmitContext ec)
1385 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
1387 return child.GetAttributableValue (ec, value_type, out value);
1390 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1392 type = storey.MutateType (type);
1393 child.MutateHoistedGenericType (storey);
1396 protected override void CloneTo (CloneContext clonectx, Expression t)
1401 public override bool IsNull {
1402 get { return child.IsNull; }
1406 public class EmptyCast : TypeCast {
1407 EmptyCast (Expression child, Type target_type)
1408 : base (child, target_type)
1412 public static Expression Create (Expression child, Type type)
1414 Constant c = child as Constant;
1416 return new EmptyConstantCast (c, type);
1418 EmptyCast e = child as EmptyCast;
1420 return new EmptyCast (e.child, type);
1422 return new EmptyCast (child, type);
1425 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1427 child.EmitBranchable (ec, label, on_true);
1430 public override void EmitSideEffect (EmitContext ec)
1432 child.EmitSideEffect (ec);
1437 // Used for predefined class library user casts (no obsolete check, etc.)
1439 public class OperatorCast : TypeCast {
1440 MethodInfo conversion_operator;
1442 public OperatorCast (Expression child, Type target_type)
1443 : this (child, target_type, false)
1447 public OperatorCast (Expression child, Type target_type, bool find_explicit)
1448 : base (child, target_type)
1450 conversion_operator = GetConversionOperator (find_explicit);
1451 if (conversion_operator == null)
1452 throw new InternalErrorException ("Outer conversion routine is out of sync");
1455 // Returns the implicit operator that converts from
1456 // 'child.Type' to our target type (type)
1457 MethodInfo GetConversionOperator (bool find_explicit)
1459 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1463 mi = TypeManager.MemberLookup (child.Type, child.Type, child.Type, MemberTypes.Method,
1464 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1467 mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1468 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1471 foreach (MethodInfo oper in mi) {
1472 AParametersCollection pd = TypeManager.GetParameterData (oper);
1474 if (pd.Types [0] == child.Type && TypeManager.TypeToCoreType (oper.ReturnType) == type)
1481 public override void Emit (EmitContext ec)
1484 ec.ig.Emit (OpCodes.Call, conversion_operator);
1489 /// This is a numeric cast to a Decimal
1491 public class CastToDecimal : OperatorCast {
1492 public CastToDecimal (Expression child)
1493 : this (child, false)
1497 public CastToDecimal (Expression child, bool find_explicit)
1498 : base (child, TypeManager.decimal_type, find_explicit)
1504 /// This is an explicit numeric cast from a Decimal
1506 public class CastFromDecimal : TypeCast
1508 static IDictionary operators;
1510 public CastFromDecimal (Expression child, Type return_type)
1511 : base (child, return_type)
1513 if (child.Type != TypeManager.decimal_type)
1514 throw new InternalErrorException (
1515 "The expected type is Decimal, instead it is " + child.Type.FullName);
1518 // Returns the explicit operator that converts from an
1519 // express of type System.Decimal to 'type'.
1520 public Expression Resolve ()
1522 if (operators == null) {
1523 MemberInfo[] all_oper = TypeManager.MemberLookup (TypeManager.decimal_type,
1524 TypeManager.decimal_type, TypeManager.decimal_type, MemberTypes.Method,
1525 BindingFlags.Static | BindingFlags.Public, "op_Explicit", null);
1527 operators = new System.Collections.Specialized.HybridDictionary ();
1528 foreach (MethodInfo oper in all_oper) {
1529 AParametersCollection pd = TypeManager.GetParameterData (oper);
1530 if (pd.Types [0] == TypeManager.decimal_type)
1531 operators.Add (TypeManager.TypeToCoreType (oper.ReturnType), oper);
1535 return operators.Contains (type) ? this : null;
1538 public override void Emit (EmitContext ec)
1540 ILGenerator ig = ec.ig;
1543 ig.Emit (OpCodes.Call, (MethodInfo)operators [type]);
1549 // Constant specialization of EmptyCast.
1550 // We need to special case this since an empty cast of
1551 // a constant is still a constant.
1553 public class EmptyConstantCast : Constant
1555 public readonly Constant child;
1557 public EmptyConstantCast(Constant child, Type type)
1558 : base (child.Location)
1560 eclass = child.eclass;
1565 public override string AsString ()
1567 return child.AsString ();
1570 public override object GetValue ()
1572 return child.GetValue ();
1575 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
1577 // FIXME: check that 'type' can be converted to 'target_type' first
1578 return child.ConvertExplicitly (in_checked_context, target_type);
1581 public override Expression CreateExpressionTree (EmitContext ec)
1583 ArrayList args = new ArrayList (2);
1584 args.Add (new Argument (child.CreateExpressionTree (ec)));
1585 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1587 Error_PointerInsideExpressionTree ();
1589 return CreateExpressionFactoryCall ("Convert", args);
1592 public override Constant Increment ()
1594 return child.Increment ();
1597 public override bool IsDefaultValue {
1598 get { return child.IsDefaultValue; }
1601 public override bool IsNegative {
1602 get { return child.IsNegative; }
1605 public override bool IsNull {
1606 get { return child.IsNull; }
1609 public override bool IsZeroInteger {
1610 get { return child.IsZeroInteger; }
1613 public override void Emit (EmitContext ec)
1618 // Only to make verifier happy
1619 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1620 ec.ig.Emit (OpCodes.Unbox_Any, type);
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 == CodeGen.Module.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)
1853 ILGenerator ig = ec.ig;
1857 if (type.IsGenericParameter || type.IsGenericType && type.IsValueType)
1858 ig.Emit (OpCodes.Unbox_Any, type);
1862 ig.Emit (OpCodes.Unbox, type);
1864 LoadFromPtr (ig, type);
1868 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1870 type = storey.MutateType (type);
1871 base.MutateHoistedGenericType (storey);
1876 /// This is used to perform explicit numeric conversions.
1878 /// Explicit numeric conversions might trigger exceptions in a checked
1879 /// context, so they should generate the conv.ovf opcodes instead of
1882 public class ConvCast : TypeCast {
1883 public enum Mode : byte {
1884 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1886 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1887 U2_I1, U2_U1, U2_I2, U2_CH,
1888 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1889 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1890 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH,
1891 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH,
1892 CH_I1, CH_U1, CH_I2,
1893 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1894 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4
1899 public ConvCast (Expression child, Type return_type, Mode m)
1900 : base (child, return_type)
1905 public override Expression DoResolve (EmitContext ec)
1907 // This should never be invoked, we are born in fully
1908 // initialized state.
1913 public override string ToString ()
1915 return String.Format ("ConvCast ({0}, {1})", mode, child);
1918 public override void Emit (EmitContext ec)
1920 ILGenerator ig = ec.ig;
1926 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1927 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1928 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1929 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1930 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1932 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1933 case Mode.U1_CH: /* nothing */ break;
1935 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1936 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1937 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1938 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1939 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1940 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1942 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1943 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1944 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1945 case Mode.U2_CH: /* nothing */ break;
1947 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1948 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1949 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1950 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1951 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1952 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1953 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1955 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1956 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1957 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1958 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1959 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1960 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1962 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1963 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1964 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1965 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1966 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1967 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1968 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1969 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1971 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1972 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1973 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1974 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1975 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1976 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1977 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1978 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1980 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1981 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1982 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1984 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1985 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1986 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1987 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1988 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1989 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1990 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1991 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1992 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1994 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1995 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1996 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1997 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1998 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1999 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
2000 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
2001 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
2002 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
2003 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
2007 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
2008 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
2009 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
2010 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
2011 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
2013 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
2014 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
2016 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
2017 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
2018 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
2019 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
2020 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
2021 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
2023 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
2024 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
2025 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
2026 case Mode.U2_CH: /* nothing */ break;
2028 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
2029 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
2030 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
2031 case Mode.I4_U4: /* nothing */ break;
2032 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
2033 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
2034 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
2036 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
2037 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
2038 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
2039 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
2040 case Mode.U4_I4: /* nothing */ break;
2041 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
2043 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
2044 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
2045 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
2046 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
2047 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
2048 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
2049 case Mode.I8_U8: /* nothing */ break;
2050 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
2052 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
2053 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
2054 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
2055 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
2056 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
2057 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
2058 case Mode.U8_I8: /* nothing */ break;
2059 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
2061 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
2062 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
2063 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
2065 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
2066 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
2067 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
2068 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
2069 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
2070 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
2071 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
2072 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
2073 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
2075 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
2076 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
2077 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
2078 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
2079 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
2080 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
2081 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
2082 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
2083 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
2084 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
2090 public class OpcodeCast : TypeCast {
2093 public OpcodeCast (Expression child, Type return_type, OpCode op)
2094 : base (child, return_type)
2099 public override Expression DoResolve (EmitContext ec)
2101 // This should never be invoked, we are born in fully
2102 // initialized state.
2107 public override void Emit (EmitContext ec)
2113 public Type UnderlyingType {
2114 get { return child.Type; }
2119 /// This kind of cast is used to encapsulate a child and cast it
2120 /// to the class requested
2122 public sealed class ClassCast : TypeCast {
2123 readonly bool forced;
2125 public ClassCast (Expression child, Type return_type)
2126 : base (child, return_type)
2130 public ClassCast (Expression child, Type return_type, bool forced)
2131 : base (child, return_type)
2133 this.forced = forced;
2136 public override void Emit (EmitContext ec)
2141 bool gen = TypeManager.IsGenericParameter (child.Type);
2143 ec.ig.Emit (OpCodes.Box, child.Type);
2145 if (type.IsGenericParameter) {
2146 ec.ig.Emit (OpCodes.Unbox_Any, type);
2154 ec.ig.Emit (OpCodes.Castclass, type);
2159 // Created during resolving pahse when an expression is wrapped or constantified
2160 // and original expression can be used later (e.g. for expression trees)
2162 public class ReducedExpression : Expression
2164 sealed class ReducedConstantExpression : EmptyConstantCast
2166 readonly Expression orig_expr;
2168 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2169 : base (expr, expr.Type)
2171 this.orig_expr = orig_expr;
2174 public override Constant ConvertImplicitly (Type target_type)
2176 Constant c = base.ConvertImplicitly (target_type);
2178 c = new ReducedConstantExpression (c, orig_expr);
2182 public override Expression CreateExpressionTree (EmitContext ec)
2184 return orig_expr.CreateExpressionTree (ec);
2187 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
2190 // Even if resolved result is a constant original expression was not
2191 // and attribute accepts constants only
2193 Attribute.Error_AttributeArgumentNotValid (orig_expr.Location);
2198 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
2200 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
2202 c = new ReducedConstantExpression (c, orig_expr);
2207 sealed class ReducedExpressionStatement : ExpressionStatement
2209 readonly Expression orig_expr;
2210 readonly ExpressionStatement stm;
2212 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
2214 this.orig_expr = orig;
2216 this.loc = orig.Location;
2219 public override Expression CreateExpressionTree (EmitContext ec)
2221 return orig_expr.CreateExpressionTree (ec);
2224 public override Expression DoResolve (EmitContext ec)
2226 eclass = stm.eclass;
2231 public override void Emit (EmitContext ec)
2236 public override void EmitStatement (EmitContext ec)
2238 stm.EmitStatement (ec);
2241 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2243 stm.MutateHoistedGenericType (storey);
2247 readonly Expression expr, orig_expr;
2249 private ReducedExpression (Expression expr, Expression orig_expr)
2252 this.orig_expr = orig_expr;
2253 this.loc = orig_expr.Location;
2256 public static Constant Create (Constant expr, Expression original_expr)
2258 return new ReducedConstantExpression (expr, original_expr);
2261 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
2263 return new ReducedExpressionStatement (s, orig);
2266 public static Expression Create (Expression expr, Expression original_expr)
2268 Constant c = expr as Constant;
2270 return Create (c, original_expr);
2272 ExpressionStatement s = expr as ExpressionStatement;
2274 return Create (s, original_expr);
2276 return new ReducedExpression (expr, original_expr);
2279 public override Expression CreateExpressionTree (EmitContext ec)
2281 return orig_expr.CreateExpressionTree (ec);
2284 public override Expression DoResolve (EmitContext ec)
2286 eclass = expr.eclass;
2291 public override void Emit (EmitContext ec)
2296 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2298 expr.EmitBranchable (ec, target, on_true);
2301 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2303 expr.MutateHoistedGenericType (storey);
2308 // Unresolved type name expressions
2310 public abstract class ATypeNameExpression : FullNamedExpression
2312 public readonly string Name;
2313 protected TypeArguments targs;
2315 protected ATypeNameExpression (string name, Location l)
2321 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2328 public bool HasTypeArguments {
2330 return targs != null;
2334 public override bool Equals (object obj)
2336 ATypeNameExpression atne = obj as ATypeNameExpression;
2337 return atne != null && atne.Name == Name &&
2338 (targs == null || targs.Equals (atne.targs));
2341 public override int GetHashCode ()
2343 return Name.GetHashCode ();
2346 public override string GetSignatureForError ()
2348 if (targs != null) {
2349 return TypeManager.RemoveGenericArity (Name) + "<" +
2350 targs.GetSignatureForError () + ">";
2358 /// SimpleName expressions are formed of a single word and only happen at the beginning
2359 /// of a dotted-name.
2361 public class SimpleName : ATypeNameExpression {
2364 public SimpleName (string name, Location l)
2369 public SimpleName (string name, TypeArguments args, Location l)
2370 : base (name, args, l)
2374 public SimpleName (string name, TypeParameter[] type_params, Location l)
2377 targs = new TypeArguments ();
2378 foreach (TypeParameter type_param in type_params)
2379 targs.Add (new TypeParameterExpr (type_param, l));
2382 public static string RemoveGenericArity (string name)
2385 StringBuilder sb = null;
2387 int pos = name.IndexOf ('`', start);
2392 sb.Append (name.Substring (start));
2397 sb = new StringBuilder ();
2398 sb.Append (name.Substring (start, pos-start));
2401 while ((pos < name.Length) && Char.IsNumber (name [pos]))
2405 } while (start < name.Length);
2407 return sb.ToString ();
2410 public SimpleName GetMethodGroup ()
2412 return new SimpleName (RemoveGenericArity (Name), targs, loc);
2415 public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
2417 if (ec.IsInFieldInitializer)
2418 Report.Error (236, l,
2419 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2422 Report.Error (120, l,
2423 "An object reference is required to access non-static member `{0}'",
2427 public bool IdenticalNameAndTypeName (EmitContext ec, Expression resolved_to, Location loc)
2429 return resolved_to != null && resolved_to.Type != null &&
2430 resolved_to.Type.Name == Name &&
2431 (ec.DeclContainer.LookupNamespaceOrType (Name, loc, /* ignore_cs0104 = */ true) != null);
2434 public override Expression DoResolve (EmitContext ec)
2436 return SimpleNameResolve (ec, null, false);
2439 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
2441 return SimpleNameResolve (ec, right_side, false);
2445 public Expression DoResolve (EmitContext ec, bool intermediate)
2447 return SimpleNameResolve (ec, null, intermediate);
2450 static bool IsNestedChild (Type t, Type parent)
2452 while (parent != null) {
2453 if (TypeManager.IsNestedChildOf (t, TypeManager.DropGenericTypeArguments (parent)))
2456 parent = parent.BaseType;
2462 FullNamedExpression ResolveNested (IResolveContext ec, Type t)
2464 if (!TypeManager.IsGenericTypeDefinition (t) && !TypeManager.IsGenericType (t))
2467 DeclSpace ds = ec.DeclContainer;
2468 while (ds != null && !IsNestedChild (t, ds.TypeBuilder))
2474 Type[] gen_params = TypeManager.GetTypeArguments (t);
2476 int arg_count = targs != null ? targs.Count : 0;
2478 for (; (ds != null) && ds.IsGeneric; ds = ds.Parent) {
2479 if (arg_count + ds.CountTypeParameters == gen_params.Length) {
2480 TypeArguments new_args = new TypeArguments ();
2481 foreach (TypeParameter param in ds.TypeParameters)
2482 new_args.Add (new TypeParameterExpr (param, loc));
2485 new_args.Add (targs);
2487 return new GenericTypeExpr (t, new_args, loc);
2494 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2496 FullNamedExpression fne = ec.GenericDeclContainer.LookupGeneric (Name, loc);
2498 return fne.ResolveAsTypeStep (ec, silent);
2500 int errors = Report.Errors;
2501 fne = ec.DeclContainer.LookupNamespaceOrType (Name, loc, /*ignore_cs0104=*/ false);
2504 if (fne.Type == null)
2507 FullNamedExpression nested = ResolveNested (ec, fne.Type);
2509 return nested.ResolveAsTypeStep (ec, false);
2511 if (targs != null) {
2512 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2513 return ct.ResolveAsTypeStep (ec, false);
2519 if (silent || errors != Report.Errors)
2522 Error_TypeOrNamespaceNotFound (ec);
2526 protected virtual void Error_TypeOrNamespaceNotFound (IResolveContext ec)
2528 MemberCore mc = ec.DeclContainer.GetDefinition (Name);
2530 Error_UnexpectedKind (ec.DeclContainer, "type", GetMemberType (mc), loc);
2534 string ns = ec.DeclContainer.NamespaceEntry.NS.Name;
2535 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2536 foreach (Assembly a in RootNamespace.Global.Assemblies) {
2537 Type type = a.GetType (fullname);
2539 Report.SymbolRelatedToPreviousError (type);
2540 Expression.ErrorIsInaccesible (loc, TypeManager.CSharpName (type));
2545 Type t = ec.DeclContainer.LookupAnyGeneric (Name);
2547 Namespace.Error_InvalidNumberOfTypeArguments (t, loc);
2551 if (targs != null) {
2552 FullNamedExpression retval = ec.DeclContainer.LookupNamespaceOrType (SimpleName.RemoveGenericArity (Name), loc, true);
2553 if (retval != null) {
2554 Namespace.Error_TypeArgumentsCannotBeUsed (retval, loc);
2559 NamespaceEntry.Error_NamespaceNotFound (loc, Name);
2562 // TODO: I am still not convinced about this. If someone else will need it
2563 // implement this as virtual property in MemberCore hierarchy
2564 public static string GetMemberType (MemberCore mc)
2570 if (mc is FieldBase)
2572 if (mc is MethodCore)
2574 if (mc is EnumMember)
2582 Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2588 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2594 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2601 /// 7.5.2: Simple Names.
2603 /// Local Variables and Parameters are handled at
2604 /// parse time, so they never occur as SimpleNames.
2606 /// The `intermediate' flag is used by MemberAccess only
2607 /// and it is used to inform us that it is ok for us to
2608 /// avoid the static check, because MemberAccess might end
2609 /// up resolving the Name as a Type name and the access as
2610 /// a static type access.
2612 /// ie: Type Type; .... { Type.GetType (""); }
2614 /// Type is both an instance variable and a Type; Type.GetType
2615 /// is the static method not an instance method of type.
2617 Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2619 Expression e = null;
2622 // Stage 1: Performed by the parser (binding to locals or parameters).
2624 Block current_block = ec.CurrentBlock;
2625 if (current_block != null){
2626 LocalInfo vi = current_block.GetLocalInfo (Name);
2628 LocalVariableReference var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2629 if (right_side != null) {
2630 return var.ResolveLValue (ec, right_side, loc);
2632 ResolveFlags rf = ResolveFlags.VariableOrValue;
2634 rf |= ResolveFlags.DisableFlowAnalysis;
2635 return var.Resolve (ec, rf);
2639 Expression expr = current_block.Toplevel.GetParameterReference (Name, loc);
2641 if (right_side != null)
2642 return expr.ResolveLValue (ec, right_side, loc);
2644 return expr.Resolve (ec);
2649 // Stage 2: Lookup members
2652 Type almost_matched_type = null;
2653 ArrayList almost_matched = null;
2654 for (DeclSpace lookup_ds = ec.DeclContainer; lookup_ds != null; lookup_ds = lookup_ds.Parent) {
2655 // either RootDeclSpace or GenericMethod
2656 if (lookup_ds.TypeBuilder == null)
2659 e = MemberLookup (ec.ContainerType, lookup_ds.TypeBuilder, Name, loc);
2661 PropertyExpr pe = e as PropertyExpr;
2663 AParametersCollection param = TypeManager.GetParameterData (pe.PropertyInfo);
2665 // since TypeManager.MemberLookup doesn't know if we're doing a lvalue access or not,
2666 // it doesn't know which accessor to check permissions against
2667 if (param.IsEmpty && pe.IsAccessibleFrom (ec.ContainerType, right_side != null))
2669 } else if (e is EventExpr) {
2670 if (((EventExpr) e).IsAccessibleFrom (ec.ContainerType))
2672 } else if (targs != null && e is TypeExpression) {
2673 e = new GenericTypeExpr (e.Type, targs, loc).ResolveAsTypeStep (ec, false);
2681 if (almost_matched == null && almost_matched_members.Count > 0) {
2682 almost_matched_type = lookup_ds.TypeBuilder;
2683 almost_matched = (ArrayList) almost_matched_members.Clone ();
2688 if (almost_matched == null && almost_matched_members.Count > 0) {
2689 almost_matched_type = ec.ContainerType;
2690 almost_matched = (ArrayList) almost_matched_members.Clone ();
2692 e = ResolveAsTypeStep (ec, true);
2696 if (current_block != null) {
2697 IKnownVariable ikv = current_block.Explicit.GetKnownVariable (Name);
2699 LocalInfo li = ikv as LocalInfo;
2700 // Supress CS0219 warning
2704 Error_VariableIsUsedBeforeItIsDeclared (Name);
2709 if (RootContext.EvalMode){
2710 FieldInfo fi = Evaluator.LookupField (Name);
2712 return new FieldExpr (fi, loc).Resolve (ec);
2715 if (almost_matched != null)
2716 almost_matched_members = almost_matched;
2717 if (almost_matched_type == null)
2718 almost_matched_type = ec.ContainerType;
2719 return Error_MemberLookupFailed (ec.ContainerType, null, almost_matched_type, Name,
2720 ec.DeclContainer.Name, AllMemberTypes, AllBindingFlags);
2723 if (e is MemberExpr) {
2724 MemberExpr me = (MemberExpr) e;
2727 if (me.IsInstance) {
2728 if (ec.IsStatic || ec.IsInFieldInitializer) {
2730 // Note that an MemberExpr can be both IsInstance and IsStatic.
2731 // An unresolved MethodGroupExpr can contain both kinds of methods
2732 // and each predicate is true if the MethodGroupExpr contains
2733 // at least one of that kind of method.
2737 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2738 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2743 // Pass the buck to MemberAccess and Invocation.
2745 left = EmptyExpression.Null;
2747 left = ec.GetThis (loc);
2750 left = new TypeExpression (ec.ContainerType, loc);
2753 me = me.ResolveMemberAccess (ec, left, loc, null);
2757 if (targs != null) {
2758 if (!targs.Resolve (ec))
2761 me.SetTypeArguments (targs);
2764 if (!me.IsStatic && (me.InstanceExpression != null) &&
2765 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2766 me.InstanceExpression.Type != me.DeclaringType &&
2767 !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2768 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2769 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2770 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2774 return (right_side != null)
2775 ? me.DoResolveLValue (ec, right_side)
2776 : me.DoResolve (ec);
2784 /// Represents a namespace or a type. The name of the class was inspired by
2785 /// section 10.8.1 (Fully Qualified Names).
2787 public abstract class FullNamedExpression : Expression
2789 protected override void CloneTo (CloneContext clonectx, Expression target)
2791 // Do nothing, most unresolved type expressions cannot be
2792 // resolved to different type
2795 public override Expression CreateExpressionTree (EmitContext ec)
2797 throw new NotSupportedException ("ET");
2800 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2802 throw new NotSupportedException ();
2805 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2810 public override void Emit (EmitContext ec)
2812 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2813 GetSignatureForError ());
2818 /// Expression that evaluates to a type
2820 public abstract class TypeExpr : FullNamedExpression {
2821 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2823 TypeExpr t = DoResolveAsTypeStep (ec);
2827 eclass = ExprClass.Type;
2831 override public Expression DoResolve (EmitContext ec)
2833 return ResolveAsTypeTerminal (ec, false);
2836 public virtual bool CheckAccessLevel (DeclSpace ds)
2838 return ds.CheckAccessLevel (Type);
2841 public virtual bool AsAccessible (DeclSpace ds)
2843 return ds.IsAccessibleAs (Type);
2846 public virtual bool IsClass {
2847 get { return Type.IsClass; }
2850 public virtual bool IsValueType {
2851 get { return TypeManager.IsStruct (Type); }
2854 public virtual bool IsInterface {
2855 get { return Type.IsInterface; }
2858 public virtual bool IsSealed {
2859 get { return Type.IsSealed; }
2862 public virtual bool CanInheritFrom ()
2864 if (Type == TypeManager.enum_type ||
2865 (Type == TypeManager.value_type && RootContext.StdLib) ||
2866 Type == TypeManager.multicast_delegate_type ||
2867 Type == TypeManager.delegate_type ||
2868 Type == TypeManager.array_type)
2874 protected abstract TypeExpr DoResolveAsTypeStep (IResolveContext ec);
2876 public override bool Equals (object obj)
2878 TypeExpr tobj = obj as TypeExpr;
2882 return Type == tobj.Type;
2885 public override int GetHashCode ()
2887 return Type.GetHashCode ();
2890 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2892 type = storey.MutateType (type);
2897 /// Fully resolved Expression that already evaluated to a type
2899 public class TypeExpression : TypeExpr {
2900 public TypeExpression (Type t, Location l)
2903 eclass = ExprClass.Type;
2907 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2912 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2919 // Used to create types from a fully qualified name. These are just used
2920 // by the parser to setup the core types.
2922 public sealed class TypeLookupExpression : TypeExpr {
2923 readonly string ns_name;
2924 readonly string name;
2926 public TypeLookupExpression (string ns, string name)
2930 eclass = ExprClass.Type;
2933 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2936 // It's null only during mscorlib bootstrap when DefineType
2937 // nees to resolve base type of same type
2939 // For instance struct Char : IComparable<char>
2941 // TODO: it could be removed when Resolve starts to use
2942 // DeclSpace instead of Type
2945 Namespace ns = RootNamespace.Global.GetNamespace (ns_name, false);
2946 FullNamedExpression fne = ns.Lookup (null, name, loc);
2954 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2959 public override string GetSignatureForError ()
2962 return TypeManager.CSharpName (ns_name + "." + name, null);
2964 return base.GetSignatureForError ();
2969 /// This class denotes an expression which evaluates to a member
2970 /// of a struct or a class.
2972 public abstract class MemberExpr : Expression
2974 protected bool is_base;
2977 /// The name of this member.
2979 public abstract string Name {
2984 // When base.member is used
2986 public bool IsBase {
2987 get { return is_base; }
2988 set { is_base = value; }
2992 /// Whether this is an instance member.
2994 public abstract bool IsInstance {
2999 /// Whether this is a static member.
3001 public abstract bool IsStatic {
3006 /// The type which declares this member.
3008 public abstract Type DeclaringType {
3013 /// The instance expression associated with this member, if it's a
3014 /// non-static member.
3016 public Expression InstanceExpression;
3018 public static void error176 (Location loc, string name)
3020 Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
3021 "with an instance reference, qualify it with a type name instead", name);
3024 public static void Error_BaseAccessInExpressionTree (Location loc)
3026 Report.Error (831, loc, "An expression tree may not contain a base access");
3029 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3031 if (InstanceExpression != null)
3032 InstanceExpression.MutateHoistedGenericType (storey);
3035 // TODO: possible optimalization
3036 // Cache resolved constant result in FieldBuilder <-> expression map
3037 public virtual MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3038 SimpleName original)
3042 // original == null || original.Resolve (...) ==> left
3045 if (left is TypeExpr) {
3046 left = left.ResolveAsBaseTerminal (ec, false);
3050 // TODO: Same problem as in class.cs, TypeTerminal does not
3051 // always do all necessary checks
3052 ObsoleteAttribute oa = AttributeTester.GetObsoleteAttribute (left.Type);
3053 if (oa != null && !ec.IsInObsoleteScope) {
3054 AttributeTester.Report_ObsoleteMessage (oa, left.GetSignatureForError (), loc);
3057 GenericTypeExpr ct = left as GenericTypeExpr;
3058 if (ct != null && !ct.CheckConstraints (ec))
3063 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3071 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3074 return ResolveExtensionMemberAccess (left);
3077 InstanceExpression = left;
3081 protected virtual MemberExpr ResolveExtensionMemberAccess (Expression left)
3083 error176 (loc, GetSignatureForError ());
3087 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3092 if (InstanceExpression == EmptyExpression.Null) {
3093 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3097 if (TypeManager.IsValueType (InstanceExpression.Type)) {
3098 if (InstanceExpression is IMemoryLocation) {
3099 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
3101 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
3102 InstanceExpression.Emit (ec);
3104 t.AddressOf (ec, AddressOp.Store);
3107 InstanceExpression.Emit (ec);
3109 if (prepare_for_load)
3110 ec.ig.Emit (OpCodes.Dup);
3113 public virtual void SetTypeArguments (TypeArguments ta)
3115 // TODO: need to get correct member type
3116 Report.Error (307, loc, "The property `{0}' cannot be used with type arguments",
3117 GetSignatureForError ());
3122 /// Represents group of extension methods
3124 public class ExtensionMethodGroupExpr : MethodGroupExpr
3126 readonly NamespaceEntry namespace_entry;
3127 public Expression ExtensionExpression;
3128 Argument extension_argument;
3130 public ExtensionMethodGroupExpr (ArrayList list, NamespaceEntry n, Type extensionType, Location l)
3131 : base (list, extensionType, l)
3133 this.namespace_entry = n;
3136 public override bool IsStatic {
3137 get { return true; }
3140 public bool IsTopLevel {
3141 get { return namespace_entry == null; }
3144 public override void EmitArguments (EmitContext ec, ArrayList arguments)
3146 if (arguments == null)
3147 arguments = new ArrayList (1);
3148 arguments.Insert (0, extension_argument);
3149 base.EmitArguments (ec, arguments);
3152 public override void EmitCall (EmitContext ec, ArrayList arguments)
3154 if (arguments == null)
3155 arguments = new ArrayList (1);
3156 arguments.Insert (0, extension_argument);
3157 base.EmitCall (ec, arguments);
3160 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3162 extension_argument.Expr.MutateHoistedGenericType (storey);
3163 base.MutateHoistedGenericType (storey);
3166 public override MethodGroupExpr OverloadResolve (EmitContext ec, ref ArrayList arguments, bool may_fail, Location loc)
3168 if (arguments == null)
3169 arguments = new ArrayList (1);
3171 arguments.Insert (0, new Argument (ExtensionExpression));
3172 MethodGroupExpr mg = ResolveOverloadExtensions (ec, arguments, namespace_entry, loc);
3174 // Store resolved argument and restore original arguments
3176 ((ExtensionMethodGroupExpr)mg).extension_argument = (Argument)arguments [0];
3177 arguments.RemoveAt (0);
3182 MethodGroupExpr ResolveOverloadExtensions (EmitContext ec, ArrayList arguments, NamespaceEntry ns, Location loc)
3184 // Use normal resolve rules
3185 MethodGroupExpr mg = base.OverloadResolve (ec, ref arguments, ns != null, loc);
3193 ExtensionMethodGroupExpr e = ns.LookupExtensionMethod (type, null, Name, loc);
3195 return base.OverloadResolve (ec, ref arguments, false, loc);
3197 e.ExtensionExpression = ExtensionExpression;
3198 e.SetTypeArguments (type_arguments);
3199 return e.ResolveOverloadExtensions (ec, arguments, e.namespace_entry, loc);
3204 /// MethodGroupExpr represents a group of method candidates which
3205 /// can be resolved to the best method overload
3207 public class MethodGroupExpr : MemberExpr
3209 public interface IErrorHandler
3211 bool AmbiguousCall (MethodBase ambiguous);
3212 bool NoExactMatch (EmitContext ec, MethodBase method);
3215 public IErrorHandler CustomErrorHandler;
3216 public MethodBase [] Methods;
3217 MethodBase best_candidate;
3218 // TODO: make private
3219 public TypeArguments type_arguments;
3220 bool identical_type_name;
3221 bool has_inaccessible_candidates_only;
3224 public MethodGroupExpr (MemberInfo [] mi, Type type, Location l)
3227 Methods = new MethodBase [mi.Length];
3228 mi.CopyTo (Methods, 0);
3231 public MethodGroupExpr (MemberInfo[] mi, Type type, Location l, bool inacessibleCandidatesOnly)
3232 : this (mi, type, l)
3234 has_inaccessible_candidates_only = inacessibleCandidatesOnly;
3237 public MethodGroupExpr (ArrayList list, Type type, Location l)
3241 Methods = (MethodBase[])list.ToArray (typeof (MethodBase));
3243 foreach (MemberInfo m in list){
3244 if (!(m is MethodBase)){
3245 Console.WriteLine ("Name " + m.Name);
3246 Console.WriteLine ("Found a: " + m.GetType ().FullName);
3255 protected MethodGroupExpr (Type type, Location loc)
3258 eclass = ExprClass.MethodGroup;
3262 public override Type DeclaringType {
3265 // We assume that the top-level type is in the end
3267 return Methods [Methods.Length - 1].DeclaringType;
3268 //return Methods [0].DeclaringType;
3272 public Type DelegateType {
3274 delegate_type = value;
3278 public bool IdenticalTypeName {
3280 return identical_type_name;
3284 public override string GetSignatureForError ()
3286 if (best_candidate != null)
3287 return TypeManager.CSharpSignature (best_candidate);
3289 return TypeManager.CSharpSignature (Methods [0]);
3292 public override string Name {
3294 return Methods [0].Name;
3298 public override bool IsInstance {
3300 if (best_candidate != null)
3301 return !best_candidate.IsStatic;
3303 foreach (MethodBase mb in Methods)
3311 public override bool IsStatic {
3313 if (best_candidate != null)
3314 return best_candidate.IsStatic;
3316 foreach (MethodBase mb in Methods)
3324 public static explicit operator ConstructorInfo (MethodGroupExpr mg)
3326 return (ConstructorInfo)mg.best_candidate;
3329 public static explicit operator MethodInfo (MethodGroupExpr mg)
3331 return (MethodInfo)mg.best_candidate;
3335 // 7.4.3.3 Better conversion from expression
3336 // Returns : 1 if a->p is better,
3337 // 2 if a->q is better,
3338 // 0 if neither is better
3340 static int BetterExpressionConversion (EmitContext ec, Argument a, Type p, Type q)
3342 Type argument_type = TypeManager.TypeToCoreType (a.Type);
3343 if (argument_type == TypeManager.anonymous_method_type && RootContext.Version > LanguageVersion.ISO_2) {
3345 // Uwrap delegate from Expression<T>
3347 if (TypeManager.DropGenericTypeArguments (p) == TypeManager.expression_type) {
3348 p = TypeManager.GetTypeArguments (p) [0];
3350 if (TypeManager.DropGenericTypeArguments (q) == TypeManager.expression_type) {
3351 q = TypeManager.GetTypeArguments (q) [0];
3354 p = Delegate.GetInvokeMethod (null, p).ReturnType;
3355 q = Delegate.GetInvokeMethod (null, q).ReturnType;
3356 if (p == TypeManager.void_type && q != TypeManager.void_type)
3358 if (q == TypeManager.void_type && p != TypeManager.void_type)
3361 if (argument_type == p)
3364 if (argument_type == q)
3368 return BetterTypeConversion (ec, p, q);
3372 // 7.4.3.4 Better conversion from type
3374 public static int BetterTypeConversion (EmitContext ec, Type p, Type q)
3376 if (p == null || q == null)
3377 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3379 if (p == TypeManager.int32_type) {
3380 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3382 } else if (p == TypeManager.int64_type) {
3383 if (q == TypeManager.uint64_type)
3385 } else if (p == TypeManager.sbyte_type) {
3386 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3387 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3389 } else if (p == TypeManager.short_type) {
3390 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3391 q == TypeManager.uint64_type)
3395 if (q == TypeManager.int32_type) {
3396 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3398 } if (q == TypeManager.int64_type) {
3399 if (p == TypeManager.uint64_type)
3401 } else if (q == TypeManager.sbyte_type) {
3402 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3403 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3405 } if (q == TypeManager.short_type) {
3406 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3407 p == TypeManager.uint64_type)
3411 // TODO: this is expensive
3412 Expression p_tmp = new EmptyExpression (p);
3413 Expression q_tmp = new EmptyExpression (q);
3415 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3416 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3418 if (p_to_q && !q_to_p)
3421 if (q_to_p && !p_to_q)
3428 /// Determines "Better function" between candidate
3429 /// and the current best match
3432 /// Returns a boolean indicating :
3433 /// false if candidate ain't better
3434 /// true if candidate is better than the current best match
3436 static bool BetterFunction (EmitContext ec, ArrayList args, int argument_count,
3437 MethodBase candidate, bool candidate_params,
3438 MethodBase best, bool best_params)
3440 AParametersCollection candidate_pd = TypeManager.GetParameterData (candidate);
3441 AParametersCollection best_pd = TypeManager.GetParameterData (best);
3443 bool better_at_least_one = false;
3445 for (int j = 0, c_idx = 0, b_idx = 0; j < argument_count; ++j, ++c_idx, ++b_idx)
3447 Argument a = (Argument) args [j];
3449 Type ct = candidate_pd.Types [c_idx];
3450 Type bt = best_pd.Types [b_idx];
3452 if (candidate_params && candidate_pd.FixedParameters [c_idx].ModFlags == Parameter.Modifier.PARAMS)
3454 ct = TypeManager.GetElementType (ct);
3458 if (best_params && best_pd.FixedParameters [b_idx].ModFlags == Parameter.Modifier.PARAMS)
3460 bt = TypeManager.GetElementType (bt);
3468 int result = BetterExpressionConversion (ec, a, ct, bt);
3470 // for each argument, the conversion to 'ct' should be no worse than
3471 // the conversion to 'bt'.
3475 // for at least one argument, the conversion to 'ct' should be better than
3476 // the conversion to 'bt'.
3478 better_at_least_one = true;
3481 if (better_at_least_one)
3485 // This handles the case
3487 // Add (float f1, float f2, float f3);
3488 // Add (params decimal [] foo);
3490 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3491 // first candidate would've chosen as better.
3497 // The two methods have equal parameter types. Now apply tie-breaking rules
3499 if (TypeManager.IsGenericMethod (best)) {
3500 if (!TypeManager.IsGenericMethod (candidate))
3502 } else if (TypeManager.IsGenericMethod (candidate)) {
3507 // This handles the following cases:
3509 // Trim () is better than Trim (params char[] chars)
3510 // Concat (string s1, string s2, string s3) is better than
3511 // Concat (string s1, params string [] srest)
3512 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3514 if (!candidate_params && best_params)
3516 if (candidate_params && !best_params)
3519 int candidate_param_count = candidate_pd.Count;
3520 int best_param_count = best_pd.Count;
3522 if (candidate_param_count != best_param_count)
3523 // can only happen if (candidate_params && best_params)
3524 return candidate_param_count > best_param_count;
3527 // now, both methods have the same number of parameters, and the parameters have the same types
3528 // Pick the "more specific" signature
3531 MethodBase orig_candidate = TypeManager.DropGenericMethodArguments (candidate);
3532 MethodBase orig_best = TypeManager.DropGenericMethodArguments (best);
3534 AParametersCollection orig_candidate_pd = TypeManager.GetParameterData (orig_candidate);
3535 AParametersCollection orig_best_pd = TypeManager.GetParameterData (orig_best);
3537 bool specific_at_least_once = false;
3538 for (int j = 0; j < candidate_param_count; ++j)
3540 Type ct = orig_candidate_pd.Types [j];
3541 Type bt = orig_best_pd.Types [j];
3544 Type specific = MoreSpecific (ct, bt);
3548 specific_at_least_once = true;
3551 if (specific_at_least_once)
3554 // FIXME: handle lifted operators
3560 protected override MemberExpr ResolveExtensionMemberAccess (Expression left)
3563 return base.ResolveExtensionMemberAccess (left);
3566 // When left side is an expression and at least one candidate method is
3567 // static, it can be extension method
3569 InstanceExpression = left;
3573 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3574 SimpleName original)
3576 if (!(left is TypeExpr) &&
3577 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3578 identical_type_name = true;
3580 return base.ResolveMemberAccess (ec, left, loc, original);
3583 public override Expression CreateExpressionTree (EmitContext ec)
3585 if (best_candidate == null) {
3586 Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3590 if (best_candidate.IsConstructor)
3591 return new TypeOfConstructorInfo (best_candidate, loc);
3593 IMethodData md = TypeManager.GetMethod (best_candidate);
3594 if (md != null && md.IsExcluded ())
3595 Report.Error (765, loc,
3596 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3598 return new TypeOfMethodInfo (best_candidate, loc);
3601 override public Expression DoResolve (EmitContext ec)
3603 if (InstanceExpression != null) {
3604 InstanceExpression = InstanceExpression.DoResolve (ec);
3605 if (InstanceExpression == null)
3612 public void ReportUsageError ()
3614 Report.Error (654, loc, "Method `" + DeclaringType + "." +
3615 Name + "()' is referenced without parentheses");
3618 override public void Emit (EmitContext ec)
3620 ReportUsageError ();
3623 public virtual void EmitArguments (EmitContext ec, ArrayList arguments)
3625 Invocation.EmitArguments (ec, arguments, false, null);
3628 public virtual void EmitCall (EmitContext ec, ArrayList arguments)
3630 Invocation.EmitCall (ec, IsBase, InstanceExpression, best_candidate, arguments, loc);
3633 void Error_AmbiguousCall (MethodBase ambiguous)
3635 if (CustomErrorHandler != null && CustomErrorHandler.AmbiguousCall (ambiguous))
3638 Report.SymbolRelatedToPreviousError (best_candidate);
3639 Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
3640 TypeManager.CSharpSignature (ambiguous), TypeManager.CSharpSignature (best_candidate));
3643 protected virtual void Error_InvalidArguments (EmitContext ec, Location loc, int idx, MethodBase method,
3644 Argument a, AParametersCollection expected_par, Type paramType)
3646 ExtensionMethodGroupExpr emg = this as ExtensionMethodGroupExpr;
3648 if (a is CollectionElementInitializer.ElementInitializerArgument) {
3649 Report.SymbolRelatedToPreviousError (method);
3650 if ((expected_par.FixedParameters [idx].ModFlags & Parameter.Modifier.ISBYREF) != 0) {
3651 Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
3652 TypeManager.CSharpSignature (method));
3655 Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
3656 TypeManager.CSharpSignature (method));
3657 } else if (TypeManager.IsDelegateType (method.DeclaringType)) {
3658 Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
3659 TypeManager.CSharpName (method.DeclaringType));
3661 Report.SymbolRelatedToPreviousError (method);
3663 Report.Error (1928, loc,
3664 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3665 emg.ExtensionExpression.GetSignatureForError (),
3666 emg.Name, TypeManager.CSharpSignature (method));
3668 Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
3669 TypeManager.CSharpSignature (method));
3673 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters [idx].ModFlags;
3675 string index = (idx + 1).ToString ();
3676 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
3677 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
3678 if ((mod & Parameter.Modifier.ISBYREF) == 0)
3679 Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
3680 index, Parameter.GetModifierSignature (a.Modifier));
3682 Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
3683 index, Parameter.GetModifierSignature (mod));
3685 string p1 = a.GetSignatureForError ();
3686 string p2 = TypeManager.CSharpName (paramType);
3689 Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
3690 Report.SymbolRelatedToPreviousError (a.Expr.Type);
3691 Report.SymbolRelatedToPreviousError (paramType);
3694 if (idx == 0 && emg != null) {
3695 Report.Error (1929, loc,
3696 "Extension method instance type `{0}' cannot be converted to `{1}'", p1, p2);
3698 Report.Error (1503, loc,
3699 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
3704 public override void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl)
3706 Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3707 Name, TypeManager.CSharpName (target));
3710 void Error_ArgumentCountWrong (int arg_count)
3712 Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
3713 Name, arg_count.ToString ());
3716 protected virtual int GetApplicableParametersCount (MethodBase method, AParametersCollection parameters)
3718 return parameters.Count;
3721 public static bool IsAncestralType (Type first_type, Type second_type)
3723 return first_type != second_type &&
3724 (TypeManager.IsSubclassOf (second_type, first_type) ||
3725 TypeManager.ImplementsInterface (second_type, first_type));
3729 /// Determines if the candidate method is applicable (section 14.4.2.1)
3730 /// to the given set of arguments
3731 /// A return value rates candidate method compatibility,
3732 /// 0 = the best, int.MaxValue = the worst
3734 public int IsApplicable (EmitContext ec,
3735 ArrayList arguments, int arg_count, ref MethodBase method, ref bool params_expanded_form)
3737 MethodBase candidate = method;
3739 AParametersCollection pd = TypeManager.GetParameterData (candidate);
3740 int param_count = GetApplicableParametersCount (candidate, pd);
3742 if (arg_count != param_count) {
3744 return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
3745 if (arg_count < param_count - 1)
3746 return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
3748 // Initialize expanded form of a method with 1 params parameter
3749 params_expanded_form = param_count == 1 && pd.HasParams;
3754 // 1. Handle generic method using type arguments when specified or type inference
3756 if (TypeManager.IsGenericMethod (candidate)) {
3757 if (type_arguments != null) {
3758 Type [] g_args = candidate.GetGenericArguments ();
3759 if (g_args.Length != type_arguments.Count)
3760 return int.MaxValue - 20000 + Math.Abs (type_arguments.Count - g_args.Length);
3762 // TODO: Don't create new method, create Parameters only
3763 method = ((MethodInfo) candidate).MakeGenericMethod (type_arguments.Arguments);
3765 pd = TypeManager.GetParameterData (candidate);
3767 int score = TypeManager.InferTypeArguments (ec, arguments, ref candidate);
3769 return score - 20000;
3771 if (TypeManager.IsGenericMethodDefinition (candidate))
3772 throw new InternalErrorException ("A generic method `{0}' definition took part in overload resolution",
3773 TypeManager.CSharpSignature (candidate));
3775 pd = TypeManager.GetParameterData (candidate);
3778 if (type_arguments != null)
3779 return int.MaxValue - 15000;
3784 // 2. Each argument has to be implicitly convertible to method parameter
3787 Parameter.Modifier p_mod = 0;
3789 for (int i = 0; i < arg_count; i++) {
3790 Argument a = (Argument) arguments [i];
3791 Parameter.Modifier a_mod = a.Modifier &
3792 ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3794 if (p_mod != Parameter.Modifier.PARAMS) {
3795 p_mod = pd.FixedParameters [i].ModFlags & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3797 if (p_mod == Parameter.Modifier.ARGLIST) {
3798 if (a.Type == TypeManager.runtime_argument_handle_type)
3806 params_expanded_form = true;
3810 if (!params_expanded_form)
3811 score = IsArgumentCompatible (ec, a_mod, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
3813 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && delegate_type == null) {
3814 // It can be applicable in expanded form
3815 score = IsArgumentCompatible (ec, a_mod, a, 0, TypeManager.GetElementType (pt));
3817 params_expanded_form = true;
3821 if (params_expanded_form)
3823 return (arg_count - i) * 2 + score;
3827 if (arg_count != param_count)
3828 params_expanded_form = true;
3833 int IsArgumentCompatible (EmitContext ec, Parameter.Modifier arg_mod, Argument argument, Parameter.Modifier param_mod, Type parameter)
3836 // Types have to be identical when ref or out modifer is used
3838 if (arg_mod != 0 || param_mod != 0) {
3839 if (TypeManager.HasElementType (parameter))
3840 parameter = TypeManager.GetElementType (parameter);
3842 Type a_type = argument.Type;
3843 if (TypeManager.HasElementType (a_type))
3844 a_type = TypeManager.GetElementType (a_type);
3846 if (a_type != parameter)
3849 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter))
3853 if (arg_mod != param_mod)
3859 public static bool IsOverride (MethodBase cand_method, MethodBase base_method)
3861 if (!IsAncestralType (base_method.DeclaringType, cand_method.DeclaringType))
3864 AParametersCollection cand_pd = TypeManager.GetParameterData (cand_method);
3865 AParametersCollection base_pd = TypeManager.GetParameterData (base_method);
3867 if (cand_pd.Count != base_pd.Count)
3870 for (int j = 0; j < cand_pd.Count; ++j)
3872 Parameter.Modifier cm = cand_pd.FixedParameters [j].ModFlags;
3873 Parameter.Modifier bm = base_pd.FixedParameters [j].ModFlags;
3874 Type ct = cand_pd.Types [j];
3875 Type bt = base_pd.Types [j];
3877 if (cm != bm || ct != bt)
3884 public static MethodGroupExpr MakeUnionSet (MethodGroupExpr mg1, MethodGroupExpr mg2, Location loc)
3895 ArrayList all = new ArrayList (mg1.Methods);
3896 foreach (MethodBase m in mg2.Methods){
3897 if (!TypeManager.ArrayContainsMethod (mg1.Methods, m, false))
3901 return new MethodGroupExpr (all, null, loc);
3904 static Type MoreSpecific (Type p, Type q)
3906 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
3908 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
3911 if (TypeManager.HasElementType (p))
3913 Type pe = TypeManager.GetElementType (p);
3914 Type qe = TypeManager.GetElementType (q);
3915 Type specific = MoreSpecific (pe, qe);
3921 else if (TypeManager.IsGenericType (p))
3923 Type[] pargs = TypeManager.GetTypeArguments (p);
3924 Type[] qargs = TypeManager.GetTypeArguments (q);
3926 bool p_specific_at_least_once = false;
3927 bool q_specific_at_least_once = false;
3929 for (int i = 0; i < pargs.Length; i++)
3931 Type specific = MoreSpecific (pargs [i], qargs [i]);
3932 if (specific == pargs [i])
3933 p_specific_at_least_once = true;
3934 if (specific == qargs [i])
3935 q_specific_at_least_once = true;
3938 if (p_specific_at_least_once && !q_specific_at_least_once)
3940 if (!p_specific_at_least_once && q_specific_at_least_once)
3947 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3949 base.MutateHoistedGenericType (storey);
3951 MethodInfo mi = best_candidate as MethodInfo;
3953 best_candidate = storey.MutateGenericMethod (mi);
3957 best_candidate = storey.MutateConstructor ((ConstructorInfo) this);
3961 /// Find the Applicable Function Members (7.4.2.1)
3963 /// me: Method Group expression with the members to select.
3964 /// it might contain constructors or methods (or anything
3965 /// that maps to a method).
3967 /// Arguments: ArrayList containing resolved Argument objects.
3969 /// loc: The location if we want an error to be reported, or a Null
3970 /// location for "probing" purposes.
3972 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3973 /// that is the best match of me on Arguments.
3976 public virtual MethodGroupExpr OverloadResolve (EmitContext ec, ref ArrayList Arguments,
3977 bool may_fail, Location loc)
3979 bool method_params = false;
3980 Type applicable_type = null;
3982 ArrayList candidates = new ArrayList (2);
3983 ArrayList candidate_overrides = null;
3986 // Used to keep a map between the candidate
3987 // and whether it is being considered in its
3988 // normal or expanded form
3990 // false is normal form, true is expanded form
3992 Hashtable candidate_to_form = null;
3994 if (Arguments != null)
3995 arg_count = Arguments.Count;
3997 if (RootContext.Version == LanguageVersion.ISO_1 && Name == "Invoke" && TypeManager.IsDelegateType (DeclaringType)) {
3999 Report.Error (1533, loc, "Invoke cannot be called directly on a delegate");
4003 int nmethods = Methods.Length;
4007 // Methods marked 'override' don't take part in 'applicable_type'
4008 // computation, nor in the actual overload resolution.
4009 // However, they still need to be emitted instead of a base virtual method.
4010 // So, we salt them away into the 'candidate_overrides' array.
4012 // In case of reflected methods, we replace each overriding method with
4013 // its corresponding base virtual method. This is to improve compatibility
4014 // with non-C# libraries which change the visibility of overrides (#75636)
4017 for (int i = 0; i < Methods.Length; ++i) {
4018 MethodBase m = Methods [i];
4019 if (TypeManager.IsOverride (m)) {
4020 if (candidate_overrides == null)
4021 candidate_overrides = new ArrayList ();
4022 candidate_overrides.Add (m);
4023 m = TypeManager.TryGetBaseDefinition (m);
4032 // Enable message recording, it's used mainly by lambda expressions
4034 Report.IMessageRecorder msg_recorder = new Report.MessageRecorder ();
4035 Report.IMessageRecorder prev_recorder = Report.SetMessageRecorder (msg_recorder);
4038 // First we construct the set of applicable methods
4040 bool is_sorted = true;
4041 int best_candidate_rate = int.MaxValue;
4042 for (int i = 0; i < nmethods; i++) {
4043 Type decl_type = Methods [i].DeclaringType;
4046 // If we have already found an applicable method
4047 // we eliminate all base types (Section 14.5.5.1)
4049 if (applicable_type != null && IsAncestralType (decl_type, applicable_type))
4053 // Check if candidate is applicable (section 14.4.2.1)
4055 bool params_expanded_form = false;
4056 int candidate_rate = IsApplicable (ec, Arguments, arg_count, ref Methods [i], ref params_expanded_form);
4058 if (candidate_rate < best_candidate_rate) {
4059 best_candidate_rate = candidate_rate;
4060 best_candidate = Methods [i];
4063 if (params_expanded_form) {
4064 if (candidate_to_form == null)
4065 candidate_to_form = new PtrHashtable ();
4066 MethodBase candidate = Methods [i];
4067 candidate_to_form [candidate] = candidate;
4070 if (candidate_rate != 0 || has_inaccessible_candidates_only) {
4071 if (msg_recorder != null)
4072 msg_recorder.EndSession ();
4076 msg_recorder = null;
4077 candidates.Add (Methods [i]);
4079 if (applicable_type == null)
4080 applicable_type = decl_type;
4081 else if (applicable_type != decl_type) {
4083 if (IsAncestralType (applicable_type, decl_type))
4084 applicable_type = decl_type;
4088 Report.SetMessageRecorder (prev_recorder);
4089 if (msg_recorder != null && !msg_recorder.IsEmpty) {
4091 msg_recorder.PrintMessages ();
4096 int candidate_top = candidates.Count;
4098 if (applicable_type == null) {
4100 // When we found a top level method which does not match and it's
4101 // not an extension method. We start extension methods lookup from here
4103 if (InstanceExpression != null) {
4104 ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (type, Name, loc);
4105 if (ex_method_lookup != null) {
4106 ex_method_lookup.ExtensionExpression = InstanceExpression;
4107 ex_method_lookup.SetTypeArguments (type_arguments);
4108 return ex_method_lookup.OverloadResolve (ec, ref Arguments, may_fail, loc);
4116 // Okay so we have failed to find exact match so we
4117 // return error info about the closest match
4119 if (best_candidate != null) {
4120 if (CustomErrorHandler != null && CustomErrorHandler.NoExactMatch (ec, best_candidate))
4123 AParametersCollection pd = TypeManager.GetParameterData (best_candidate);
4124 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4125 if (arg_count == pd.Count || pd.HasParams) {
4126 if (TypeManager.IsGenericMethodDefinition (best_candidate)) {
4127 if (type_arguments == null) {
4128 Report.Error (411, loc,
4129 "The type arguments for method `{0}' cannot be inferred from " +
4130 "the usage. Try specifying the type arguments explicitly",
4131 TypeManager.CSharpSignature (best_candidate));
4135 Type[] g_args = TypeManager.GetGenericArguments (best_candidate);
4136 if (type_arguments.Count != g_args.Length) {
4137 Report.SymbolRelatedToPreviousError (best_candidate);
4138 Report.Error (305, loc, "Using the generic method `{0}' requires `{1}' type argument(s)",
4139 TypeManager.CSharpSignature (best_candidate),
4140 g_args.Length.ToString ());
4144 if (type_arguments != null && !TypeManager.IsGenericMethod (best_candidate)) {
4145 Namespace.Error_TypeArgumentsCannotBeUsed (best_candidate, loc);
4150 if (has_inaccessible_candidates_only) {
4151 if (InstanceExpression != null && type != ec.ContainerType && TypeManager.IsNestedFamilyAccessible (ec.ContainerType, best_candidate.DeclaringType)) {
4152 // Although a derived class can access protected members of
4153 // its base class it cannot do so through an instance of the
4154 // base class (CS1540). If the qualifier_type is a base of the
4155 // ec.ContainerType and the lookup succeeds with the latter one,
4156 // then we are in this situation.
4157 Error_CannotAccessProtected (loc, best_candidate, type, ec.ContainerType);
4159 Report.SymbolRelatedToPreviousError (best_candidate);
4160 ErrorIsInaccesible (loc, GetSignatureForError ());
4164 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate, cand_params, may_fail, loc))
4167 if (has_inaccessible_candidates_only)
4170 throw new InternalErrorException ("VerifyArgumentsCompat didn't find any problem with rejected candidate " + best_candidate);
4175 // We failed to find any method with correct argument count
4177 if (Name == ConstructorInfo.ConstructorName) {
4178 Report.SymbolRelatedToPreviousError (type);
4179 Report.Error (1729, loc,
4180 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4181 TypeManager.CSharpName (type), arg_count);
4183 Error_ArgumentCountWrong (arg_count);
4191 // At this point, applicable_type is _one_ of the most derived types
4192 // in the set of types containing the methods in this MethodGroup.
4193 // Filter the candidates so that they only contain methods from the
4194 // most derived types.
4197 int finalized = 0; // Number of finalized candidates
4200 // Invariant: applicable_type is a most derived type
4202 // We'll try to complete Section 14.5.5.1 for 'applicable_type' by
4203 // eliminating all it's base types. At the same time, we'll also move
4204 // every unrelated type to the end of the array, and pick the next
4205 // 'applicable_type'.
4207 Type next_applicable_type = null;
4208 int j = finalized; // where to put the next finalized candidate
4209 int k = finalized; // where to put the next undiscarded candidate
4210 for (int i = finalized; i < candidate_top; ++i) {
4211 MethodBase candidate = (MethodBase) candidates [i];
4212 Type decl_type = candidate.DeclaringType;
4214 if (decl_type == applicable_type) {
4215 candidates [k++] = candidates [j];
4216 candidates [j++] = candidates [i];
4220 if (IsAncestralType (decl_type, applicable_type))
4223 if (next_applicable_type != null &&
4224 IsAncestralType (decl_type, next_applicable_type))
4227 candidates [k++] = candidates [i];
4229 if (next_applicable_type == null ||
4230 IsAncestralType (next_applicable_type, decl_type))
4231 next_applicable_type = decl_type;
4234 applicable_type = next_applicable_type;
4237 } while (applicable_type != null);
4241 // Now we actually find the best method
4244 best_candidate = (MethodBase) candidates [0];
4245 method_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4247 for (int ix = 1; ix < candidate_top; ix++) {
4248 MethodBase candidate = (MethodBase) candidates [ix];
4250 if (candidate == best_candidate)
4253 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4255 if (BetterFunction (ec, Arguments, arg_count,
4256 candidate, cand_params,
4257 best_candidate, method_params)) {
4258 best_candidate = candidate;
4259 method_params = cand_params;
4263 // Now check that there are no ambiguities i.e the selected method
4264 // should be better than all the others
4266 MethodBase ambiguous = null;
4267 for (int ix = 1; ix < candidate_top; ix++) {
4268 MethodBase candidate = (MethodBase) candidates [ix];
4270 if (candidate == best_candidate)
4273 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4274 if (!BetterFunction (ec, Arguments, arg_count,
4275 best_candidate, method_params,
4276 candidate, cand_params))
4279 Report.SymbolRelatedToPreviousError (candidate);
4280 ambiguous = candidate;
4284 if (ambiguous != null) {
4285 Error_AmbiguousCall (ambiguous);
4290 // If the method is a virtual function, pick an override closer to the LHS type.
4292 if (!IsBase && best_candidate.IsVirtual) {
4293 if (TypeManager.IsOverride (best_candidate))
4294 throw new InternalErrorException (
4295 "Should not happen. An 'override' method took part in overload resolution: " + best_candidate);
4297 if (candidate_overrides != null) {
4298 Type[] gen_args = null;
4299 bool gen_override = false;
4300 if (TypeManager.IsGenericMethod (best_candidate))
4301 gen_args = TypeManager.GetGenericArguments (best_candidate);
4303 foreach (MethodBase candidate in candidate_overrides) {
4304 if (TypeManager.IsGenericMethod (candidate)) {
4305 if (gen_args == null)
4308 if (gen_args.Length != TypeManager.GetGenericArguments (candidate).Length)
4311 if (gen_args != null)
4315 if (IsOverride (candidate, best_candidate)) {
4316 gen_override = true;
4317 best_candidate = candidate;
4321 if (gen_override && gen_args != null) {
4323 best_candidate = ((MethodInfo) best_candidate).MakeGenericMethod (gen_args);
4330 // And now check if the arguments are all
4331 // compatible, perform conversions if
4332 // necessary etc. and return if everything is
4335 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate,
4336 method_params, may_fail, loc))
4339 if (best_candidate == null)
4342 MethodBase the_method = TypeManager.DropGenericMethodArguments (best_candidate);
4344 if (the_method.IsGenericMethodDefinition &&
4345 !ConstraintChecker.CheckConstraints (ec, the_method, best_candidate, loc))
4350 // Check ObsoleteAttribute on the best method
4352 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (the_method);
4353 if (oa != null && !ec.IsInObsoleteScope)
4354 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc);
4356 IMethodData data = TypeManager.GetMethod (the_method);
4358 data.SetMemberIsUsed ();
4363 public override void SetTypeArguments (TypeArguments ta)
4365 type_arguments = ta;
4368 public bool VerifyArgumentsCompat (EmitContext ec, ref ArrayList arguments,
4369 int arg_count, MethodBase method,
4370 bool chose_params_expanded,
4371 bool may_fail, Location loc)
4373 AParametersCollection pd = TypeManager.GetParameterData (method);
4375 int errors = Report.Errors;
4376 Parameter.Modifier p_mod = 0;
4378 int a_idx = 0, a_pos = 0;
4380 ArrayList params_initializers = null;
4381 bool has_unsafe_arg = false;
4383 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4384 a = (Argument) arguments [a_idx];
4385 if (p_mod != Parameter.Modifier.PARAMS) {
4386 p_mod = pd.FixedParameters [a_idx].ModFlags;
4387 pt = pd.Types [a_idx];
4388 has_unsafe_arg |= pt.IsPointer;
4390 if (p_mod == Parameter.Modifier.ARGLIST) {
4391 if (a.Type != TypeManager.runtime_argument_handle_type)
4396 if (p_mod == Parameter.Modifier.PARAMS) {
4397 if (chose_params_expanded) {
4398 params_initializers = new ArrayList (arg_count - a_idx);
4399 pt = TypeManager.GetElementType (pt);
4405 // Types have to be identical when ref or out modifer is used
4407 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4408 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4411 if (!TypeManager.IsEqual (a.Expr.Type, pt))
4417 if (delegate_type != null && !Delegate.IsTypeCovariant (a.Expr, pt))
4420 Expression conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4425 // Convert params arguments to an array initializer
4427 if (params_initializers != null) {
4428 // we choose to use 'a.Expr' rather than 'conv' so that
4429 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
4430 params_initializers.Add (a.Expr);
4431 arguments.RemoveAt (a_idx--);
4436 // Update the argument with the implicit conversion
4440 if (a_idx != arg_count) {
4441 if (!may_fail && Report.Errors == errors) {
4442 if (CustomErrorHandler != null)
4443 CustomErrorHandler.NoExactMatch (ec, best_candidate);
4445 Error_InvalidArguments (ec, loc, a_pos, method, a, pd, pt);
4451 // Fill not provided arguments required by params modifier
4453 int param_count = GetApplicableParametersCount (method, pd);
4454 if (params_initializers == null && pd.HasParams && arg_count + 1 == param_count) {
4455 if (arguments == null)
4456 arguments = new ArrayList (1);
4458 pt = pd.Types [param_count - 1];
4459 pt = TypeManager.GetElementType (pt);
4460 has_unsafe_arg |= pt.IsPointer;
4461 params_initializers = new ArrayList (0);
4465 // Append an array argument with all params arguments
4467 if (params_initializers != null) {
4468 arguments.Add (new Argument (
4469 new ArrayCreation (new TypeExpression (pt, loc), "[]",
4470 params_initializers, loc).Resolve (ec)));
4474 if (arg_count < param_count) {
4476 Error_ArgumentCountWrong (arg_count);
4480 if (has_unsafe_arg && !ec.InUnsafe) {
4490 public class ConstantExpr : MemberExpr
4494 public ConstantExpr (FieldInfo constant, Location loc)
4496 this.constant = constant;
4500 public override string Name {
4501 get { throw new NotImplementedException (); }
4504 public override bool IsInstance {
4505 get { return !IsStatic; }
4508 public override bool IsStatic {
4509 get { return constant.IsStatic; }
4512 public override Type DeclaringType {
4513 get { return constant.DeclaringType; }
4516 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc, SimpleName original)
4518 constant = TypeManager.GetGenericFieldDefinition (constant);
4520 IConstant ic = TypeManager.GetConstant (constant);
4522 if (constant.IsLiteral) {
4523 ic = new ExternalConstant (constant);
4525 ic = ExternalConstant.CreateDecimal (constant);
4526 // HACK: decimal field was not resolved as constant
4528 return new FieldExpr (constant, loc).ResolveMemberAccess (ec, left, loc, original);
4530 TypeManager.RegisterConstant (constant, ic);
4533 return base.ResolveMemberAccess (ec, left, loc, original);
4536 public override Expression CreateExpressionTree (EmitContext ec)
4538 throw new NotSupportedException ("ET");
4541 public override Expression DoResolve (EmitContext ec)
4543 IConstant ic = TypeManager.GetConstant (constant);
4544 if (ic.ResolveValue ()) {
4545 if (!ec.IsInObsoleteScope)
4546 ic.CheckObsoleteness (loc);
4549 return ic.CreateConstantReference (loc);
4552 public override void Emit (EmitContext ec)
4554 throw new NotSupportedException ();
4557 public override string GetSignatureForError ()
4559 return TypeManager.GetFullNameSignature (constant);
4564 /// Fully resolved expression that evaluates to a Field
4566 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariableReference {
4567 public FieldInfo FieldInfo;
4568 readonly Type constructed_generic_type;
4569 VariableInfo variable_info;
4571 LocalTemporary temp;
4574 protected FieldExpr (Location l)
4579 public FieldExpr (FieldInfo fi, Location l)
4582 type = TypeManager.TypeToCoreType (fi.FieldType);
4586 public FieldExpr (FieldInfo fi, Type genericType, Location l)
4589 if (TypeManager.IsGenericTypeDefinition (genericType))
4591 this.constructed_generic_type = genericType;
4594 public override string Name {
4596 return FieldInfo.Name;
4600 public override bool IsInstance {
4602 return !FieldInfo.IsStatic;
4606 public override bool IsStatic {
4608 return FieldInfo.IsStatic;
4612 public override Type DeclaringType {
4614 return FieldInfo.DeclaringType;
4618 public override string GetSignatureForError ()
4620 return TypeManager.GetFullNameSignature (FieldInfo);
4623 public VariableInfo VariableInfo {
4625 return variable_info;
4629 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
4630 SimpleName original)
4632 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
4633 Type t = fi.FieldType;
4635 if (t.IsPointer && !ec.InUnsafe) {
4639 return base.ResolveMemberAccess (ec, left, loc, original);
4642 public void SetHasAddressTaken ()
4644 IVariableReference vr = InstanceExpression as IVariableReference;
4646 vr.SetHasAddressTaken ();
4649 public override Expression CreateExpressionTree (EmitContext ec)
4651 Expression instance;
4652 if (InstanceExpression == null) {
4653 instance = new NullLiteral (loc);
4655 instance = InstanceExpression.CreateExpressionTree (ec);
4658 ArrayList args = new ArrayList (2);
4659 args.Add (new Argument (instance));
4660 args.Add (new Argument (CreateTypeOfExpression ()));
4661 return CreateExpressionFactoryCall ("Field", args);
4664 public Expression CreateTypeOfExpression ()
4666 return new TypeOfField (GetConstructedFieldInfo (), loc);
4669 override public Expression DoResolve (EmitContext ec)
4671 return DoResolve (ec, false, false);
4674 Expression DoResolve (EmitContext ec, bool lvalue_instance, bool out_access)
4676 if (!FieldInfo.IsStatic){
4677 if (InstanceExpression == null){
4679 // This can happen when referencing an instance field using
4680 // a fully qualified type expression: TypeName.InstanceField = xxx
4682 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4686 // Resolve the field's instance expression while flow analysis is turned
4687 // off: when accessing a field "a.b", we must check whether the field
4688 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4690 if (lvalue_instance) {
4691 using (ec.With (EmitContext.Flags.DoFlowAnalysis, false)) {
4692 Expression right_side =
4693 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4694 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side, loc);
4697 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
4698 InstanceExpression = InstanceExpression.Resolve (ec, rf);
4701 if (InstanceExpression == null)
4704 using (ec.Set (EmitContext.Flags.OmitStructFlowAnalysis)) {
4705 InstanceExpression.CheckMarshalByRefAccess (ec);
4709 // TODO: the code above uses some non-standard multi-resolve rules
4710 if (eclass != ExprClass.Invalid)
4713 if (!ec.IsInObsoleteScope) {
4714 FieldBase f = TypeManager.GetField (FieldInfo);
4716 f.CheckObsoleteness (loc);
4718 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
4720 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
4724 IFixedBuffer fb = AttributeTester.GetFixedBuffer (FieldInfo);
4725 IVariableReference var = InstanceExpression as IVariableReference;
4728 IFixedExpression fe = InstanceExpression as IFixedExpression;
4729 if (!ec.InFixedInitializer && (fe == null || !fe.IsFixed)) {
4730 Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4733 if (InstanceExpression.eclass != ExprClass.Variable) {
4734 Report.SymbolRelatedToPreviousError (FieldInfo);
4735 Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4736 TypeManager.GetFullNameSignature (FieldInfo));
4737 } else if (var != null && var.IsHoisted) {
4738 AnonymousMethodExpression.Error_AddressOfCapturedVar (var, loc);
4741 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4744 eclass = ExprClass.Variable;
4746 // If the instance expression is a local variable or parameter.
4747 if (var == null || var.VariableInfo == null)
4750 VariableInfo vi = var.VariableInfo;
4751 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
4754 variable_info = vi.GetSubStruct (FieldInfo.Name);
4755 eclass = ExprClass.Variable;
4759 static readonly int [] codes = {
4760 191, // instance, write access
4761 192, // instance, out access
4762 198, // static, write access
4763 199, // static, out access
4764 1648, // member of value instance, write access
4765 1649, // member of value instance, out access
4766 1650, // member of value static, write access
4767 1651 // member of value static, out access
4770 static readonly string [] msgs = {
4771 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4772 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4773 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4774 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4775 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4776 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4777 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4778 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4781 // The return value is always null. Returning a value simplifies calling code.
4782 Expression Report_AssignToReadonly (Expression right_side)
4785 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4789 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4791 Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4796 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4798 IVariableReference var = InstanceExpression as IVariableReference;
4799 if (var != null && var.VariableInfo != null)
4800 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
4802 bool lvalue_instance = !FieldInfo.IsStatic && TypeManager.IsValueType (FieldInfo.DeclaringType);
4803 bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
4805 Expression e = DoResolve (ec, lvalue_instance, out_access);
4810 FieldBase fb = TypeManager.GetField (FieldInfo);
4814 if (FieldInfo.IsInitOnly) {
4815 // InitOnly fields can only be assigned in constructors or initializers
4816 if (!ec.IsInFieldInitializer && !ec.IsConstructor)
4817 return Report_AssignToReadonly (right_side);
4819 if (ec.IsConstructor) {
4820 Type ctype = ec.TypeContainer.CurrentType;
4822 ctype = ec.ContainerType;
4824 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4825 if (!TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
4826 return Report_AssignToReadonly (right_side);
4827 // static InitOnly fields cannot be assigned-to in an instance constructor
4828 if (IsStatic && !ec.IsStatic)
4829 return Report_AssignToReadonly (right_side);
4830 // instance constructors can't modify InitOnly fields of other instances of the same type
4831 if (!IsStatic && !(InstanceExpression is This))
4832 return Report_AssignToReadonly (right_side);
4836 if (right_side == EmptyExpression.OutAccess &&
4837 !IsStatic && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type)) {
4838 Report.SymbolRelatedToPreviousError (DeclaringType);
4839 Report.Warning (197, 1, loc,
4840 "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",
4841 GetSignatureForError ());
4844 eclass = ExprClass.Variable;
4848 bool is_marshal_by_ref ()
4850 return !IsStatic && TypeManager.IsStruct (Type) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type);
4853 public override void CheckMarshalByRefAccess (EmitContext ec)
4855 if (is_marshal_by_ref () && !(InstanceExpression is This)) {
4856 Report.SymbolRelatedToPreviousError (DeclaringType);
4857 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",
4858 GetSignatureForError ());
4862 public override int GetHashCode ()
4864 return FieldInfo.GetHashCode ();
4867 public bool IsFixed {
4870 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
4872 IVariableReference variable = InstanceExpression as IVariableReference;
4873 if (variable != null)
4874 return TypeManager.IsStruct (InstanceExpression.Type) && variable.IsFixed;
4876 IFixedExpression fe = InstanceExpression as IFixedExpression;
4877 return fe != null && fe.IsFixed;
4881 public bool IsHoisted {
4883 IVariableReference hv = InstanceExpression as IVariableReference;
4884 return hv != null && hv.IsHoisted;
4888 public override bool Equals (object obj)
4890 FieldExpr fe = obj as FieldExpr;
4894 if (FieldInfo != fe.FieldInfo)
4897 if (InstanceExpression == null || fe.InstanceExpression == null)
4900 return InstanceExpression.Equals (fe.InstanceExpression);
4903 public void Emit (EmitContext ec, bool leave_copy)
4905 ILGenerator ig = ec.ig;
4906 bool is_volatile = false;
4908 FieldBase f = TypeManager.GetField (FieldInfo);
4910 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4913 f.SetMemberIsUsed ();
4916 if (FieldInfo.IsStatic){
4918 ig.Emit (OpCodes.Volatile);
4920 ig.Emit (OpCodes.Ldsfld, GetConstructedFieldInfo ());
4923 EmitInstance (ec, false);
4925 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
4927 ig.Emit (OpCodes.Ldflda, GetConstructedFieldInfo ());
4928 ig.Emit (OpCodes.Ldflda, ff.Element);
4931 ig.Emit (OpCodes.Volatile);
4933 ig.Emit (OpCodes.Ldfld, GetConstructedFieldInfo ());
4938 ec.ig.Emit (OpCodes.Dup);
4939 if (!FieldInfo.IsStatic) {
4940 temp = new LocalTemporary (this.Type);
4946 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4948 FieldAttributes fa = FieldInfo.Attributes;
4949 bool is_static = (fa & FieldAttributes.Static) != 0;
4950 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
4951 ILGenerator ig = ec.ig;
4953 if (is_readonly && !ec.IsConstructor){
4954 Report_AssignToReadonly (source);
4958 prepared = prepare_for_load;
4959 EmitInstance (ec, prepared);
4963 ec.ig.Emit (OpCodes.Dup);
4964 if (!FieldInfo.IsStatic) {
4965 temp = new LocalTemporary (this.Type);
4970 FieldBase f = TypeManager.GetField (FieldInfo);
4972 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4973 ig.Emit (OpCodes.Volatile);
4979 ig.Emit (OpCodes.Stsfld, GetConstructedFieldInfo ());
4981 ig.Emit (OpCodes.Stfld, GetConstructedFieldInfo ());
4990 public override void Emit (EmitContext ec)
4995 public override void EmitSideEffect (EmitContext ec)
4997 FieldBase f = TypeManager.GetField (FieldInfo);
4998 bool is_volatile = f != null && (f.ModFlags & Modifiers.VOLATILE) != 0;
5000 if (is_volatile || is_marshal_by_ref ())
5001 base.EmitSideEffect (ec);
5004 public override void Error_VariableIsUsedBeforeItIsDeclared (string name)
5006 Report.Error (844, loc,
5007 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the field `{1}'",
5008 name, GetSignatureForError ());
5011 public void AddressOf (EmitContext ec, AddressOp mode)
5013 ILGenerator ig = ec.ig;
5015 FieldBase f = TypeManager.GetField (FieldInfo);
5017 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
5018 Report.Warning (420, 1, loc, "`{0}': A volatile field references will not be treated as volatile",
5019 f.GetSignatureForError ());
5022 if ((mode & AddressOp.Store) != 0)
5024 if ((mode & AddressOp.Load) != 0)
5025 f.SetMemberIsUsed ();
5029 // Handle initonly fields specially: make a copy and then
5030 // get the address of the copy.
5033 if (FieldInfo.IsInitOnly){
5035 if (ec.IsConstructor){
5036 if (FieldInfo.IsStatic){
5048 local = ig.DeclareLocal (type);
5049 ig.Emit (OpCodes.Stloc, local);
5050 ig.Emit (OpCodes.Ldloca, local);
5055 if (FieldInfo.IsStatic){
5056 ig.Emit (OpCodes.Ldsflda, GetConstructedFieldInfo ());
5059 EmitInstance (ec, false);
5060 ig.Emit (OpCodes.Ldflda, GetConstructedFieldInfo ());
5064 FieldInfo GetConstructedFieldInfo ()
5066 if (constructed_generic_type == null)
5069 return TypeBuilder.GetField (constructed_generic_type, FieldInfo);
5071 throw new NotSupportedException ();
5075 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5077 FieldInfo = storey.MutateField (FieldInfo);
5078 base.MutateHoistedGenericType (storey);
5084 /// Expression that evaluates to a Property. The Assign class
5085 /// might set the `Value' expression if we are in an assignment.
5087 /// This is not an LValue because we need to re-write the expression, we
5088 /// can not take data from the stack and store it.
5090 public class PropertyExpr : MemberExpr, IAssignMethod {
5091 public readonly PropertyInfo PropertyInfo;
5092 MethodInfo getter, setter;
5097 LocalTemporary temp;
5100 public PropertyExpr (Type container_type, PropertyInfo pi, Location l)
5103 eclass = ExprClass.PropertyAccess;
5107 type = TypeManager.TypeToCoreType (pi.PropertyType);
5109 ResolveAccessors (container_type);
5112 public override string Name {
5114 return PropertyInfo.Name;
5118 public override bool IsInstance {
5124 public override bool IsStatic {
5130 public override Expression CreateExpressionTree (EmitContext ec)
5133 if (IsSingleDimensionalArrayLength ()) {
5134 args = new ArrayList (1);
5135 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5136 return CreateExpressionFactoryCall ("ArrayLength", args);
5140 Error_BaseAccessInExpressionTree (loc);
5144 args = new ArrayList (2);
5145 if (InstanceExpression == null)
5146 args.Add (new Argument (new NullLiteral (loc)));
5148 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5149 args.Add (new Argument (new TypeOfMethodInfo (getter, loc)));
5150 return CreateExpressionFactoryCall ("Property", args);
5153 public Expression CreateSetterTypeOfExpression ()
5155 return new TypeOfMethodInfo (setter, loc);
5158 public override Type DeclaringType {
5160 return PropertyInfo.DeclaringType;
5164 public override string GetSignatureForError ()
5166 return TypeManager.GetFullNameSignature (PropertyInfo);
5169 void FindAccessors (Type invocation_type)
5171 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
5172 BindingFlags.Static | BindingFlags.Instance |
5173 BindingFlags.DeclaredOnly;
5175 Type current = PropertyInfo.DeclaringType;
5176 for (; current != null; current = current.BaseType) {
5177 MemberInfo[] group = TypeManager.MemberLookup (
5178 invocation_type, invocation_type, current,
5179 MemberTypes.Property, flags, PropertyInfo.Name, null);
5184 if (group.Length != 1)
5185 // Oooops, can this ever happen ?
5188 PropertyInfo pi = (PropertyInfo) group [0];
5191 getter = pi.GetGetMethod (true);
5194 setter = pi.GetSetMethod (true);
5196 MethodInfo accessor = getter != null ? getter : setter;
5198 if (!accessor.IsVirtual)
5204 // We also perform the permission checking here, as the PropertyInfo does not
5205 // hold the information for the accessibility of its setter/getter
5207 // TODO: Refactor to use some kind of cache together with GetPropertyFromAccessor
5208 void ResolveAccessors (Type container_type)
5210 FindAccessors (container_type);
5212 if (getter != null) {
5213 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
5214 IMethodData md = TypeManager.GetMethod (the_getter);
5216 md.SetMemberIsUsed ();
5218 is_static = getter.IsStatic;
5221 if (setter != null) {
5222 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
5223 IMethodData md = TypeManager.GetMethod (the_setter);
5225 md.SetMemberIsUsed ();
5227 is_static = setter.IsStatic;
5231 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5233 if (InstanceExpression != null)
5234 InstanceExpression.MutateHoistedGenericType (storey);
5236 type = storey.MutateType (type);
5238 getter = storey.MutateGenericMethod (getter);
5240 setter = storey.MutateGenericMethod (setter);
5243 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
5246 InstanceExpression = null;
5250 if (InstanceExpression == null) {
5251 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5255 InstanceExpression = InstanceExpression.DoResolve (ec);
5256 if (lvalue_instance && InstanceExpression != null)
5257 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
5259 if (InstanceExpression == null)
5262 InstanceExpression.CheckMarshalByRefAccess (ec);
5264 if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) &&
5265 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
5266 !TypeManager.IsNestedChildOf (ec.ContainerType, InstanceExpression.Type) &&
5267 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.ContainerType)) {
5268 Report.SymbolRelatedToPreviousError (PropertyInfo);
5269 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
5276 void Error_PropertyNotFound (MethodInfo mi, bool getter)
5278 // TODO: correctly we should compare arguments but it will lead to bigger changes
5279 if (mi is MethodBuilder) {
5280 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
5284 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
5286 AParametersCollection iparams = TypeManager.GetParameterData (mi);
5287 sig.Append (getter ? "get_" : "set_");
5289 sig.Append (iparams.GetSignatureForError ());
5291 Report.SymbolRelatedToPreviousError (mi);
5292 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
5293 Name, sig.ToString ());
5296 public bool IsAccessibleFrom (Type invocation_type, bool lvalue)
5299 MethodInfo accessor = lvalue ? setter : getter;
5300 if (accessor == null && lvalue)
5302 return accessor != null && IsAccessorAccessible (invocation_type, accessor, out dummy);
5305 bool IsSingleDimensionalArrayLength ()
5307 if (DeclaringType != TypeManager.array_type || getter == null || Name != "Length")
5310 string t_name = InstanceExpression.Type.Name;
5311 int t_name_len = t_name.Length;
5312 return t_name_len > 2 && t_name [t_name_len - 2] == '[';
5315 override public Expression DoResolve (EmitContext ec)
5320 if (getter != null){
5321 if (TypeManager.GetParameterData (getter).Count != 0){
5322 Error_PropertyNotFound (getter, true);
5327 if (getter == null){
5329 // The following condition happens if the PropertyExpr was
5330 // created, but is invalid (ie, the property is inaccessible),
5331 // and we did not want to embed the knowledge about this in
5332 // the caller routine. This only avoids double error reporting.
5337 if (InstanceExpression != EmptyExpression.Null) {
5338 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5339 TypeManager.GetFullNameSignature (PropertyInfo));
5344 bool must_do_cs1540_check = false;
5345 if (getter != null &&
5346 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
5347 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
5348 if (pm != null && pm.HasCustomAccessModifier) {
5349 Report.SymbolRelatedToPreviousError (pm);
5350 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5351 TypeManager.CSharpSignature (getter));
5354 Report.SymbolRelatedToPreviousError (getter);
5355 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
5360 if (!InstanceResolve (ec, false, must_do_cs1540_check))
5364 // Only base will allow this invocation to happen.
5366 if (IsBase && getter.IsAbstract) {
5367 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5370 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
5374 if (!ec.IsInObsoleteScope) {
5375 PropertyBase pb = TypeManager.GetProperty (PropertyInfo);
5377 pb.CheckObsoleteness (loc);
5379 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (PropertyInfo);
5381 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc);
5390 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
5392 if (right_side == EmptyExpression.OutAccess) {
5393 if (ec.CurrentBlock.Toplevel.GetParameterReference (PropertyInfo.Name, loc) is MemberAccess) {
5394 Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5397 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as `ref' or `out' parameter",
5398 GetSignatureForError ());
5403 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5404 Error_CannotModifyIntermediateExpressionValue (ec);
5407 if (setter == null){
5409 // The following condition happens if the PropertyExpr was
5410 // created, but is invalid (ie, the property is inaccessible),
5411 // and we did not want to embed the knowledge about this in
5412 // the caller routine. This only avoids double error reporting.
5417 if (ec.CurrentBlock.Toplevel.GetParameterReference (PropertyInfo.Name, loc) is MemberAccess) {
5418 Report.Error (1947, loc, "A range variable `{0}' cannot be assigned to. Consider using `let' clause to store the value",
5421 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
5422 GetSignatureForError ());
5427 if (TypeManager.GetParameterData (setter).Count != 1){
5428 Error_PropertyNotFound (setter, false);
5432 bool must_do_cs1540_check;
5433 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
5434 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
5435 if (pm != null && pm.HasCustomAccessModifier) {
5436 Report.SymbolRelatedToPreviousError (pm);
5437 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5438 TypeManager.CSharpSignature (setter));
5441 Report.SymbolRelatedToPreviousError (setter);
5442 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
5447 if (!InstanceResolve (ec, TypeManager.IsStruct (PropertyInfo.DeclaringType), must_do_cs1540_check))
5451 // Only base will allow this invocation to happen.
5453 if (IsBase && setter.IsAbstract){
5454 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5457 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe) {
5461 if (!ec.IsInObsoleteScope) {
5462 PropertyBase pb = TypeManager.GetProperty (PropertyInfo);
5464 pb.CheckObsoleteness (loc);
5466 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (PropertyInfo);
5468 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc);
5475 public override void Emit (EmitContext ec)
5480 public void Emit (EmitContext ec, bool leave_copy)
5483 // Special case: length of single dimension array property is turned into ldlen
5485 if (IsSingleDimensionalArrayLength ()) {
5487 EmitInstance (ec, false);
5488 ec.ig.Emit (OpCodes.Ldlen);
5489 ec.ig.Emit (OpCodes.Conv_I4);
5493 Invocation.EmitCall (ec, IsBase, InstanceExpression, getter, null, loc, prepared, false);
5496 ec.ig.Emit (OpCodes.Dup);
5498 temp = new LocalTemporary (this.Type);
5505 // Implements the IAssignMethod interface for assignments
5507 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5509 Expression my_source = source;
5511 if (prepare_for_load) {
5516 ec.ig.Emit (OpCodes.Dup);
5518 temp = new LocalTemporary (this.Type);
5522 } else if (leave_copy) {
5524 temp = new LocalTemporary (this.Type);
5529 ArrayList args = new ArrayList (1);
5530 args.Add (new Argument (my_source, Argument.AType.Expression));
5532 Invocation.EmitCall (ec, IsBase, InstanceExpression, setter, args, loc, false, prepared);
5542 /// Fully resolved expression that evaluates to an Event
5544 public class EventExpr : MemberExpr {
5545 public readonly EventInfo EventInfo;
5548 MethodInfo add_accessor, remove_accessor;
5550 public EventExpr (EventInfo ei, Location loc)
5554 eclass = ExprClass.EventAccess;
5556 add_accessor = TypeManager.GetAddMethod (ei);
5557 remove_accessor = TypeManager.GetRemoveMethod (ei);
5558 if (add_accessor.IsStatic || remove_accessor.IsStatic)
5561 if (EventInfo is MyEventBuilder){
5562 MyEventBuilder eb = (MyEventBuilder) EventInfo;
5563 type = eb.EventType;
5566 type = EventInfo.EventHandlerType;
5569 public override string Name {
5571 return EventInfo.Name;
5575 public override bool IsInstance {
5581 public override bool IsStatic {
5587 public override Type DeclaringType {
5589 return EventInfo.DeclaringType;
5593 void Error_AssignmentEventOnly ()
5595 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5596 GetSignatureForError ());
5599 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
5600 SimpleName original)
5603 // If the event is local to this class, we transform ourselves into a FieldExpr
5606 if (EventInfo.DeclaringType == ec.ContainerType ||
5607 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
5608 EventField mi = TypeManager.GetEventField (EventInfo);
5611 if (!ec.IsInObsoleteScope)
5612 mi.CheckObsoleteness (loc);
5614 if ((mi.ModFlags & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0 && !ec.IsInCompoundAssignment)
5615 Error_AssignmentEventOnly ();
5617 FieldExpr ml = new FieldExpr (mi.FieldBuilder, loc);
5619 InstanceExpression = null;
5621 return ml.ResolveMemberAccess (ec, left, loc, original);
5625 if (left is This && !ec.IsInCompoundAssignment)
5626 Error_AssignmentEventOnly ();
5628 return base.ResolveMemberAccess (ec, left, loc, original);
5631 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
5634 InstanceExpression = null;
5638 if (InstanceExpression == null) {
5639 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5643 InstanceExpression = InstanceExpression.DoResolve (ec);
5644 if (InstanceExpression == null)
5647 if (IsBase && add_accessor.IsAbstract) {
5648 Error_CannotCallAbstractBase(TypeManager.CSharpSignature(add_accessor));
5653 // This is using the same mechanism as the CS1540 check in PropertyExpr.
5654 // However, in the Event case, we reported a CS0122 instead.
5656 // TODO: Exact copy from PropertyExpr
5658 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
5659 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
5660 !TypeManager.IsNestedChildOf (ec.ContainerType, InstanceExpression.Type) &&
5661 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.ContainerType)) {
5662 Report.SymbolRelatedToPreviousError (EventInfo);
5663 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5670 public bool IsAccessibleFrom (Type invocation_type)
5673 return IsAccessorAccessible (invocation_type, add_accessor, out dummy) &&
5674 IsAccessorAccessible (invocation_type, remove_accessor, out dummy);
5677 public override Expression CreateExpressionTree (EmitContext ec)
5679 throw new NotSupportedException ("ET");
5682 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5684 // contexts where an LValue is valid have already devolved to FieldExprs
5685 Error_CannotAssign ();
5689 public override Expression DoResolve (EmitContext ec)
5691 bool must_do_cs1540_check;
5692 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
5693 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
5694 Report.SymbolRelatedToPreviousError (EventInfo);
5695 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5699 if (!InstanceResolve (ec, must_do_cs1540_check))
5702 if (!ec.IsInCompoundAssignment) {
5703 Error_CannotAssign ();
5707 if (!ec.IsInObsoleteScope) {
5708 EventField ev = TypeManager.GetEventField (EventInfo);
5710 ev.CheckObsoleteness (loc);
5712 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (EventInfo);
5714 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc);
5721 public override void Emit (EmitContext ec)
5723 Error_CannotAssign ();
5726 public void Error_CannotAssign ()
5728 Report.Error (70, loc,
5729 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
5730 GetSignatureForError (), TypeManager.CSharpName (EventInfo.DeclaringType));
5733 public override string GetSignatureForError ()
5735 return TypeManager.CSharpSignature (EventInfo);
5738 public void EmitAddOrRemove (EmitContext ec, bool is_add, Expression source)
5740 ArrayList args = new ArrayList (1);
5741 args.Add (new Argument (source, Argument.AType.Expression));
5742 Invocation.EmitCall (ec, IsBase, InstanceExpression, is_add ? add_accessor : remove_accessor, args, loc);
5746 public class TemporaryVariable : VariableReference
5750 public TemporaryVariable (Type type, Location loc)
5754 eclass = ExprClass.Variable;
5757 public override Expression CreateExpressionTree (EmitContext ec)
5759 throw new NotSupportedException ("ET");
5762 public override Expression DoResolve (EmitContext ec)
5767 TypeExpr te = new TypeExpression (type, loc);
5768 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
5769 if (!li.Resolve (ec))
5773 // Don't capture temporary variables except when using
5774 // iterator redirection
5776 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.IsIterator && ec.IsVariableCapturingRequired) {
5777 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
5778 storey.CaptureLocalVariable (ec, li);
5784 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5786 return DoResolve (ec);
5789 public override void Emit (EmitContext ec)
5794 public void EmitAssign (EmitContext ec, Expression source)
5796 EmitAssign (ec, source, false, false);
5799 public override HoistedVariable GetHoistedVariable (EmitContext ec)
5801 return li.HoistedVariableReference;
5804 public override bool IsFixed {
5805 get { return true; }
5808 public override bool IsRef {
5809 get { return false; }
5812 public override string Name {
5813 get { throw new NotImplementedException (); }
5816 public override void SetHasAddressTaken ()
5818 throw new NotImplementedException ();
5821 protected override ILocalVariable Variable {
5825 public override VariableInfo VariableInfo {
5826 get { throw new NotImplementedException (); }
5831 /// Handles `var' contextual keyword; var becomes a keyword only
5832 /// if no type called var exists in a variable scope
5834 public class VarExpr : SimpleName
5836 // Used for error reporting only
5837 ArrayList initializer;
5839 public VarExpr (Location loc)
5844 public ArrayList VariableInitializer {
5846 this.initializer = value;
5850 public bool InferType (EmitContext ec, Expression right_side)
5853 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
5855 type = right_side.Type;
5856 if (type == TypeManager.null_type || type == TypeManager.void_type || type == TypeManager.anonymous_method_type) {
5857 Report.Error (815, loc, "An implicitly typed local variable declaration cannot be initialized with `{0}'",
5858 right_side.GetSignatureForError ());
5862 eclass = ExprClass.Variable;
5866 protected override void Error_TypeOrNamespaceNotFound (IResolveContext ec)
5868 Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");
5871 public override TypeExpr ResolveAsContextualType (IResolveContext rc, bool silent)
5873 TypeExpr te = base.ResolveAsContextualType (rc, true);
5877 if (initializer == null)
5880 if (initializer.Count > 1) {
5881 Location loc = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [1]).Location;
5882 Report.Error (819, loc, "An implicitly typed local variable declaration cannot include multiple declarators");
5887 Expression variable_initializer = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [0]).expression_or_array_initializer;
5888 if (variable_initializer == null) {
5889 Report.Error (818, loc, "An implicitly typed local variable declarator must include an initializer");