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 Error_ValueCannotBeConvertedCore (ec, loc, target, expl);
370 protected void Error_ValueCannotBeConvertedCore (EmitContext ec, Location loc, Type target, bool expl)
372 // The error was already reported as CS1660
373 if (type == InternalType.AnonymousMethod)
376 if (TypeManager.IsGenericParameter (Type) && TypeManager.IsGenericParameter (target) && type.Name == target.Name) {
378 string sig1 = type.DeclaringMethod == null ?
379 TypeManager.CSharpName (type.DeclaringType) :
380 TypeManager.CSharpSignature (type.DeclaringMethod);
381 string sig2 = target.DeclaringMethod == null ?
382 TypeManager.CSharpName (target.DeclaringType) :
383 TypeManager.CSharpSignature (target.DeclaringMethod);
384 Report.ExtraInformation (loc,
386 "The generic parameter `{0}' of `{1}' cannot be converted to the generic parameter `{0}' of `{2}' (in the previous ",
387 Type.Name, sig1, sig2));
389 } else if (Type.FullName == target.FullName){
390 Report.ExtraInformation (loc,
392 "The type `{0}' has two conflicting definitions, one comes from `{1}' and the other from `{2}' (in the previous ",
393 Type.FullName, Type.Assembly.FullName, target.Assembly.FullName));
397 Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
398 TypeManager.CSharpName (type), TypeManager.CSharpName (target));
402 Report.DisableReporting ();
403 bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null;
404 Report.EnableReporting ();
407 Report.Error (266, loc, "Cannot implicitly convert type `{0}' to `{1}'. " +
408 "An explicit conversion exists (are you missing a cast?)",
409 TypeManager.CSharpName (Type), TypeManager.CSharpName (target));
413 Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
414 TypeManager.CSharpName (type),
415 TypeManager.CSharpName (target));
418 public virtual void Error_VariableIsUsedBeforeItIsDeclared (string name)
420 Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", name);
423 protected virtual void Error_TypeDoesNotContainDefinition (Type type, string name)
425 Error_TypeDoesNotContainDefinition (loc, type, name);
428 public static void Error_TypeDoesNotContainDefinition (Location loc, Type type, string name)
430 Report.SymbolRelatedToPreviousError (type);
431 Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
432 TypeManager.CSharpName (type), name);
435 protected static void Error_ValueAssignment (Location loc)
437 Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
440 ResolveFlags ExprClassToResolveFlags
445 case ExprClass.Namespace:
446 return ResolveFlags.Type;
448 case ExprClass.MethodGroup:
449 return ResolveFlags.MethodGroup;
451 case ExprClass.TypeParameter:
452 return ResolveFlags.TypeParameter;
454 case ExprClass.Value:
455 case ExprClass.Variable:
456 case ExprClass.PropertyAccess:
457 case ExprClass.EventAccess:
458 case ExprClass.IndexerAccess:
459 return ResolveFlags.VariableOrValue;
462 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
468 /// Resolves an expression and performs semantic analysis on it.
472 /// Currently Resolve wraps DoResolve to perform sanity
473 /// checking and assertion checking on what we expect from Resolve.
475 public Expression Resolve (EmitContext ec, ResolveFlags flags)
477 if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type)
478 return ResolveAsTypeStep (ec, false);
480 bool do_flow_analysis = ec.DoFlowAnalysis;
481 bool omit_struct_analysis = ec.OmitStructFlowAnalysis;
482 if ((flags & ResolveFlags.DisableFlowAnalysis) != 0)
483 do_flow_analysis = false;
484 if ((flags & ResolveFlags.DisableStructFlowAnalysis) != 0)
485 omit_struct_analysis = true;
488 using (ec.WithFlowAnalysis (do_flow_analysis, omit_struct_analysis)) {
489 if (this is SimpleName) {
490 bool intermediate = (flags & ResolveFlags.Intermediate) == ResolveFlags.Intermediate;
491 e = ((SimpleName) this).DoResolve (ec, intermediate);
500 if ((flags & e.ExprClassToResolveFlags) == 0) {
501 e.Error_UnexpectedKind (flags, loc);
505 if (e.type == null && !(e is Namespace)) {
506 throw new Exception (
507 "Expression " + e.GetType () +
508 " did not set its type after Resolve\n" +
509 "called from: " + this.GetType ());
516 /// Resolves an expression and performs semantic analysis on it.
518 public Expression Resolve (EmitContext ec)
520 Expression e = Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
522 if (e != null && e.eclass == ExprClass.MethodGroup && RootContext.Version == LanguageVersion.ISO_1) {
523 ((MethodGroupExpr) e).ReportUsageError ();
529 public Constant ResolveAsConstant (EmitContext ec, MemberCore mc)
531 Expression e = Resolve (ec);
535 Constant c = e as Constant;
539 if (type != null && TypeManager.IsReferenceType (type))
540 Const.Error_ConstantCanBeInitializedWithNullOnly (type, loc, mc.GetSignatureForError ());
542 Const.Error_ExpressionMustBeConstant (loc, mc.GetSignatureForError ());
548 /// Resolves an expression for LValue assignment
552 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
553 /// checking and assertion checking on what we expect from Resolve
555 public Expression ResolveLValue (EmitContext ec, Expression right_side)
557 int errors = Report.Errors;
558 bool out_access = right_side == EmptyExpression.OutAccess;
560 Expression e = DoResolveLValue (ec, right_side);
562 if (e != null && out_access && !(e is IMemoryLocation)) {
563 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
564 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
566 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
567 // e.GetType () + " " + e.GetSignatureForError ());
572 if (errors == Report.Errors) {
574 Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
576 Error_ValueAssignment (loc);
581 if (e.eclass == ExprClass.Invalid)
582 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
584 if ((e.type == null) && !(e is GenericTypeExpr))
585 throw new Exception ("Expression " + e + " did not set its type after Resolve");
591 /// Emits the code for the expression
595 /// The Emit method is invoked to generate the code
596 /// for the expression.
598 public abstract void Emit (EmitContext ec);
600 // Emit code to branch to @target if this expression is equivalent to @on_true.
601 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
602 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
603 // including the use of conditional branches. Note also that a branch MUST be emitted
604 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
607 ec.ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
610 // Emit this expression for its side effects, not for its value.
611 // The default implementation is to emit the value, and then throw it away.
612 // Subclasses can provide more efficient implementations, but those MUST be equivalent
613 public virtual void EmitSideEffect (EmitContext ec)
616 ec.ig.Emit (OpCodes.Pop);
620 /// Protected constructor. Only derivate types should
621 /// be able to be created
624 protected Expression ()
626 eclass = ExprClass.Invalid;
631 /// Returns a fully formed expression after a MemberLookup
634 public static Expression ExprClassFromMemberInfo (Type container_type, MemberInfo mi, Location loc)
637 return new EventExpr ((EventInfo) mi, loc);
638 else if (mi is FieldInfo) {
639 FieldInfo fi = (FieldInfo) mi;
640 if (fi.IsLiteral || (fi.IsInitOnly && fi.FieldType == TypeManager.decimal_type))
641 return new ConstantExpr (fi, loc);
642 return new FieldExpr (fi, loc);
643 } else if (mi is PropertyInfo)
644 return new PropertyExpr (container_type, (PropertyInfo) mi, loc);
645 else if (mi is Type) {
646 return new TypeExpression ((System.Type) mi, loc);
652 // TODO: [Obsolete ("Can be removed")]
653 protected static ArrayList almost_matched_members = new ArrayList (4);
656 // FIXME: Probably implement a cache for (t,name,current_access_set)?
658 // This code could use some optimizations, but we need to do some
659 // measurements. For example, we could use a delegate to `flag' when
660 // something can not any longer be a method-group (because it is something
664 // If the return value is an Array, then it is an array of
667 // If the return value is an MemberInfo, it is anything, but a Method
671 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
672 // the arguments here and have MemberLookup return only the methods that
673 // match the argument count/type, unlike we are doing now (we delay this
676 // This is so we can catch correctly attempts to invoke instance methods
677 // from a static body (scan for error 120 in ResolveSimpleName).
680 // FIXME: Potential optimization, have a static ArrayList
683 public static Expression MemberLookup (Type container_type, Type queried_type, string name,
684 MemberTypes mt, BindingFlags bf, Location loc)
686 return MemberLookup (container_type, null, queried_type, name, mt, bf, loc);
690 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
691 // `qualifier_type' or null to lookup members in the current class.
694 public static Expression MemberLookup (Type container_type,
695 Type qualifier_type, Type queried_type,
696 string name, MemberTypes mt,
697 BindingFlags bf, Location loc)
699 almost_matched_members.Clear ();
701 MemberInfo [] mi = TypeManager.MemberLookup (container_type, qualifier_type,
702 queried_type, mt, bf, name, almost_matched_members);
708 bool is_interface = qualifier_type != null && qualifier_type.IsInterface;
709 ArrayList methods = new ArrayList (2);
710 ArrayList non_methods = null;
712 foreach (MemberInfo m in mi) {
713 if (m is MethodBase) {
718 if (non_methods == null) {
719 non_methods = new ArrayList (2);
724 foreach (MemberInfo n_m in non_methods) {
725 if (m.DeclaringType.IsInterface && TypeManager.ImplementsInterface (m.DeclaringType, n_m.DeclaringType))
728 Report.SymbolRelatedToPreviousError (m);
729 Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
730 TypeManager.GetFullNameSignature (m), TypeManager.GetFullNameSignature (n_m));
735 if (methods.Count == 0)
736 return ExprClassFromMemberInfo (container_type, (MemberInfo)non_methods [0], loc);
738 if (non_methods != null) {
739 MethodBase method = (MethodBase) methods [0];
740 MemberInfo non_method = (MemberInfo) non_methods [0];
741 if (method.DeclaringType == non_method.DeclaringType) {
742 // Cannot happen with C# code, but is valid in IL
743 Report.SymbolRelatedToPreviousError (method);
744 Report.SymbolRelatedToPreviousError (non_method);
745 Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
746 TypeManager.GetFullNameSignature (non_method),
747 TypeManager.CSharpSignature (method));
752 Report.SymbolRelatedToPreviousError (method);
753 Report.SymbolRelatedToPreviousError (non_method);
754 Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and non-method `{1}'. Using method `{0}'",
755 TypeManager.CSharpSignature (method), TypeManager.GetFullNameSignature (non_method));
759 return new MethodGroupExpr (methods, queried_type, loc);
762 if (mi [0] is MethodBase)
763 return new MethodGroupExpr (mi, queried_type, loc);
765 return ExprClassFromMemberInfo (container_type, mi [0], loc);
768 public const MemberTypes AllMemberTypes =
769 MemberTypes.Constructor |
773 MemberTypes.NestedType |
774 MemberTypes.Property;
776 public const BindingFlags AllBindingFlags =
777 BindingFlags.Public |
778 BindingFlags.Static |
779 BindingFlags.Instance;
781 public static Expression MemberLookup (Type container_type, Type queried_type,
782 string name, Location loc)
784 return MemberLookup (container_type, null, queried_type, name,
785 AllMemberTypes, AllBindingFlags, loc);
788 public static Expression MemberLookup (Type container_type, Type qualifier_type,
789 Type queried_type, string name, Location loc)
791 return MemberLookup (container_type, qualifier_type, queried_type,
792 name, AllMemberTypes, AllBindingFlags, loc);
795 public static MethodGroupExpr MethodLookup (Type container_type, Type queried_type,
796 string name, Location loc)
798 return (MethodGroupExpr)MemberLookup (container_type, null, queried_type, name,
799 MemberTypes.Method, AllBindingFlags, loc);
803 /// This is a wrapper for MemberLookup that is not used to "probe", but
804 /// to find a final definition. If the final definition is not found, we
805 /// look for private members and display a useful debugging message if we
808 protected Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
809 Type queried_type, string name,
810 MemberTypes mt, BindingFlags bf,
815 int errors = Report.Errors;
816 e = MemberLookup (ec.ContainerType, qualifier_type, queried_type, name, mt, bf, loc);
818 if (e != null || errors != Report.Errors)
821 // No errors were reported by MemberLookup, but there was an error.
822 return Error_MemberLookupFailed (ec.ContainerType, qualifier_type, queried_type,
826 protected virtual Expression Error_MemberLookupFailed (Type container_type, Type qualifier_type,
827 Type queried_type, string name, string class_name,
828 MemberTypes mt, BindingFlags bf)
830 MemberInfo[] lookup = null;
831 if (queried_type == null) {
832 class_name = "global::";
834 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
835 mt, (bf & ~BindingFlags.Public) | BindingFlags.NonPublic,
838 if (lookup != null) {
839 Expression e = Error_MemberLookupFailed (queried_type, lookup);
842 // FIXME: This is still very wrong, it should be done inside
843 // OverloadResolve to do correct arguments matching.
844 // Requires MemberLookup accessiblity check removal
846 if (e == null || (mt & (MemberTypes.Method | MemberTypes.Constructor)) == 0) {
847 MemberInfo mi = lookup[0];
848 Report.SymbolRelatedToPreviousError (mi);
849 if (qualifier_type != null && container_type != null && qualifier_type != container_type &&
850 TypeManager.IsNestedFamilyAccessible (container_type, mi.DeclaringType)) {
851 // Although a derived class can access protected members of
852 // its base class it cannot do so through an instance of the
853 // base class (CS1540). If the qualifier_type is a base of the
854 // ec.ContainerType and the lookup succeeds with the latter one,
855 // then we are in this situation.
856 Error_CannotAccessProtected (loc, mi, qualifier_type, container_type);
858 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (mi));
865 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
866 AllMemberTypes, AllBindingFlags | BindingFlags.NonPublic,
870 if (lookup == null) {
871 if (class_name != null) {
872 Report.Error (103, loc, "The name `{0}' does not exist in the current context",
875 Error_TypeDoesNotContainDefinition (queried_type, name);
880 if (TypeManager.MemberLookup (queried_type, null, queried_type,
881 AllMemberTypes, AllBindingFlags |
882 BindingFlags.NonPublic, name, null) == null) {
883 if ((lookup.Length == 1) && (lookup [0] is Type)) {
884 Type t = (Type) lookup [0];
886 Report.Error (305, loc,
887 "Using the generic type `{0}' " +
888 "requires {1} type arguments",
889 TypeManager.CSharpName (t),
890 TypeManager.GetNumberOfTypeArguments (t).ToString ());
895 return Error_MemberLookupFailed (queried_type, lookup);
898 protected virtual Expression Error_MemberLookupFailed (Type type, MemberInfo[] members)
900 for (int i = 0; i < members.Length; ++i) {
901 if (!(members [i] is MethodBase))
905 // By default propagate the closest candidates upwards
906 return new MethodGroupExpr (members, type, loc, true);
909 protected virtual void Error_NegativeArrayIndex (Location loc)
911 throw new NotImplementedException ();
914 protected void Error_PointerInsideExpressionTree ()
916 Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
920 /// Returns an expression that can be used to invoke operator true
921 /// on the expression if it exists.
923 static public Expression GetOperatorTrue (EmitContext ec, Expression e, Location loc)
925 return GetOperatorTrueOrFalse (ec, e, true, loc);
929 /// Returns an expression that can be used to invoke operator false
930 /// on the expression if it exists.
932 static public Expression GetOperatorFalse (EmitContext ec, Expression e, Location loc)
934 return GetOperatorTrueOrFalse (ec, e, false, loc);
937 static Expression GetOperatorTrueOrFalse (EmitContext ec, Expression e, bool is_true, Location loc)
939 MethodGroupExpr operator_group;
940 string mname = Operator.GetMetadataName (is_true ? Operator.OpType.True : Operator.OpType.False);
941 operator_group = MethodLookup (ec.ContainerType, e.Type, mname, loc) as MethodGroupExpr;
942 if (operator_group == null)
945 Arguments arguments = new Arguments (1);
946 arguments.Add (new Argument (e));
947 operator_group = operator_group.OverloadResolve (
948 ec, ref arguments, false, loc);
950 if (operator_group == null)
953 return new UserOperatorCall (operator_group, arguments, null, loc);
957 /// Resolves the expression `e' into a boolean expression: either through
958 /// an implicit conversion, or through an `operator true' invocation
960 public static Expression ResolveBoolean (EmitContext ec, Expression e, Location loc)
966 if (e.Type == TypeManager.bool_type)
969 Expression converted = Convert.ImplicitConversion (ec, e, TypeManager.bool_type, Location.Null);
971 if (converted != null)
975 // If no implicit conversion to bool exists, try using `operator true'
977 converted = Expression.GetOperatorTrue (ec, e, loc);
978 if (converted == null){
979 e.Error_ValueCannotBeConverted (ec, loc, TypeManager.bool_type, false);
985 public virtual string ExprClassName
989 case ExprClass.Invalid:
991 case ExprClass.Value:
993 case ExprClass.Variable:
995 case ExprClass.Namespace:
999 case ExprClass.MethodGroup:
1000 return "method group";
1001 case ExprClass.PropertyAccess:
1002 return "property access";
1003 case ExprClass.EventAccess:
1004 return "event access";
1005 case ExprClass.IndexerAccess:
1006 return "indexer access";
1007 case ExprClass.Nothing:
1009 case ExprClass.TypeParameter:
1010 return "type parameter";
1012 throw new Exception ("Should not happen");
1017 /// Reports that we were expecting `expr' to be of class `expected'
1019 public void Error_UnexpectedKind (DeclSpace ds, string expected, Location loc)
1021 Error_UnexpectedKind (ds, expected, ExprClassName, loc);
1024 public void Error_UnexpectedKind (DeclSpace ds, string expected, string was, Location loc)
1026 string name = GetSignatureForError ();
1028 name = ds.GetSignatureForError () + '.' + name;
1030 Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
1031 name, was, expected);
1034 public void Error_UnexpectedKind (ResolveFlags flags, Location loc)
1036 string [] valid = new string [4];
1039 if ((flags & ResolveFlags.VariableOrValue) != 0) {
1040 valid [count++] = "variable";
1041 valid [count++] = "value";
1044 if ((flags & ResolveFlags.Type) != 0)
1045 valid [count++] = "type";
1047 if ((flags & ResolveFlags.MethodGroup) != 0)
1048 valid [count++] = "method group";
1051 valid [count++] = "unknown";
1053 StringBuilder sb = new StringBuilder (valid [0]);
1054 for (int i = 1; i < count - 1; i++) {
1056 sb.Append (valid [i]);
1059 sb.Append ("' or `");
1060 sb.Append (valid [count - 1]);
1063 Report.Error (119, loc,
1064 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1067 public static void UnsafeError (Location loc)
1069 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1073 // Load the object from the pointer.
1075 public static void LoadFromPtr (ILGenerator ig, Type t)
1077 if (t == TypeManager.int32_type)
1078 ig.Emit (OpCodes.Ldind_I4);
1079 else if (t == TypeManager.uint32_type)
1080 ig.Emit (OpCodes.Ldind_U4);
1081 else if (t == TypeManager.short_type)
1082 ig.Emit (OpCodes.Ldind_I2);
1083 else if (t == TypeManager.ushort_type)
1084 ig.Emit (OpCodes.Ldind_U2);
1085 else if (t == TypeManager.char_type)
1086 ig.Emit (OpCodes.Ldind_U2);
1087 else if (t == TypeManager.byte_type)
1088 ig.Emit (OpCodes.Ldind_U1);
1089 else if (t == TypeManager.sbyte_type)
1090 ig.Emit (OpCodes.Ldind_I1);
1091 else if (t == TypeManager.uint64_type)
1092 ig.Emit (OpCodes.Ldind_I8);
1093 else if (t == TypeManager.int64_type)
1094 ig.Emit (OpCodes.Ldind_I8);
1095 else if (t == TypeManager.float_type)
1096 ig.Emit (OpCodes.Ldind_R4);
1097 else if (t == TypeManager.double_type)
1098 ig.Emit (OpCodes.Ldind_R8);
1099 else if (t == TypeManager.bool_type)
1100 ig.Emit (OpCodes.Ldind_I1);
1101 else if (t == TypeManager.intptr_type)
1102 ig.Emit (OpCodes.Ldind_I);
1103 else if (TypeManager.IsEnumType (t)) {
1104 if (t == TypeManager.enum_type)
1105 ig.Emit (OpCodes.Ldind_Ref);
1107 LoadFromPtr (ig, TypeManager.GetEnumUnderlyingType (t));
1108 } else if (TypeManager.IsStruct (t) || TypeManager.IsGenericParameter (t))
1109 ig.Emit (OpCodes.Ldobj, t);
1110 else if (t.IsPointer)
1111 ig.Emit (OpCodes.Ldind_I);
1113 ig.Emit (OpCodes.Ldind_Ref);
1117 // The stack contains the pointer and the value of type `type'
1119 public static void StoreFromPtr (ILGenerator ig, Type type)
1121 if (TypeManager.IsEnumType (type))
1122 type = TypeManager.GetEnumUnderlyingType (type);
1123 if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
1124 ig.Emit (OpCodes.Stind_I4);
1125 else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
1126 ig.Emit (OpCodes.Stind_I8);
1127 else if (type == TypeManager.char_type || type == TypeManager.short_type ||
1128 type == TypeManager.ushort_type)
1129 ig.Emit (OpCodes.Stind_I2);
1130 else if (type == TypeManager.float_type)
1131 ig.Emit (OpCodes.Stind_R4);
1132 else if (type == TypeManager.double_type)
1133 ig.Emit (OpCodes.Stind_R8);
1134 else if (type == TypeManager.byte_type || type == TypeManager.sbyte_type ||
1135 type == TypeManager.bool_type)
1136 ig.Emit (OpCodes.Stind_I1);
1137 else if (type == TypeManager.intptr_type)
1138 ig.Emit (OpCodes.Stind_I);
1139 else if (TypeManager.IsStruct (type) || TypeManager.IsGenericParameter (type))
1140 ig.Emit (OpCodes.Stobj, type);
1142 ig.Emit (OpCodes.Stind_Ref);
1146 // Returns the size of type `t' if known, otherwise, 0
1148 public static int GetTypeSize (Type t)
1150 t = TypeManager.TypeToCoreType (t);
1151 if (t == TypeManager.int32_type ||
1152 t == TypeManager.uint32_type ||
1153 t == TypeManager.float_type)
1155 else if (t == TypeManager.int64_type ||
1156 t == TypeManager.uint64_type ||
1157 t == TypeManager.double_type)
1159 else if (t == TypeManager.byte_type ||
1160 t == TypeManager.sbyte_type ||
1161 t == TypeManager.bool_type)
1163 else if (t == TypeManager.short_type ||
1164 t == TypeManager.char_type ||
1165 t == TypeManager.ushort_type)
1167 else if (t == TypeManager.decimal_type)
1173 protected void Error_CannotCallAbstractBase (string name)
1175 Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
1178 protected void Error_CannotModifyIntermediateExpressionValue (EmitContext ec)
1180 Report.SymbolRelatedToPreviousError (type);
1181 if (ec.CurrentInitializerVariable != null) {
1182 Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
1183 TypeManager.CSharpName (type), GetSignatureForError ());
1185 Report.Error (1612, loc, "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
1186 GetSignatureForError ());
1190 public void Error_ExpressionCannotBeGeneric (Location loc)
1192 Report.Error (307, loc, "The {0} `{1}' cannot be used with type arguments",
1193 ExprClassName, GetSignatureForError ());
1197 // Converts `source' to an int, uint, long or ulong.
1199 public Expression ConvertExpressionToArrayIndex (EmitContext ec, Expression source)
1201 Expression converted;
1203 using (ec.With (EmitContext.Flags.CheckState, true)) {
1204 converted = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, source.loc);
1205 if (converted == null)
1206 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, source.loc);
1207 if (converted == null)
1208 converted = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, source.loc);
1209 if (converted == null)
1210 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, source.loc);
1212 if (converted == null) {
1213 source.Error_ValueCannotBeConverted (ec, source.loc, TypeManager.int32_type, false);
1219 // Only positive constants are allowed at compile time
1221 Constant c = converted as Constant;
1224 Error_NegativeArrayIndex (source.loc);
1229 return new ArrayIndexCast (converted).Resolve (ec);
1233 // Derived classes implement this method by cloning the fields that
1234 // could become altered during the Resolve stage
1236 // Only expressions that are created for the parser need to implement
1239 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1241 throw new NotImplementedException (
1243 "CloneTo not implemented for expression {0}", this.GetType ()));
1247 // Clones an expression created by the parser.
1249 // We only support expressions created by the parser so far, not
1250 // expressions that have been resolved (many more classes would need
1251 // to implement CloneTo).
1253 // This infrastructure is here merely for Lambda expressions which
1254 // compile the same code using different type values for the same
1255 // arguments to find the correct overload
1257 public Expression Clone (CloneContext clonectx)
1259 Expression cloned = (Expression) MemberwiseClone ();
1260 CloneTo (clonectx, cloned);
1266 // Implementation of expression to expression tree conversion
1268 public abstract Expression CreateExpressionTree (EmitContext ec);
1270 protected Expression CreateExpressionFactoryCall (string name, Arguments args)
1272 return CreateExpressionFactoryCall (name, null, args, loc);
1275 protected Expression CreateExpressionFactoryCall (string name, TypeArguments typeArguments, Arguments args)
1277 return CreateExpressionFactoryCall (name, typeArguments, args, loc);
1280 public static Expression CreateExpressionFactoryCall (string name, TypeArguments typeArguments, Arguments args, Location loc)
1282 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (loc), name, typeArguments, loc), args);
1285 protected static TypeExpr CreateExpressionTypeExpression (Location loc)
1287 TypeExpr texpr = TypeManager.expression_type_expr;
1288 if (texpr == null) {
1289 Type t = TypeManager.CoreLookupType ("System.Linq.Expressions", "Expression", Kind.Class, true);
1293 TypeManager.expression_type_expr = texpr = new TypeExpression (t, Location.Null);
1299 public virtual void MutateHoistedGenericType (AnonymousMethodStorey storey)
1301 // TODO: It should probably be type = storey.MutateType (type);
1306 /// This is just a base class for expressions that can
1307 /// appear on statements (invocations, object creation,
1308 /// assignments, post/pre increment and decrement). The idea
1309 /// being that they would support an extra Emition interface that
1310 /// does not leave a result on the stack.
1312 public abstract class ExpressionStatement : Expression {
1314 public virtual ExpressionStatement ResolveStatement (EmitContext ec)
1316 Expression e = Resolve (ec);
1320 ExpressionStatement es = e as ExpressionStatement;
1322 Error_InvalidExpressionStatement ();
1328 /// Requests the expression to be emitted in a `statement'
1329 /// context. This means that no new value is left on the
1330 /// stack after invoking this method (constrasted with
1331 /// Emit that will always leave a value on the stack).
1333 public abstract void EmitStatement (EmitContext ec);
1335 public override void EmitSideEffect (EmitContext ec)
1342 /// This kind of cast is used to encapsulate the child
1343 /// whose type is child.Type into an expression that is
1344 /// reported to return "return_type". This is used to encapsulate
1345 /// expressions which have compatible types, but need to be dealt
1346 /// at higher levels with.
1348 /// For example, a "byte" expression could be encapsulated in one
1349 /// of these as an "unsigned int". The type for the expression
1350 /// would be "unsigned int".
1353 public abstract class TypeCast : Expression
1355 protected readonly Expression child;
1357 protected TypeCast (Expression child, Type return_type)
1359 eclass = child.eclass;
1360 loc = child.Location;
1365 public override Expression CreateExpressionTree (EmitContext ec)
1367 Arguments args = new Arguments (2);
1368 args.Add (new Argument (child.CreateExpressionTree (ec)));
1369 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1371 if (type.IsPointer || child.Type.IsPointer)
1372 Error_PointerInsideExpressionTree ();
1374 return CreateExpressionFactoryCall (ec.CheckState ? "ConvertChecked" : "Convert", args);
1377 public override Expression DoResolve (EmitContext ec)
1379 // This should never be invoked, we are born in fully
1380 // initialized state.
1385 public override void Emit (EmitContext ec)
1390 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
1392 return child.GetAttributableValue (ec, value_type, out value);
1395 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1397 type = storey.MutateType (type);
1398 child.MutateHoistedGenericType (storey);
1401 protected override void CloneTo (CloneContext clonectx, Expression t)
1406 public override bool IsNull {
1407 get { return child.IsNull; }
1411 public class EmptyCast : TypeCast {
1412 EmptyCast (Expression child, Type target_type)
1413 : base (child, target_type)
1417 public static Expression Create (Expression child, Type type)
1419 Constant c = child as Constant;
1421 return new EmptyConstantCast (c, type);
1423 EmptyCast e = child as EmptyCast;
1425 return new EmptyCast (e.child, type);
1427 return new EmptyCast (child, type);
1430 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1432 child.EmitBranchable (ec, label, on_true);
1435 public override void EmitSideEffect (EmitContext ec)
1437 child.EmitSideEffect (ec);
1442 // Used for predefined class library user casts (no obsolete check, etc.)
1444 public class OperatorCast : TypeCast {
1445 MethodInfo conversion_operator;
1447 public OperatorCast (Expression child, Type target_type)
1448 : this (child, target_type, false)
1452 public OperatorCast (Expression child, Type target_type, bool find_explicit)
1453 : base (child, target_type)
1455 conversion_operator = GetConversionOperator (find_explicit);
1456 if (conversion_operator == null)
1457 throw new InternalErrorException ("Outer conversion routine is out of sync");
1460 // Returns the implicit operator that converts from
1461 // 'child.Type' to our target type (type)
1462 MethodInfo GetConversionOperator (bool find_explicit)
1464 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1468 mi = TypeManager.MemberLookup (child.Type, child.Type, child.Type, MemberTypes.Method,
1469 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1472 mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1473 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1476 foreach (MethodInfo oper in mi) {
1477 AParametersCollection pd = TypeManager.GetParameterData (oper);
1479 if (pd.Types [0] == child.Type && TypeManager.TypeToCoreType (oper.ReturnType) == type)
1486 public override void Emit (EmitContext ec)
1489 ec.ig.Emit (OpCodes.Call, conversion_operator);
1494 /// This is a numeric cast to a Decimal
1496 public class CastToDecimal : OperatorCast {
1497 public CastToDecimal (Expression child)
1498 : this (child, false)
1502 public CastToDecimal (Expression child, bool find_explicit)
1503 : base (child, TypeManager.decimal_type, find_explicit)
1509 /// This is an explicit numeric cast from a Decimal
1511 public class CastFromDecimal : TypeCast
1513 static IDictionary operators;
1515 public CastFromDecimal (Expression child, Type return_type)
1516 : base (child, return_type)
1518 if (child.Type != TypeManager.decimal_type)
1519 throw new InternalErrorException (
1520 "The expected type is Decimal, instead it is " + child.Type.FullName);
1523 // Returns the explicit operator that converts from an
1524 // express of type System.Decimal to 'type'.
1525 public Expression Resolve ()
1527 if (operators == null) {
1528 MemberInfo[] all_oper = TypeManager.MemberLookup (TypeManager.decimal_type,
1529 TypeManager.decimal_type, TypeManager.decimal_type, MemberTypes.Method,
1530 BindingFlags.Static | BindingFlags.Public, "op_Explicit", null);
1532 operators = new System.Collections.Specialized.HybridDictionary ();
1533 foreach (MethodInfo oper in all_oper) {
1534 AParametersCollection pd = TypeManager.GetParameterData (oper);
1535 if (pd.Types [0] == TypeManager.decimal_type)
1536 operators.Add (TypeManager.TypeToCoreType (oper.ReturnType), oper);
1540 return operators.Contains (type) ? this : null;
1543 public override void Emit (EmitContext ec)
1545 ILGenerator ig = ec.ig;
1548 ig.Emit (OpCodes.Call, (MethodInfo)operators [type]);
1554 // Constant specialization of EmptyCast.
1555 // We need to special case this since an empty cast of
1556 // a constant is still a constant.
1558 public class EmptyConstantCast : Constant
1560 public readonly Constant child;
1562 public EmptyConstantCast(Constant child, Type type)
1563 : base (child.Location)
1565 eclass = child.eclass;
1570 public override string AsString ()
1572 return child.AsString ();
1575 public override object GetValue ()
1577 return child.GetValue ();
1580 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
1582 // FIXME: check that 'type' can be converted to 'target_type' first
1583 return child.ConvertExplicitly (in_checked_context, target_type);
1586 public override Expression CreateExpressionTree (EmitContext ec)
1588 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1589 child.CreateExpressionTree (ec),
1590 new TypeOf (new TypeExpression (type, loc), loc));
1593 Error_PointerInsideExpressionTree ();
1595 return CreateExpressionFactoryCall ("Convert", args);
1598 public override Constant Increment ()
1600 return child.Increment ();
1603 public override bool IsDefaultValue {
1604 get { return child.IsDefaultValue; }
1607 public override bool IsNegative {
1608 get { return child.IsNegative; }
1611 public override bool IsNull {
1612 get { return child.IsNull; }
1615 public override bool IsZeroInteger {
1616 get { return child.IsZeroInteger; }
1619 public override void Emit (EmitContext ec)
1624 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1626 child.EmitBranchable (ec, label, on_true);
1629 // Only to make verifier happy
1630 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1631 ec.ig.Emit (OpCodes.Unbox_Any, type);
1635 public override void EmitSideEffect (EmitContext ec)
1637 child.EmitSideEffect (ec);
1640 public override Constant ConvertImplicitly (Type target_type)
1642 // FIXME: Do we need to check user conversions?
1643 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1645 return child.ConvertImplicitly (target_type);
1648 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1650 child.MutateHoistedGenericType (storey);
1656 /// This class is used to wrap literals which belong inside Enums
1658 public class EnumConstant : Constant {
1659 public Constant Child;
1661 public EnumConstant (Constant child, Type enum_type):
1662 base (child.Location)
1664 eclass = child.eclass;
1669 public override Expression DoResolve (EmitContext ec)
1671 // This should never be invoked, we are born in fully
1672 // initialized state.
1677 public override void Emit (EmitContext ec)
1682 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1684 Child.EmitBranchable (ec, label, on_true);
1687 public override void EmitSideEffect (EmitContext ec)
1689 Child.EmitSideEffect (ec);
1692 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
1694 value = GetTypedValue ();
1698 public override string GetSignatureForError()
1700 return TypeManager.CSharpName (Type);
1703 public override object GetValue ()
1705 return Child.GetValue ();
1708 public override object GetTypedValue ()
1710 // FIXME: runtime is not ready to work with just emited enums
1711 if (!RootContext.StdLib) {
1712 return Child.GetValue ();
1716 // Small workaround for big problem
1717 // System.Enum.ToObject cannot be called on dynamic types
1718 // EnumBuilder has to be used, but we cannot use EnumBuilder
1719 // because it does not properly support generics
1721 // This works only sometimes
1723 if (type.Module == RootContext.ToplevelTypes.Builder)
1724 return Child.GetValue ();
1727 return System.Enum.ToObject (type, Child.GetValue ());
1730 public override string AsString ()
1732 return Child.AsString ();
1735 public override Constant Increment()
1737 return new EnumConstant (Child.Increment (), type);
1740 public override bool IsDefaultValue {
1742 return Child.IsDefaultValue;
1746 public override bool IsZeroInteger {
1747 get { return Child.IsZeroInteger; }
1750 public override bool IsNegative {
1752 return Child.IsNegative;
1756 public override Constant ConvertExplicitly(bool in_checked_context, Type target_type)
1758 if (Child.Type == target_type)
1761 return Child.ConvertExplicitly (in_checked_context, target_type);
1764 public override Constant ConvertImplicitly (Type type)
1766 Type this_type = TypeManager.DropGenericTypeArguments (Type);
1767 type = TypeManager.DropGenericTypeArguments (type);
1769 if (this_type == type) {
1770 // This is workaround of mono bug. It can be removed when the latest corlib spreads enough
1771 if (TypeManager.IsEnumType (type.UnderlyingSystemType))
1774 Type child_type = TypeManager.DropGenericTypeArguments (Child.Type);
1775 if (type.UnderlyingSystemType != child_type)
1776 Child = Child.ConvertImplicitly (type.UnderlyingSystemType);
1780 if (!Convert.ImplicitStandardConversionExists (this, type)){
1784 return Child.ConvertImplicitly(type);
1790 /// This kind of cast is used to encapsulate Value Types in objects.
1792 /// The effect of it is to box the value type emitted by the previous
1795 public class BoxedCast : TypeCast {
1797 public BoxedCast (Expression expr, Type target_type)
1798 : base (expr, target_type)
1800 eclass = ExprClass.Value;
1803 public override Expression DoResolve (EmitContext ec)
1805 // This should never be invoked, we are born in fully
1806 // initialized state.
1811 public override void Emit (EmitContext ec)
1815 ec.ig.Emit (OpCodes.Box, child.Type);
1818 public override void EmitSideEffect (EmitContext ec)
1820 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1821 // so, we need to emit the box+pop instructions in most cases
1822 if (TypeManager.IsStruct (child.Type) &&
1823 (type == TypeManager.object_type || type == TypeManager.value_type))
1824 child.EmitSideEffect (ec);
1826 base.EmitSideEffect (ec);
1830 public class UnboxCast : TypeCast {
1831 public UnboxCast (Expression expr, Type return_type)
1832 : base (expr, return_type)
1836 public override Expression DoResolve (EmitContext ec)
1838 // This should never be invoked, we are born in fully
1839 // initialized state.
1844 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1846 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
1847 Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
1848 return base.DoResolveLValue (ec, right_side);
1851 public override void Emit (EmitContext ec)
1855 ILGenerator ig = ec.ig;
1858 ig.Emit (OpCodes.Unbox_Any, type);
1860 ig.Emit (OpCodes.Unbox, type);
1861 LoadFromPtr (ig, type);
1865 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1867 type = storey.MutateType (type);
1868 base.MutateHoistedGenericType (storey);
1873 /// This is used to perform explicit numeric conversions.
1875 /// Explicit numeric conversions might trigger exceptions in a checked
1876 /// context, so they should generate the conv.ovf opcodes instead of
1879 public class ConvCast : TypeCast {
1880 public enum Mode : byte {
1881 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1883 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1884 U2_I1, U2_U1, U2_I2, U2_CH,
1885 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1886 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1887 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH,
1888 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH,
1889 CH_I1, CH_U1, CH_I2,
1890 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1891 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4
1896 public ConvCast (Expression child, Type return_type, Mode m)
1897 : base (child, return_type)
1902 public override Expression DoResolve (EmitContext ec)
1904 // This should never be invoked, we are born in fully
1905 // initialized state.
1910 public override string ToString ()
1912 return String.Format ("ConvCast ({0}, {1})", mode, child);
1915 public override void Emit (EmitContext ec)
1917 ILGenerator ig = ec.ig;
1923 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1924 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1925 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1926 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1927 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1929 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1930 case Mode.U1_CH: /* nothing */ break;
1932 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1933 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1934 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1935 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1936 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1937 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1939 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1940 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1941 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1942 case Mode.U2_CH: /* nothing */ break;
1944 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1945 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1946 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1947 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1948 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1949 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1950 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1952 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1953 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1954 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1955 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1956 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1957 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1959 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1960 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1961 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1962 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1963 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1964 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1965 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1966 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1968 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1969 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1970 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1971 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1972 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1973 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1974 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1975 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1977 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1978 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1979 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1981 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1982 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1983 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1984 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1985 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1986 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1987 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1988 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1989 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1991 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1992 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1993 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1994 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1995 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1996 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1997 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1998 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1999 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
2000 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
2004 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
2005 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
2006 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
2007 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
2008 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
2010 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
2011 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
2013 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
2014 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
2015 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
2016 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
2017 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
2018 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
2020 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
2021 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
2022 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
2023 case Mode.U2_CH: /* nothing */ break;
2025 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
2026 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
2027 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
2028 case Mode.I4_U4: /* nothing */ break;
2029 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
2030 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
2031 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
2033 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
2034 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
2035 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
2036 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
2037 case Mode.U4_I4: /* nothing */ break;
2038 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
2040 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
2041 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
2042 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
2043 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
2044 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
2045 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
2046 case Mode.I8_U8: /* nothing */ break;
2047 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
2049 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
2050 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
2051 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
2052 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
2053 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
2054 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
2055 case Mode.U8_I8: /* nothing */ break;
2056 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
2058 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
2059 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
2060 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
2062 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
2063 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
2064 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
2065 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
2066 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
2067 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
2068 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
2069 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
2070 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
2072 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
2073 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
2074 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
2075 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
2076 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
2077 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
2078 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
2079 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
2080 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
2081 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
2087 public class OpcodeCast : TypeCast {
2090 public OpcodeCast (Expression child, Type return_type, OpCode op)
2091 : base (child, return_type)
2096 public override Expression DoResolve (EmitContext ec)
2098 // This should never be invoked, we are born in fully
2099 // initialized state.
2104 public override void Emit (EmitContext ec)
2110 public Type UnderlyingType {
2111 get { return child.Type; }
2116 /// This kind of cast is used to encapsulate a child and cast it
2117 /// to the class requested
2119 public sealed class ClassCast : TypeCast {
2120 readonly bool forced;
2122 public ClassCast (Expression child, Type return_type)
2123 : base (child, return_type)
2127 public ClassCast (Expression child, Type return_type, bool forced)
2128 : base (child, return_type)
2130 this.forced = forced;
2133 public override void Emit (EmitContext ec)
2138 bool gen = TypeManager.IsGenericParameter (child.Type);
2140 ec.ig.Emit (OpCodes.Box, child.Type);
2142 if (type.IsGenericParameter) {
2143 ec.ig.Emit (OpCodes.Unbox_Any, type);
2151 ec.ig.Emit (OpCodes.Castclass, type);
2156 // Created during resolving pahse when an expression is wrapped or constantified
2157 // and original expression can be used later (e.g. for expression trees)
2159 public class ReducedExpression : Expression
2161 sealed class ReducedConstantExpression : EmptyConstantCast
2163 readonly Expression orig_expr;
2165 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2166 : base (expr, expr.Type)
2168 this.orig_expr = orig_expr;
2171 public override Constant ConvertImplicitly (Type target_type)
2173 Constant c = base.ConvertImplicitly (target_type);
2175 c = new ReducedConstantExpression (c, orig_expr);
2179 public override Expression CreateExpressionTree (EmitContext ec)
2181 return orig_expr.CreateExpressionTree (ec);
2184 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
2187 // Even if resolved result is a constant original expression was not
2188 // and attribute accepts constants only
2190 Attribute.Error_AttributeArgumentNotValid (orig_expr.Location);
2195 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
2197 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
2199 c = new ReducedConstantExpression (c, orig_expr);
2204 sealed class ReducedExpressionStatement : ExpressionStatement
2206 readonly Expression orig_expr;
2207 readonly ExpressionStatement stm;
2209 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
2211 this.orig_expr = orig;
2213 this.loc = orig.Location;
2216 public override Expression CreateExpressionTree (EmitContext ec)
2218 return orig_expr.CreateExpressionTree (ec);
2221 public override Expression DoResolve (EmitContext ec)
2223 eclass = stm.eclass;
2228 public override void Emit (EmitContext ec)
2233 public override void EmitStatement (EmitContext ec)
2235 stm.EmitStatement (ec);
2238 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2240 stm.MutateHoistedGenericType (storey);
2244 readonly Expression expr, orig_expr;
2246 private ReducedExpression (Expression expr, Expression orig_expr)
2249 this.orig_expr = orig_expr;
2250 this.loc = orig_expr.Location;
2253 public static Constant Create (Constant expr, Expression original_expr)
2255 return new ReducedConstantExpression (expr, original_expr);
2258 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
2260 return new ReducedExpressionStatement (s, orig);
2263 public static Expression Create (Expression expr, Expression original_expr)
2265 Constant c = expr as Constant;
2267 return Create (c, original_expr);
2269 ExpressionStatement s = expr as ExpressionStatement;
2271 return Create (s, original_expr);
2273 return new ReducedExpression (expr, original_expr);
2276 public override Expression CreateExpressionTree (EmitContext ec)
2278 return orig_expr.CreateExpressionTree (ec);
2281 public override Expression DoResolve (EmitContext ec)
2283 eclass = expr.eclass;
2288 public override void Emit (EmitContext ec)
2293 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2295 expr.EmitBranchable (ec, target, on_true);
2298 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2300 expr.MutateHoistedGenericType (storey);
2305 // Unresolved type name expressions
2307 public abstract class ATypeNameExpression : FullNamedExpression
2309 public readonly string Name;
2310 protected TypeArguments targs;
2312 protected ATypeNameExpression (string name, Location l)
2318 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2325 public bool HasTypeArguments {
2327 return targs != null;
2331 public override bool Equals (object obj)
2333 ATypeNameExpression atne = obj as ATypeNameExpression;
2334 return atne != null && atne.Name == Name &&
2335 (targs == null || targs.Equals (atne.targs));
2338 public override int GetHashCode ()
2340 return Name.GetHashCode ();
2343 public override string GetSignatureForError ()
2345 if (targs != null) {
2346 return TypeManager.RemoveGenericArity (Name) + "<" +
2347 targs.GetSignatureForError () + ">";
2355 /// SimpleName expressions are formed of a single word and only happen at the beginning
2356 /// of a dotted-name.
2358 public class SimpleName : ATypeNameExpression {
2361 public SimpleName (string name, Location l)
2366 public SimpleName (string name, TypeArguments args, Location l)
2367 : base (name, args, l)
2371 public SimpleName (string name, TypeParameter[] type_params, Location l)
2374 targs = new TypeArguments ();
2375 foreach (TypeParameter type_param in type_params)
2376 targs.Add (new TypeParameterExpr (type_param, l));
2379 public static string RemoveGenericArity (string name)
2382 StringBuilder sb = null;
2384 int pos = name.IndexOf ('`', start);
2389 sb.Append (name.Substring (start));
2394 sb = new StringBuilder ();
2395 sb.Append (name.Substring (start, pos-start));
2398 while ((pos < name.Length) && Char.IsNumber (name [pos]))
2402 } while (start < name.Length);
2404 return sb.ToString ();
2407 public SimpleName GetMethodGroup ()
2409 return new SimpleName (RemoveGenericArity (Name), targs, loc);
2412 public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
2414 if (ec.IsInFieldInitializer)
2415 Report.Error (236, l,
2416 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2419 Report.Error (120, l,
2420 "An object reference is required to access non-static member `{0}'",
2424 public bool IdenticalNameAndTypeName (EmitContext ec, Expression resolved_to, Location loc)
2426 return resolved_to != null && resolved_to.Type != null &&
2427 resolved_to.Type.Name == Name &&
2428 (ec.DeclContainer.LookupNamespaceOrType (Name, loc, /* ignore_cs0104 = */ true) != null);
2431 public override Expression DoResolve (EmitContext ec)
2433 return SimpleNameResolve (ec, null, false);
2436 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
2438 return SimpleNameResolve (ec, right_side, false);
2442 public Expression DoResolve (EmitContext ec, bool intermediate)
2444 return SimpleNameResolve (ec, null, intermediate);
2447 static bool IsNestedChild (Type t, Type parent)
2449 while (parent != null) {
2450 if (TypeManager.IsNestedChildOf (t, TypeManager.DropGenericTypeArguments (parent)))
2453 parent = parent.BaseType;
2459 FullNamedExpression ResolveNested (IResolveContext ec, Type t)
2461 if (!TypeManager.IsGenericTypeDefinition (t) && !TypeManager.IsGenericType (t))
2464 DeclSpace ds = ec.DeclContainer;
2465 while (ds != null && !IsNestedChild (t, ds.TypeBuilder))
2471 Type[] gen_params = TypeManager.GetTypeArguments (t);
2473 int arg_count = targs != null ? targs.Count : 0;
2475 for (; (ds != null) && ds.IsGeneric; ds = ds.Parent) {
2476 if (arg_count + ds.CountTypeParameters == gen_params.Length) {
2477 TypeArguments new_args = new TypeArguments ();
2478 foreach (TypeParameter param in ds.TypeParameters)
2479 new_args.Add (new TypeParameterExpr (param, loc));
2482 new_args.Add (targs);
2484 return new GenericTypeExpr (t, new_args, loc);
2491 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2493 FullNamedExpression fne = ec.GenericDeclContainer.LookupGeneric (Name, loc);
2495 return fne.ResolveAsTypeStep (ec, silent);
2497 int errors = Report.Errors;
2498 fne = ec.DeclContainer.LookupNamespaceOrType (Name, loc, /*ignore_cs0104=*/ false);
2501 if (fne.Type == null)
2504 FullNamedExpression nested = ResolveNested (ec, fne.Type);
2506 return nested.ResolveAsTypeStep (ec, false);
2508 if (targs != null) {
2509 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2510 return ct.ResolveAsTypeStep (ec, false);
2516 if (silent || errors != Report.Errors)
2519 Error_TypeOrNamespaceNotFound (ec);
2523 protected virtual void Error_TypeOrNamespaceNotFound (IResolveContext ec)
2525 MemberCore mc = ec.DeclContainer.GetDefinition (Name);
2527 Error_UnexpectedKind (ec.DeclContainer, "type", GetMemberType (mc), loc);
2531 string ns = ec.DeclContainer.NamespaceEntry.NS.Name;
2532 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2533 foreach (Assembly a in GlobalRootNamespace.Instance.Assemblies) {
2534 Type type = a.GetType (fullname);
2536 Report.SymbolRelatedToPreviousError (type);
2537 Expression.ErrorIsInaccesible (loc, TypeManager.CSharpName (type));
2542 Type t = ec.DeclContainer.LookupAnyGeneric (Name);
2544 Namespace.Error_InvalidNumberOfTypeArguments (t, loc);
2548 if (targs != null) {
2549 FullNamedExpression retval = ec.DeclContainer.LookupNamespaceOrType (SimpleName.RemoveGenericArity (Name), loc, true);
2550 if (retval != null) {
2551 Namespace.Error_TypeArgumentsCannotBeUsed (retval, loc);
2556 NamespaceEntry.Error_NamespaceNotFound (loc, Name);
2559 // TODO: I am still not convinced about this. If someone else will need it
2560 // implement this as virtual property in MemberCore hierarchy
2561 public static string GetMemberType (MemberCore mc)
2567 if (mc is FieldBase)
2569 if (mc is MethodCore)
2571 if (mc is EnumMember)
2579 Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2585 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2591 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2598 /// 7.5.2: Simple Names.
2600 /// Local Variables and Parameters are handled at
2601 /// parse time, so they never occur as SimpleNames.
2603 /// The `intermediate' flag is used by MemberAccess only
2604 /// and it is used to inform us that it is ok for us to
2605 /// avoid the static check, because MemberAccess might end
2606 /// up resolving the Name as a Type name and the access as
2607 /// a static type access.
2609 /// ie: Type Type; .... { Type.GetType (""); }
2611 /// Type is both an instance variable and a Type; Type.GetType
2612 /// is the static method not an instance method of type.
2614 Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2616 Expression e = null;
2619 // Stage 1: Performed by the parser (binding to locals or parameters).
2621 Block current_block = ec.CurrentBlock;
2622 if (current_block != null){
2623 LocalInfo vi = current_block.GetLocalInfo (Name);
2625 LocalVariableReference var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2626 if (right_side != null) {
2627 return var.ResolveLValue (ec, right_side);
2629 ResolveFlags rf = ResolveFlags.VariableOrValue;
2631 rf |= ResolveFlags.DisableFlowAnalysis;
2632 return var.Resolve (ec, rf);
2636 Expression expr = current_block.Toplevel.GetParameterReference (Name, loc);
2638 if (right_side != null)
2639 return expr.ResolveLValue (ec, right_side);
2641 return expr.Resolve (ec);
2646 // Stage 2: Lookup members
2649 Type almost_matched_type = null;
2650 ArrayList almost_matched = null;
2651 for (DeclSpace lookup_ds = ec.DeclContainer; lookup_ds != null; lookup_ds = lookup_ds.Parent) {
2652 // either RootDeclSpace or GenericMethod
2653 if (lookup_ds.TypeBuilder == null)
2656 e = MemberLookup (ec.ContainerType, lookup_ds.TypeBuilder, Name, loc);
2658 PropertyExpr pe = e as PropertyExpr;
2660 AParametersCollection param = TypeManager.GetParameterData (pe.PropertyInfo);
2662 // since TypeManager.MemberLookup doesn't know if we're doing a lvalue access or not,
2663 // it doesn't know which accessor to check permissions against
2664 if (param.IsEmpty && pe.IsAccessibleFrom (ec.ContainerType, right_side != null))
2666 } else if (e is EventExpr) {
2667 if (((EventExpr) e).IsAccessibleFrom (ec.ContainerType))
2669 } else if (targs != null && e is TypeExpression) {
2670 e = new GenericTypeExpr (e.Type, targs, loc).ResolveAsTypeStep (ec, false);
2678 if (almost_matched == null && almost_matched_members.Count > 0) {
2679 almost_matched_type = lookup_ds.TypeBuilder;
2680 almost_matched = (ArrayList) almost_matched_members.Clone ();
2685 if (almost_matched == null && almost_matched_members.Count > 0) {
2686 almost_matched_type = ec.ContainerType;
2687 almost_matched = (ArrayList) almost_matched_members.Clone ();
2689 e = ResolveAsTypeStep (ec, true);
2693 if (current_block != null) {
2694 IKnownVariable ikv = current_block.Explicit.GetKnownVariable (Name);
2696 LocalInfo li = ikv as LocalInfo;
2697 // Supress CS0219 warning
2701 Error_VariableIsUsedBeforeItIsDeclared (Name);
2706 if (RootContext.EvalMode){
2707 FieldInfo fi = Evaluator.LookupField (Name);
2709 return new FieldExpr (fi, loc).Resolve (ec);
2712 if (almost_matched != null)
2713 almost_matched_members = almost_matched;
2714 if (almost_matched_type == null)
2715 almost_matched_type = ec.ContainerType;
2716 return Error_MemberLookupFailed (ec.ContainerType, null, almost_matched_type, Name,
2717 ec.DeclContainer.Name, AllMemberTypes, AllBindingFlags);
2720 if (e is MemberExpr) {
2721 MemberExpr me = (MemberExpr) e;
2724 if (me.IsInstance) {
2725 if (ec.IsStatic || ec.IsInFieldInitializer) {
2727 // Note that an MemberExpr can be both IsInstance and IsStatic.
2728 // An unresolved MethodGroupExpr can contain both kinds of methods
2729 // and each predicate is true if the MethodGroupExpr contains
2730 // at least one of that kind of method.
2734 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2735 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2740 // Pass the buck to MemberAccess and Invocation.
2742 left = EmptyExpression.Null;
2744 left = ec.GetThis (loc);
2747 left = new TypeExpression (ec.ContainerType, loc);
2750 me = me.ResolveMemberAccess (ec, left, loc, null);
2754 if (targs != null) {
2755 if (!targs.Resolve (ec))
2758 me.SetTypeArguments (targs);
2761 if (!me.IsStatic && (me.InstanceExpression != null && me.InstanceExpression != EmptyExpression.Null) &&
2762 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2763 me.InstanceExpression.Type != me.DeclaringType &&
2764 !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2765 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2766 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2767 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2771 return (right_side != null)
2772 ? me.DoResolveLValue (ec, right_side)
2773 : me.DoResolve (ec);
2781 /// Represents a namespace or a type. The name of the class was inspired by
2782 /// section 10.8.1 (Fully Qualified Names).
2784 public abstract class FullNamedExpression : Expression
2786 protected override void CloneTo (CloneContext clonectx, Expression target)
2788 // Do nothing, most unresolved type expressions cannot be
2789 // resolved to different type
2792 public override Expression CreateExpressionTree (EmitContext ec)
2794 throw new NotSupportedException ("ET");
2797 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2799 throw new NotSupportedException ();
2802 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2807 public override void Emit (EmitContext ec)
2809 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2810 GetSignatureForError ());
2815 /// Expression that evaluates to a type
2817 public abstract class TypeExpr : FullNamedExpression {
2818 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2820 TypeExpr t = DoResolveAsTypeStep (ec);
2824 eclass = ExprClass.Type;
2828 override public Expression DoResolve (EmitContext ec)
2830 return ResolveAsTypeTerminal (ec, false);
2833 public virtual bool CheckAccessLevel (DeclSpace ds)
2835 return ds.CheckAccessLevel (Type);
2838 public virtual bool IsClass {
2839 get { return Type.IsClass; }
2842 public virtual bool IsValueType {
2843 get { return TypeManager.IsStruct (Type); }
2846 public virtual bool IsInterface {
2847 get { return Type.IsInterface; }
2850 public virtual bool IsSealed {
2851 get { return Type.IsSealed; }
2854 public virtual bool CanInheritFrom ()
2856 if (Type == TypeManager.enum_type ||
2857 (Type == TypeManager.value_type && RootContext.StdLib) ||
2858 Type == TypeManager.multicast_delegate_type ||
2859 Type == TypeManager.delegate_type ||
2860 Type == TypeManager.array_type)
2866 protected abstract TypeExpr DoResolveAsTypeStep (IResolveContext ec);
2868 public override bool Equals (object obj)
2870 TypeExpr tobj = obj as TypeExpr;
2874 return Type == tobj.Type;
2877 public override int GetHashCode ()
2879 return Type.GetHashCode ();
2882 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2884 type = storey.MutateType (type);
2889 /// Fully resolved Expression that already evaluated to a type
2891 public class TypeExpression : TypeExpr {
2892 public TypeExpression (Type t, Location l)
2895 eclass = ExprClass.Type;
2899 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2904 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2911 // Used to create types from a fully qualified name. These are just used
2912 // by the parser to setup the core types.
2914 public sealed class TypeLookupExpression : TypeExpr {
2915 readonly string ns_name;
2916 readonly string name;
2918 public TypeLookupExpression (string ns, string name)
2922 eclass = ExprClass.Type;
2925 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2928 // It's null only during mscorlib bootstrap when DefineType
2929 // nees to resolve base type of same type
2931 // For instance struct Char : IComparable<char>
2933 // TODO: it could be removed when Resolve starts to use
2934 // DeclSpace instead of Type
2937 Namespace ns = GlobalRootNamespace.Instance.GetNamespace (ns_name, false);
2938 FullNamedExpression fne = ns.Lookup (null, name, loc);
2946 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2951 public override string GetSignatureForError ()
2954 return TypeManager.CSharpName (ns_name + "." + name, null);
2956 return base.GetSignatureForError ();
2961 /// This class denotes an expression which evaluates to a member
2962 /// of a struct or a class.
2964 public abstract class MemberExpr : Expression
2966 protected bool is_base;
2969 /// The name of this member.
2971 public abstract string Name {
2976 // When base.member is used
2978 public bool IsBase {
2979 get { return is_base; }
2980 set { is_base = value; }
2984 /// Whether this is an instance member.
2986 public abstract bool IsInstance {
2991 /// Whether this is a static member.
2993 public abstract bool IsStatic {
2998 /// The type which declares this member.
3000 public abstract Type DeclaringType {
3005 /// The instance expression associated with this member, if it's a
3006 /// non-static member.
3008 public Expression InstanceExpression;
3010 public static void error176 (Location loc, string name)
3012 Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
3013 "with an instance reference, qualify it with a type name instead", name);
3016 public static void Error_BaseAccessInExpressionTree (Location loc)
3018 Report.Error (831, loc, "An expression tree may not contain a base access");
3021 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3023 if (InstanceExpression != null)
3024 InstanceExpression.MutateHoistedGenericType (storey);
3027 // TODO: possible optimalization
3028 // Cache resolved constant result in FieldBuilder <-> expression map
3029 public virtual MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3030 SimpleName original)
3034 // original == null || original.Resolve (...) ==> left
3037 if (left is TypeExpr) {
3038 left = left.ResolveAsBaseTerminal (ec, false);
3042 // TODO: Same problem as in class.cs, TypeTerminal does not
3043 // always do all necessary checks
3044 ObsoleteAttribute oa = AttributeTester.GetObsoleteAttribute (left.Type);
3045 if (oa != null && !ec.IsInObsoleteScope) {
3046 AttributeTester.Report_ObsoleteMessage (oa, left.GetSignatureForError (), loc);
3049 GenericTypeExpr ct = left as GenericTypeExpr;
3050 if (ct != null && !ct.CheckConstraints (ec))
3055 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3063 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3066 return ResolveExtensionMemberAccess (left);
3069 InstanceExpression = left;
3073 protected virtual MemberExpr ResolveExtensionMemberAccess (Expression left)
3075 error176 (loc, GetSignatureForError ());
3079 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3084 if (InstanceExpression == EmptyExpression.Null) {
3085 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3089 if (TypeManager.IsValueType (InstanceExpression.Type)) {
3090 if (InstanceExpression is IMemoryLocation) {
3091 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
3093 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
3094 InstanceExpression.Emit (ec);
3096 t.AddressOf (ec, AddressOp.Store);
3099 InstanceExpression.Emit (ec);
3101 if (prepare_for_load)
3102 ec.ig.Emit (OpCodes.Dup);
3105 public virtual void SetTypeArguments (TypeArguments ta)
3107 // TODO: need to get correct member type
3108 Report.Error (307, loc, "The property `{0}' cannot be used with type arguments",
3109 GetSignatureForError ());
3114 /// Represents group of extension methods
3116 public class ExtensionMethodGroupExpr : MethodGroupExpr
3118 readonly NamespaceEntry namespace_entry;
3119 public Expression ExtensionExpression;
3120 Argument extension_argument;
3122 public ExtensionMethodGroupExpr (ArrayList list, NamespaceEntry n, Type extensionType, Location l)
3123 : base (list, extensionType, l)
3125 this.namespace_entry = n;
3128 public override bool IsStatic {
3129 get { return true; }
3132 public bool IsTopLevel {
3133 get { return namespace_entry == null; }
3136 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3138 extension_argument.Expr.MutateHoistedGenericType (storey);
3139 base.MutateHoistedGenericType (storey);
3142 public override MethodGroupExpr OverloadResolve (EmitContext ec, ref Arguments arguments, bool may_fail, Location loc)
3144 if (arguments == null)
3145 arguments = new Arguments (1);
3147 arguments.Insert (0, new Argument (ExtensionExpression));
3148 MethodGroupExpr mg = ResolveOverloadExtensions (ec, ref arguments, namespace_entry, loc);
3150 // Store resolved argument and restore original arguments
3152 ((ExtensionMethodGroupExpr)mg).extension_argument = arguments [0];
3154 arguments.RemoveAt (0); // Clean-up modified arguments for error reporting
3159 MethodGroupExpr ResolveOverloadExtensions (EmitContext ec, ref Arguments arguments, NamespaceEntry ns, Location loc)
3161 // Use normal resolve rules
3162 MethodGroupExpr mg = base.OverloadResolve (ec, ref arguments, ns != null, loc);
3170 ExtensionMethodGroupExpr e = ns.LookupExtensionMethod (type, null, Name, loc);
3172 return base.OverloadResolve (ec, ref arguments, false, loc);
3174 e.ExtensionExpression = ExtensionExpression;
3175 e.SetTypeArguments (type_arguments);
3176 return e.ResolveOverloadExtensions (ec, ref arguments, e.namespace_entry, loc);
3181 /// MethodGroupExpr represents a group of method candidates which
3182 /// can be resolved to the best method overload
3184 public class MethodGroupExpr : MemberExpr
3186 public interface IErrorHandler
3188 bool AmbiguousCall (MethodBase ambiguous);
3189 bool NoExactMatch (EmitContext ec, MethodBase method);
3192 public IErrorHandler CustomErrorHandler;
3193 public MethodBase [] Methods;
3194 MethodBase best_candidate;
3195 // TODO: make private
3196 public TypeArguments type_arguments;
3197 bool identical_type_name;
3198 bool has_inaccessible_candidates_only;
3202 public MethodGroupExpr (MemberInfo [] mi, Type type, Location l)
3205 Methods = new MethodBase [mi.Length];
3206 mi.CopyTo (Methods, 0);
3209 public MethodGroupExpr (MemberInfo[] mi, Type type, Location l, bool inacessibleCandidatesOnly)
3210 : this (mi, type, l)
3212 has_inaccessible_candidates_only = inacessibleCandidatesOnly;
3215 public MethodGroupExpr (ArrayList list, Type type, Location l)
3219 Methods = (MethodBase[])list.ToArray (typeof (MethodBase));
3221 foreach (MemberInfo m in list){
3222 if (!(m is MethodBase)){
3223 Console.WriteLine ("Name " + m.Name);
3224 Console.WriteLine ("Found a: " + m.GetType ().FullName);
3233 protected MethodGroupExpr (Type type, Location loc)
3236 eclass = ExprClass.MethodGroup;
3237 this.type = InternalType.MethodGroup;
3238 queried_type = type;
3241 public override Type DeclaringType {
3243 return queried_type;
3247 public Type DelegateType {
3249 delegate_type = value;
3253 public bool IdenticalTypeName {
3255 return identical_type_name;
3259 public override string GetSignatureForError ()
3261 if (best_candidate != null)
3262 return TypeManager.CSharpSignature (best_candidate);
3264 return TypeManager.CSharpSignature (Methods [0]);
3267 public override string Name {
3269 return Methods [0].Name;
3273 public override bool IsInstance {
3275 if (best_candidate != null)
3276 return !best_candidate.IsStatic;
3278 foreach (MethodBase mb in Methods)
3286 public override bool IsStatic {
3288 if (best_candidate != null)
3289 return best_candidate.IsStatic;
3291 foreach (MethodBase mb in Methods)
3299 public static explicit operator ConstructorInfo (MethodGroupExpr mg)
3301 return (ConstructorInfo)mg.best_candidate;
3304 public static explicit operator MethodInfo (MethodGroupExpr mg)
3306 return (MethodInfo)mg.best_candidate;
3310 // 7.4.3.3 Better conversion from expression
3311 // Returns : 1 if a->p is better,
3312 // 2 if a->q is better,
3313 // 0 if neither is better
3315 static int BetterExpressionConversion (EmitContext ec, Argument a, Type p, Type q)
3317 Type argument_type = TypeManager.TypeToCoreType (a.Type);
3318 if (argument_type == InternalType.AnonymousMethod && RootContext.Version > LanguageVersion.ISO_2) {
3320 // Uwrap delegate from Expression<T>
3322 if (TypeManager.DropGenericTypeArguments (p) == TypeManager.expression_type) {
3323 p = TypeManager.GetTypeArguments (p) [0];
3325 if (TypeManager.DropGenericTypeArguments (q) == TypeManager.expression_type) {
3326 q = TypeManager.GetTypeArguments (q) [0];
3329 p = Delegate.GetInvokeMethod (null, p).ReturnType;
3330 q = Delegate.GetInvokeMethod (null, q).ReturnType;
3331 if (p == TypeManager.void_type && q != TypeManager.void_type)
3333 if (q == TypeManager.void_type && p != TypeManager.void_type)
3336 if (argument_type == p)
3339 if (argument_type == q)
3343 return BetterTypeConversion (ec, p, q);
3347 // 7.4.3.4 Better conversion from type
3349 public static int BetterTypeConversion (EmitContext ec, Type p, Type q)
3351 if (p == null || q == null)
3352 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3354 if (p == TypeManager.int32_type) {
3355 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3357 } else if (p == TypeManager.int64_type) {
3358 if (q == TypeManager.uint64_type)
3360 } else if (p == TypeManager.sbyte_type) {
3361 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3362 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3364 } else if (p == TypeManager.short_type) {
3365 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3366 q == TypeManager.uint64_type)
3370 if (q == TypeManager.int32_type) {
3371 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3373 } if (q == TypeManager.int64_type) {
3374 if (p == TypeManager.uint64_type)
3376 } else if (q == TypeManager.sbyte_type) {
3377 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3378 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3380 } if (q == TypeManager.short_type) {
3381 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3382 p == TypeManager.uint64_type)
3386 // TODO: this is expensive
3387 Expression p_tmp = new EmptyExpression (p);
3388 Expression q_tmp = new EmptyExpression (q);
3390 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3391 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3393 if (p_to_q && !q_to_p)
3396 if (q_to_p && !p_to_q)
3403 /// Determines "Better function" between candidate
3404 /// and the current best match
3407 /// Returns a boolean indicating :
3408 /// false if candidate ain't better
3409 /// true if candidate is better than the current best match
3411 static bool BetterFunction (EmitContext ec, Arguments args, int argument_count,
3412 MethodBase candidate, bool candidate_params,
3413 MethodBase best, bool best_params)
3415 AParametersCollection candidate_pd = TypeManager.GetParameterData (candidate);
3416 AParametersCollection best_pd = TypeManager.GetParameterData (best);
3418 bool better_at_least_one = false;
3420 for (int j = 0, c_idx = 0, b_idx = 0; j < argument_count; ++j, ++c_idx, ++b_idx)
3422 Argument a = args [j];
3424 // Provided default argument value is never better
3425 if (a.IsDefaultArgument && candidate_params == best_params)
3428 Type ct = candidate_pd.Types [c_idx];
3429 Type bt = best_pd.Types [b_idx];
3431 if (candidate_params && candidate_pd.FixedParameters [c_idx].ModFlags == Parameter.Modifier.PARAMS)
3433 ct = TypeManager.GetElementType (ct);
3437 if (best_params && best_pd.FixedParameters [b_idx].ModFlags == Parameter.Modifier.PARAMS)
3439 bt = TypeManager.GetElementType (bt);
3447 int result = BetterExpressionConversion (ec, a, ct, bt);
3449 // for each argument, the conversion to 'ct' should be no worse than
3450 // the conversion to 'bt'.
3454 // for at least one argument, the conversion to 'ct' should be better than
3455 // the conversion to 'bt'.
3457 better_at_least_one = true;
3460 if (better_at_least_one)
3464 // This handles the case
3466 // Add (float f1, float f2, float f3);
3467 // Add (params decimal [] foo);
3469 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3470 // first candidate would've chosen as better.
3476 // The two methods have equal parameter types. Now apply tie-breaking rules
3478 if (TypeManager.IsGenericMethod (best)) {
3479 if (!TypeManager.IsGenericMethod (candidate))
3481 } else if (TypeManager.IsGenericMethod (candidate)) {
3486 // This handles the following cases:
3488 // Trim () is better than Trim (params char[] chars)
3489 // Concat (string s1, string s2, string s3) is better than
3490 // Concat (string s1, params string [] srest)
3491 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3493 if (!candidate_params && best_params)
3495 if (candidate_params && !best_params)
3498 int candidate_param_count = candidate_pd.Count;
3499 int best_param_count = best_pd.Count;
3501 if (candidate_param_count != best_param_count)
3502 // can only happen if (candidate_params && best_params)
3503 return candidate_param_count > best_param_count && best_pd.HasParams;
3506 // now, both methods have the same number of parameters, and the parameters have the same types
3507 // Pick the "more specific" signature
3510 MethodBase orig_candidate = TypeManager.DropGenericMethodArguments (candidate);
3511 MethodBase orig_best = TypeManager.DropGenericMethodArguments (best);
3513 AParametersCollection orig_candidate_pd = TypeManager.GetParameterData (orig_candidate);
3514 AParametersCollection orig_best_pd = TypeManager.GetParameterData (orig_best);
3516 bool specific_at_least_once = false;
3517 for (int j = 0; j < candidate_param_count; ++j)
3519 Type ct = orig_candidate_pd.Types [j];
3520 Type bt = orig_best_pd.Types [j];
3523 Type specific = MoreSpecific (ct, bt);
3527 specific_at_least_once = true;
3530 if (specific_at_least_once)
3533 // FIXME: handle lifted operators
3539 protected override MemberExpr ResolveExtensionMemberAccess (Expression left)
3542 return base.ResolveExtensionMemberAccess (left);
3545 // When left side is an expression and at least one candidate method is
3546 // static, it can be extension method
3548 InstanceExpression = left;
3552 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3553 SimpleName original)
3555 if (!(left is TypeExpr) &&
3556 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3557 identical_type_name = true;
3559 return base.ResolveMemberAccess (ec, left, loc, original);
3562 public override Expression CreateExpressionTree (EmitContext ec)
3564 if (best_candidate == null) {
3565 Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3569 if (best_candidate.IsConstructor)
3570 return new TypeOfConstructorInfo (best_candidate, loc);
3572 IMethodData md = TypeManager.GetMethod (best_candidate);
3573 if (md != null && md.IsExcluded ())
3574 Report.Error (765, loc,
3575 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3577 return new TypeOfMethodInfo (best_candidate, loc);
3580 override public Expression DoResolve (EmitContext ec)
3582 if (InstanceExpression != null) {
3583 InstanceExpression = InstanceExpression.DoResolve (ec);
3584 if (InstanceExpression == null)
3591 public void ReportUsageError ()
3593 Report.Error (654, loc, "Method `" + DeclaringType + "." +
3594 Name + "()' is referenced without parentheses");
3597 override public void Emit (EmitContext ec)
3599 ReportUsageError ();
3602 public void EmitCall (EmitContext ec, Arguments arguments)
3604 Invocation.EmitCall (ec, IsBase, InstanceExpression, best_candidate, arguments, loc);
3607 void Error_AmbiguousCall (MethodBase ambiguous)
3609 if (CustomErrorHandler != null && CustomErrorHandler.AmbiguousCall (ambiguous))
3612 Report.SymbolRelatedToPreviousError (best_candidate);
3613 Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
3614 TypeManager.CSharpSignature (ambiguous), TypeManager.CSharpSignature (best_candidate));
3617 protected virtual void Error_InvalidArguments (EmitContext ec, Location loc, int idx, MethodBase method,
3618 Argument a, AParametersCollection expected_par, Type paramType)
3620 ExtensionMethodGroupExpr emg = this as ExtensionMethodGroupExpr;
3622 if (a is CollectionElementInitializer.ElementInitializerArgument) {
3623 Report.SymbolRelatedToPreviousError (method);
3624 if ((expected_par.FixedParameters [idx].ModFlags & Parameter.Modifier.ISBYREF) != 0) {
3625 Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
3626 TypeManager.CSharpSignature (method));
3629 Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
3630 TypeManager.CSharpSignature (method));
3631 } else if (TypeManager.IsDelegateType (method.DeclaringType)) {
3632 Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
3633 TypeManager.CSharpName (method.DeclaringType));
3635 Report.SymbolRelatedToPreviousError (method);
3637 Report.Error (1928, loc,
3638 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3639 emg.ExtensionExpression.GetSignatureForError (),
3640 emg.Name, TypeManager.CSharpSignature (method));
3642 Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
3643 TypeManager.CSharpSignature (method));
3647 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters [idx].ModFlags;
3649 string index = (idx + 1).ToString ();
3650 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
3651 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
3652 if ((mod & Parameter.Modifier.ISBYREF) == 0)
3653 Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
3654 index, Parameter.GetModifierSignature (a.Modifier));
3656 Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
3657 index, Parameter.GetModifierSignature (mod));
3659 string p1 = a.GetSignatureForError ();
3660 string p2 = TypeManager.CSharpName (paramType);
3663 Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
3664 Report.SymbolRelatedToPreviousError (a.Expr.Type);
3665 Report.SymbolRelatedToPreviousError (paramType);
3668 if (idx == 0 && emg != null) {
3669 Report.Error (1929, loc,
3670 "Extension method instance type `{0}' cannot be converted to `{1}'", p1, p2);
3672 Report.Error (1503, loc,
3673 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
3678 public override void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl)
3680 Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3681 Name, TypeManager.CSharpName (target));
3684 void Error_ArgumentCountWrong (int arg_count)
3686 Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
3687 Name, arg_count.ToString ());
3690 protected virtual int GetApplicableParametersCount (MethodBase method, AParametersCollection parameters)
3692 return parameters.Count;
3695 public static bool IsAncestralType (Type first_type, Type second_type)
3697 return first_type != second_type &&
3698 (TypeManager.IsSubclassOf (second_type, first_type) ||
3699 TypeManager.ImplementsInterface (second_type, first_type));
3703 /// Determines if the candidate method is applicable (section 14.4.2.1)
3704 /// to the given set of arguments
3705 /// A return value rates candidate method compatibility,
3706 /// 0 = the best, int.MaxValue = the worst
3708 public int IsApplicable (EmitContext ec,
3709 ref Arguments arguments, int arg_count, ref MethodBase method, ref bool params_expanded_form)
3711 MethodBase candidate = method;
3713 AParametersCollection pd = TypeManager.GetParameterData (candidate);
3714 int param_count = GetApplicableParametersCount (candidate, pd);
3715 int optional_count = 0;
3717 if (arg_count != param_count) {
3718 for (int i = 0; i < pd.Count; ++i) {
3719 if (pd.FixedParameters [i].HasDefaultValue) {
3720 optional_count = pd.Count - i;
3725 int args_gap = Math.Abs (arg_count - param_count);
3726 if (optional_count != 0) {
3727 if (args_gap > optional_count)
3728 return int.MaxValue - 10000 + args_gap - optional_count;
3730 // Readjust expected number when params used
3733 if (arg_count < param_count)
3736 } else if (arg_count != param_count) {
3738 return int.MaxValue - 10000 + args_gap;
3739 if (arg_count < param_count - 1)
3740 return int.MaxValue - 10000 + args_gap;
3743 // Initialize expanded form of a method with 1 params parameter
3744 params_expanded_form = param_count == 1 && pd.HasParams;
3746 // Resize to fit optional arguments
3747 if (optional_count != 0) {
3749 if (arguments == null) {
3750 resized = new Arguments (optional_count);
3752 resized = new Arguments (param_count);
3753 resized.AddRange (arguments);
3756 for (int i = arg_count; i < param_count; ++i)
3758 arguments = resized;
3762 if (arg_count > 0) {
3764 // Shuffle named arguments to the right positions if there are any
3766 if (arguments [arg_count - 1] is NamedArgument) {
3767 arg_count = arguments.Count;
3769 for (int i = 0; i < arg_count; ++i) {
3770 bool arg_moved = false;
3772 NamedArgument na = arguments[i] as NamedArgument;
3776 int index = pd.GetParameterIndexByName (na.Name.Value);
3778 // Named parameter not found or already reordered
3782 // When using parameters which should not be available to the user
3783 if (index >= param_count)
3787 arguments.MarkReorderedArgument (na);
3791 Argument temp = arguments[index];
3792 arguments[index] = arguments[i];
3793 arguments[i] = temp;
3800 arg_count = arguments.Count;
3802 } else if (arguments != null) {
3803 arg_count = arguments.Count;
3808 // 1. Handle generic method using type arguments when specified or type inference
3810 if (TypeManager.IsGenericMethod (candidate)) {
3811 if (type_arguments != null) {
3812 Type [] g_args = candidate.GetGenericArguments ();
3813 if (g_args.Length != type_arguments.Count)
3814 return int.MaxValue - 20000 + Math.Abs (type_arguments.Count - g_args.Length);
3816 // TODO: Don't create new method, create Parameters only
3817 method = ((MethodInfo) candidate).MakeGenericMethod (type_arguments.Arguments);
3819 pd = TypeManager.GetParameterData (candidate);
3821 int score = TypeManager.InferTypeArguments (ec, arguments, ref candidate);
3823 return score - 20000;
3825 if (TypeManager.IsGenericMethodDefinition (candidate))
3826 throw new InternalErrorException ("A generic method `{0}' definition took part in overload resolution",
3827 TypeManager.CSharpSignature (candidate));
3829 pd = TypeManager.GetParameterData (candidate);
3832 if (type_arguments != null)
3833 return int.MaxValue - 15000;
3838 // 2. Each argument has to be implicitly convertible to method parameter
3841 Parameter.Modifier p_mod = 0;
3843 for (int i = 0; i < arg_count; i++) {
3844 Argument a = arguments [i];
3846 if (!pd.FixedParameters [i].HasDefaultValue)
3847 throw new InternalErrorException ();
3849 Expression e = pd.FixedParameters [i].DefaultValue as Constant;
3851 e = new DefaultValueExpression (new TypeExpression (pd.Types [i], loc), loc).Resolve (ec);
3853 arguments [i] = new Argument (e, Argument.AType.Default);
3857 if (p_mod != Parameter.Modifier.PARAMS) {
3858 p_mod = pd.FixedParameters [i].ModFlags & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3861 params_expanded_form = true;
3864 Parameter.Modifier a_mod = a.Modifier & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3866 if (!params_expanded_form)
3867 score = IsArgumentCompatible (ec, a_mod, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
3869 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && delegate_type == null) {
3870 // It can be applicable in expanded form
3871 score = IsArgumentCompatible (ec, a_mod, a, 0, TypeManager.GetElementType (pt));
3873 params_expanded_form = true;
3877 if (params_expanded_form)
3879 return (arg_count - i) * 2 + score;
3883 if (arg_count != param_count)
3884 params_expanded_form = true;
3889 int IsArgumentCompatible (EmitContext ec, Parameter.Modifier arg_mod, Argument argument, Parameter.Modifier param_mod, Type parameter)
3892 // Types have to be identical when ref or out modifer is used
3894 if (arg_mod != 0 || param_mod != 0) {
3895 if (TypeManager.HasElementType (parameter))
3896 parameter = TypeManager.GetElementType (parameter);
3898 Type a_type = argument.Type;
3899 if (TypeManager.HasElementType (a_type))
3900 a_type = TypeManager.GetElementType (a_type);
3902 if (a_type != parameter)
3905 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter))
3909 if (arg_mod != param_mod)
3915 public static bool IsOverride (MethodBase cand_method, MethodBase base_method)
3917 if (!IsAncestralType (base_method.DeclaringType, cand_method.DeclaringType))
3920 AParametersCollection cand_pd = TypeManager.GetParameterData (cand_method);
3921 AParametersCollection base_pd = TypeManager.GetParameterData (base_method);
3923 if (cand_pd.Count != base_pd.Count)
3926 for (int j = 0; j < cand_pd.Count; ++j)
3928 Parameter.Modifier cm = cand_pd.FixedParameters [j].ModFlags;
3929 Parameter.Modifier bm = base_pd.FixedParameters [j].ModFlags;
3930 Type ct = cand_pd.Types [j];
3931 Type bt = base_pd.Types [j];
3933 if (cm != bm || ct != bt)
3940 public static MethodGroupExpr MakeUnionSet (MethodGroupExpr mg1, MethodGroupExpr mg2, Location loc)
3951 ArrayList all = new ArrayList (mg1.Methods);
3952 foreach (MethodBase m in mg2.Methods){
3953 if (!TypeManager.ArrayContainsMethod (mg1.Methods, m, false))
3957 return new MethodGroupExpr (all, null, loc);
3960 static Type MoreSpecific (Type p, Type q)
3962 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
3964 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
3967 if (TypeManager.HasElementType (p))
3969 Type pe = TypeManager.GetElementType (p);
3970 Type qe = TypeManager.GetElementType (q);
3971 Type specific = MoreSpecific (pe, qe);
3977 else if (TypeManager.IsGenericType (p))
3979 Type[] pargs = TypeManager.GetTypeArguments (p);
3980 Type[] qargs = TypeManager.GetTypeArguments (q);
3982 bool p_specific_at_least_once = false;
3983 bool q_specific_at_least_once = false;
3985 for (int i = 0; i < pargs.Length; i++)
3987 Type specific = MoreSpecific (pargs [i], qargs [i]);
3988 if (specific == pargs [i])
3989 p_specific_at_least_once = true;
3990 if (specific == qargs [i])
3991 q_specific_at_least_once = true;
3994 if (p_specific_at_least_once && !q_specific_at_least_once)
3996 if (!p_specific_at_least_once && q_specific_at_least_once)
4003 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4005 base.MutateHoistedGenericType (storey);
4007 MethodInfo mi = best_candidate as MethodInfo;
4009 best_candidate = storey.MutateGenericMethod (mi);
4013 best_candidate = storey.MutateConstructor ((ConstructorInfo) this);
4017 /// Find the Applicable Function Members (7.4.2.1)
4019 /// me: Method Group expression with the members to select.
4020 /// it might contain constructors or methods (or anything
4021 /// that maps to a method).
4023 /// Arguments: ArrayList containing resolved Argument objects.
4025 /// loc: The location if we want an error to be reported, or a Null
4026 /// location for "probing" purposes.
4028 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4029 /// that is the best match of me on Arguments.
4032 public virtual MethodGroupExpr OverloadResolve (EmitContext ec, ref Arguments Arguments,
4033 bool may_fail, Location loc)
4035 bool method_params = false;
4036 Type applicable_type = null;
4037 ArrayList candidates = new ArrayList (2);
4038 ArrayList candidate_overrides = null;
4041 // Used to keep a map between the candidate
4042 // and whether it is being considered in its
4043 // normal or expanded form
4045 // false is normal form, true is expanded form
4047 Hashtable candidate_to_form = null;
4048 Hashtable candidates_expanded = null;
4049 Arguments candidate_args = Arguments;
4051 int arg_count = Arguments != null ? Arguments.Count : 0;
4053 if (RootContext.Version == LanguageVersion.ISO_1 && Name == "Invoke" && TypeManager.IsDelegateType (DeclaringType)) {
4055 Report.Error (1533, loc, "Invoke cannot be called directly on a delegate");
4059 int nmethods = Methods.Length;
4063 // Methods marked 'override' don't take part in 'applicable_type'
4064 // computation, nor in the actual overload resolution.
4065 // However, they still need to be emitted instead of a base virtual method.
4066 // So, we salt them away into the 'candidate_overrides' array.
4068 // In case of reflected methods, we replace each overriding method with
4069 // its corresponding base virtual method. This is to improve compatibility
4070 // with non-C# libraries which change the visibility of overrides (#75636)
4073 for (int i = 0; i < Methods.Length; ++i) {
4074 MethodBase m = Methods [i];
4075 if (TypeManager.IsOverride (m)) {
4076 if (candidate_overrides == null)
4077 candidate_overrides = new ArrayList ();
4078 candidate_overrides.Add (m);
4079 m = TypeManager.TryGetBaseDefinition (m);
4088 // Enable message recording, it's used mainly by lambda expressions
4090 Report.IMessageRecorder msg_recorder = new Report.MessageRecorder ();
4091 Report.IMessageRecorder prev_recorder = Report.SetMessageRecorder (msg_recorder);
4094 // First we construct the set of applicable methods
4096 bool is_sorted = true;
4097 int best_candidate_rate = int.MaxValue;
4098 for (int i = 0; i < nmethods; i++) {
4099 Type decl_type = Methods [i].DeclaringType;
4102 // If we have already found an applicable method
4103 // we eliminate all base types (Section 14.5.5.1)
4105 if (applicable_type != null && IsAncestralType (decl_type, applicable_type))
4109 // Check if candidate is applicable (section 14.4.2.1)
4111 bool params_expanded_form = false;
4112 int candidate_rate = IsApplicable (ec, ref candidate_args, arg_count, ref Methods [i], ref params_expanded_form);
4114 if (candidate_rate < best_candidate_rate) {
4115 best_candidate_rate = candidate_rate;
4116 best_candidate = Methods [i];
4119 if (params_expanded_form) {
4120 if (candidate_to_form == null)
4121 candidate_to_form = new PtrHashtable ();
4122 MethodBase candidate = Methods [i];
4123 candidate_to_form [candidate] = candidate;
4126 if (candidate_args != Arguments) {
4127 if (candidates_expanded == null)
4128 candidates_expanded = new Hashtable (2);
4130 candidates_expanded.Add (Methods [i], candidate_args);
4131 candidate_args = Arguments;
4134 if (candidate_rate != 0 || has_inaccessible_candidates_only) {
4135 if (msg_recorder != null)
4136 msg_recorder.EndSession ();
4140 msg_recorder = null;
4141 candidates.Add (Methods [i]);
4143 if (applicable_type == null)
4144 applicable_type = decl_type;
4145 else if (applicable_type != decl_type) {
4147 if (IsAncestralType (applicable_type, decl_type))
4148 applicable_type = decl_type;
4152 Report.SetMessageRecorder (prev_recorder);
4153 if (msg_recorder != null && !msg_recorder.IsEmpty) {
4155 msg_recorder.PrintMessages ();
4160 int candidate_top = candidates.Count;
4162 if (applicable_type == null) {
4164 // When we found a top level method which does not match and it's
4165 // not an extension method. We start extension methods lookup from here
4167 if (InstanceExpression != null) {
4168 ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (type, Name, loc);
4169 if (ex_method_lookup != null) {
4170 ex_method_lookup.ExtensionExpression = InstanceExpression;
4171 ex_method_lookup.SetTypeArguments (type_arguments);
4172 return ex_method_lookup.OverloadResolve (ec, ref Arguments, may_fail, loc);
4180 // Okay so we have failed to find exact match so we
4181 // return error info about the closest match
4183 if (best_candidate != null) {
4184 if (CustomErrorHandler != null && !has_inaccessible_candidates_only && CustomErrorHandler.NoExactMatch (ec, best_candidate))
4187 AParametersCollection pd = TypeManager.GetParameterData (best_candidate);
4188 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4189 if (arg_count == pd.Count || pd.HasParams) {
4190 if (TypeManager.IsGenericMethodDefinition (best_candidate)) {
4191 if (type_arguments == null) {
4192 Report.Error (411, loc,
4193 "The type arguments for method `{0}' cannot be inferred from " +
4194 "the usage. Try specifying the type arguments explicitly",
4195 TypeManager.CSharpSignature (best_candidate));
4199 Type[] g_args = TypeManager.GetGenericArguments (best_candidate);
4200 if (type_arguments.Count != g_args.Length) {
4201 Report.SymbolRelatedToPreviousError (best_candidate);
4202 Report.Error (305, loc, "Using the generic method `{0}' requires `{1}' type argument(s)",
4203 TypeManager.CSharpSignature (best_candidate),
4204 g_args.Length.ToString ());
4208 if (type_arguments != null && !TypeManager.IsGenericMethod (best_candidate)) {
4209 Namespace.Error_TypeArgumentsCannotBeUsed (best_candidate, loc);
4214 if (has_inaccessible_candidates_only) {
4215 if (InstanceExpression != null && type != ec.ContainerType && TypeManager.IsNestedFamilyAccessible (ec.ContainerType, best_candidate.DeclaringType)) {
4216 // Although a derived class can access protected members of
4217 // its base class it cannot do so through an instance of the
4218 // base class (CS1540). If the qualifier_type is a base of the
4219 // ec.ContainerType and the lookup succeeds with the latter one,
4220 // then we are in this situation.
4221 Error_CannotAccessProtected (loc, best_candidate, queried_type, ec.ContainerType);
4223 Report.SymbolRelatedToPreviousError (best_candidate);
4224 ErrorIsInaccesible (loc, GetSignatureForError ());
4228 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate, cand_params, may_fail, loc))
4231 if (has_inaccessible_candidates_only)
4234 throw new InternalErrorException ("VerifyArgumentsCompat didn't find any problem with rejected candidate " + best_candidate);
4239 // We failed to find any method with correct argument count
4241 if (Name == ConstructorInfo.ConstructorName) {
4242 Report.SymbolRelatedToPreviousError (queried_type);
4243 Report.Error (1729, loc,
4244 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4245 TypeManager.CSharpName (queried_type), arg_count);
4247 Error_ArgumentCountWrong (arg_count);
4255 // At this point, applicable_type is _one_ of the most derived types
4256 // in the set of types containing the methods in this MethodGroup.
4257 // Filter the candidates so that they only contain methods from the
4258 // most derived types.
4261 int finalized = 0; // Number of finalized candidates
4264 // Invariant: applicable_type is a most derived type
4266 // We'll try to complete Section 14.5.5.1 for 'applicable_type' by
4267 // eliminating all it's base types. At the same time, we'll also move
4268 // every unrelated type to the end of the array, and pick the next
4269 // 'applicable_type'.
4271 Type next_applicable_type = null;
4272 int j = finalized; // where to put the next finalized candidate
4273 int k = finalized; // where to put the next undiscarded candidate
4274 for (int i = finalized; i < candidate_top; ++i) {
4275 MethodBase candidate = (MethodBase) candidates [i];
4276 Type decl_type = candidate.DeclaringType;
4278 if (decl_type == applicable_type) {
4279 candidates [k++] = candidates [j];
4280 candidates [j++] = candidates [i];
4284 if (IsAncestralType (decl_type, applicable_type))
4287 if (next_applicable_type != null &&
4288 IsAncestralType (decl_type, next_applicable_type))
4291 candidates [k++] = candidates [i];
4293 if (next_applicable_type == null ||
4294 IsAncestralType (next_applicable_type, decl_type))
4295 next_applicable_type = decl_type;
4298 applicable_type = next_applicable_type;
4301 } while (applicable_type != null);
4305 // Now we actually find the best method
4308 best_candidate = (MethodBase) candidates [0];
4309 method_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4312 // TODO: Broken inverse order of candidates logic does not work with optional
4313 // parameters used for method overrides and I am not going to fix it for SRE
4315 if (candidates_expanded != null && candidates_expanded.Contains (best_candidate)) {
4316 candidate_args = (Arguments) candidates_expanded [best_candidate];
4317 arg_count = candidate_args.Count;
4320 for (int ix = 1; ix < candidate_top; ix++) {
4321 MethodBase candidate = (MethodBase) candidates [ix];
4323 if (candidate == best_candidate)
4326 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4328 if (BetterFunction (ec, candidate_args, arg_count,
4329 candidate, cand_params,
4330 best_candidate, method_params)) {
4331 best_candidate = candidate;
4332 method_params = cand_params;
4336 // Now check that there are no ambiguities i.e the selected method
4337 // should be better than all the others
4339 MethodBase ambiguous = null;
4340 for (int ix = 1; ix < candidate_top; ix++) {
4341 MethodBase candidate = (MethodBase) candidates [ix];
4343 if (candidate == best_candidate)
4346 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4347 if (!BetterFunction (ec, candidate_args, arg_count,
4348 best_candidate, method_params,
4349 candidate, cand_params))
4352 Report.SymbolRelatedToPreviousError (candidate);
4353 ambiguous = candidate;
4357 if (ambiguous != null) {
4358 Error_AmbiguousCall (ambiguous);
4363 // If the method is a virtual function, pick an override closer to the LHS type.
4365 if (!IsBase && best_candidate.IsVirtual) {
4366 if (TypeManager.IsOverride (best_candidate))
4367 throw new InternalErrorException (
4368 "Should not happen. An 'override' method took part in overload resolution: " + best_candidate);
4370 if (candidate_overrides != null) {
4371 Type[] gen_args = null;
4372 bool gen_override = false;
4373 if (TypeManager.IsGenericMethod (best_candidate))
4374 gen_args = TypeManager.GetGenericArguments (best_candidate);
4376 foreach (MethodBase candidate in candidate_overrides) {
4377 if (TypeManager.IsGenericMethod (candidate)) {
4378 if (gen_args == null)
4381 if (gen_args.Length != TypeManager.GetGenericArguments (candidate).Length)
4384 if (gen_args != null)
4388 if (IsOverride (candidate, best_candidate)) {
4389 gen_override = true;
4390 best_candidate = candidate;
4394 if (gen_override && gen_args != null) {
4396 best_candidate = ((MethodInfo) best_candidate).MakeGenericMethod (gen_args);
4403 // And now check if the arguments are all
4404 // compatible, perform conversions if
4405 // necessary etc. and return if everything is
4408 if (!VerifyArgumentsCompat (ec, ref candidate_args, arg_count, best_candidate,
4409 method_params, may_fail, loc))
4412 if (best_candidate == null)
4415 MethodBase the_method = TypeManager.DropGenericMethodArguments (best_candidate);
4416 if (TypeManager.IsGenericMethodDefinition (the_method) &&
4417 !ConstraintChecker.CheckConstraints (ec, the_method, best_candidate, loc))
4421 // Check ObsoleteAttribute on the best method
4423 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (the_method);
4424 if (oa != null && !ec.IsInObsoleteScope)
4425 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc);
4427 IMethodData data = TypeManager.GetMethod (the_method);
4429 data.SetMemberIsUsed ();
4431 Arguments = candidate_args;
4435 public override void SetTypeArguments (TypeArguments ta)
4437 type_arguments = ta;
4440 public bool VerifyArgumentsCompat (EmitContext ec, ref Arguments arguments,
4441 int arg_count, MethodBase method,
4442 bool chose_params_expanded,
4443 bool may_fail, Location loc)
4445 AParametersCollection pd = TypeManager.GetParameterData (method);
4446 int param_count = GetApplicableParametersCount (method, pd);
4448 int errors = Report.Errors;
4449 Parameter.Modifier p_mod = 0;
4451 int a_idx = 0, a_pos = 0;
4453 ArrayList params_initializers = null;
4454 bool has_unsafe_arg = false;
4456 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4457 a = arguments [a_idx];
4458 if (p_mod != Parameter.Modifier.PARAMS) {
4459 p_mod = pd.FixedParameters [a_idx].ModFlags;
4460 pt = pd.Types [a_idx];
4461 has_unsafe_arg |= pt.IsPointer;
4463 if (p_mod == Parameter.Modifier.PARAMS) {
4464 if (chose_params_expanded) {
4465 params_initializers = new ArrayList (arg_count - a_idx);
4466 pt = TypeManager.GetElementType (pt);
4472 // Types have to be identical when ref or out modifer is used
4474 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4475 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4478 if (!TypeManager.IsEqual (a.Expr.Type, pt))
4483 NamedArgument na = a as NamedArgument;
4485 int name_index = pd.GetParameterIndexByName (na.Name.Value);
4486 if (name_index < 0 || name_index >= param_count) {
4487 if (DeclaringType != null && TypeManager.IsDelegateType (DeclaringType)) {
4488 Report.SymbolRelatedToPreviousError (DeclaringType);
4489 Report.Error (1746, na.Name.Location,
4490 "The delegate `{0}' does not contain a parameter named `{1}'",
4491 TypeManager.CSharpName (DeclaringType), na.Name.Value);
4493 Report.SymbolRelatedToPreviousError (best_candidate);
4494 Report.Error (1739, na.Name.Location,
4495 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
4496 TypeManager.CSharpSignature (method), na.Name.Value);
4498 } else if (arguments[name_index] != a) {
4499 if (DeclaringType != null && TypeManager.IsDelegateType (DeclaringType))
4500 Report.SymbolRelatedToPreviousError (DeclaringType);
4502 Report.SymbolRelatedToPreviousError (best_candidate);
4504 Report.Error (1744, na.Name.Location,
4505 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
4511 if (delegate_type != null && !Delegate.IsTypeCovariant (a.Expr, pt))
4514 Expression conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4519 // Convert params arguments to an array initializer
4521 if (params_initializers != null) {
4522 // we choose to use 'a.Expr' rather than 'conv' so that
4523 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
4524 params_initializers.Add (a.Expr);
4525 arguments.RemoveAt (a_idx--);
4530 // Update the argument with the implicit conversion
4534 if (a_idx != arg_count) {
4535 if (!may_fail && Report.Errors == errors) {
4536 if (CustomErrorHandler != null)
4537 CustomErrorHandler.NoExactMatch (ec, best_candidate);
4539 Error_InvalidArguments (ec, loc, a_pos, method, a, pd, pt);
4545 // Fill not provided arguments required by params modifier
4547 if (params_initializers == null && pd.HasParams && arg_count + 1 == param_count) {
4548 if (arguments == null)
4549 arguments = new Arguments (1);
4551 pt = pd.Types [param_count - 1];
4552 pt = TypeManager.GetElementType (pt);
4553 has_unsafe_arg |= pt.IsPointer;
4554 params_initializers = new ArrayList (0);
4558 // Append an array argument with all params arguments
4560 if (params_initializers != null) {
4561 arguments.Add (new Argument (
4562 new ArrayCreation (new TypeExpression (pt, loc), "[]",
4563 params_initializers, loc).Resolve (ec)));
4567 if (arg_count < param_count) {
4569 Error_ArgumentCountWrong (arg_count);
4573 if (has_unsafe_arg && !ec.InUnsafe) {
4583 public class ConstantExpr : MemberExpr
4587 public ConstantExpr (FieldInfo constant, Location loc)
4589 this.constant = constant;
4593 public override string Name {
4594 get { throw new NotImplementedException (); }
4597 public override bool IsInstance {
4598 get { return !IsStatic; }
4601 public override bool IsStatic {
4602 get { return constant.IsStatic; }
4605 public override Type DeclaringType {
4606 get { return constant.DeclaringType; }
4609 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc, SimpleName original)
4611 constant = TypeManager.GetGenericFieldDefinition (constant);
4613 IConstant ic = TypeManager.GetConstant (constant);
4615 if (constant.IsLiteral) {
4616 ic = new ExternalConstant (constant);
4618 ic = ExternalConstant.CreateDecimal (constant);
4619 // HACK: decimal field was not resolved as constant
4621 return new FieldExpr (constant, loc).ResolveMemberAccess (ec, left, loc, original);
4623 TypeManager.RegisterConstant (constant, ic);
4626 return base.ResolveMemberAccess (ec, left, loc, original);
4629 public override Expression CreateExpressionTree (EmitContext ec)
4631 throw new NotSupportedException ("ET");
4634 public override Expression DoResolve (EmitContext ec)
4636 IConstant ic = TypeManager.GetConstant (constant);
4637 if (ic.ResolveValue ()) {
4638 if (!ec.IsInObsoleteScope)
4639 ic.CheckObsoleteness (loc);
4642 return ic.CreateConstantReference (loc);
4645 public override void Emit (EmitContext ec)
4647 throw new NotSupportedException ();
4650 public override string GetSignatureForError ()
4652 return TypeManager.GetFullNameSignature (constant);
4657 /// Fully resolved expression that evaluates to a Field
4659 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariableReference {
4660 public FieldInfo FieldInfo;
4661 readonly Type constructed_generic_type;
4662 VariableInfo variable_info;
4664 LocalTemporary temp;
4667 protected FieldExpr (Location l)
4672 public FieldExpr (FieldInfo fi, Location l)
4675 type = TypeManager.TypeToCoreType (fi.FieldType);
4679 public FieldExpr (FieldInfo fi, Type genericType, Location l)
4682 if (TypeManager.IsGenericTypeDefinition (genericType))
4684 this.constructed_generic_type = genericType;
4687 public override string Name {
4689 return FieldInfo.Name;
4693 public override bool IsInstance {
4695 return !FieldInfo.IsStatic;
4699 public override bool IsStatic {
4701 return FieldInfo.IsStatic;
4705 public override Type DeclaringType {
4707 return FieldInfo.DeclaringType;
4711 public override string GetSignatureForError ()
4713 return TypeManager.GetFullNameSignature (FieldInfo);
4716 public VariableInfo VariableInfo {
4718 return variable_info;
4722 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
4723 SimpleName original)
4725 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
4726 Type t = fi.FieldType;
4728 if (t.IsPointer && !ec.InUnsafe) {
4732 return base.ResolveMemberAccess (ec, left, loc, original);
4735 public void SetHasAddressTaken ()
4737 IVariableReference vr = InstanceExpression as IVariableReference;
4739 vr.SetHasAddressTaken ();
4742 public override Expression CreateExpressionTree (EmitContext ec)
4744 Expression instance;
4745 if (InstanceExpression == null) {
4746 instance = new NullLiteral (loc);
4748 instance = InstanceExpression.CreateExpressionTree (ec);
4751 Arguments args = Arguments.CreateForExpressionTree (ec, null,
4753 CreateTypeOfExpression ());
4755 return CreateExpressionFactoryCall ("Field", args);
4758 public Expression CreateTypeOfExpression ()
4760 return new TypeOfField (GetConstructedFieldInfo (), loc);
4763 override public Expression DoResolve (EmitContext ec)
4765 return DoResolve (ec, false, false);
4768 Expression DoResolve (EmitContext ec, bool lvalue_instance, bool out_access)
4770 if (!FieldInfo.IsStatic){
4771 if (InstanceExpression == null){
4773 // This can happen when referencing an instance field using
4774 // a fully qualified type expression: TypeName.InstanceField = xxx
4776 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4780 // Resolve the field's instance expression while flow analysis is turned
4781 // off: when accessing a field "a.b", we must check whether the field
4782 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4784 if (lvalue_instance) {
4785 using (ec.With (EmitContext.Flags.DoFlowAnalysis, false)) {
4786 Expression right_side =
4787 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4789 if (InstanceExpression != EmptyExpression.Null)
4790 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
4793 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
4795 if (InstanceExpression != EmptyExpression.Null)
4796 InstanceExpression = InstanceExpression.Resolve (ec, rf);
4799 if (InstanceExpression == null)
4802 using (ec.Set (EmitContext.Flags.OmitStructFlowAnalysis)) {
4803 InstanceExpression.CheckMarshalByRefAccess (ec);
4807 // TODO: the code above uses some non-standard multi-resolve rules
4808 if (eclass != ExprClass.Invalid)
4811 if (!ec.IsInObsoleteScope) {
4812 FieldBase f = TypeManager.GetField (FieldInfo);
4814 f.CheckObsoleteness (loc);
4816 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
4818 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
4822 IFixedBuffer fb = AttributeTester.GetFixedBuffer (FieldInfo);
4823 IVariableReference var = InstanceExpression as IVariableReference;
4826 IFixedExpression fe = InstanceExpression as IFixedExpression;
4827 if (!ec.InFixedInitializer && (fe == null || !fe.IsFixed)) {
4828 Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4831 if (InstanceExpression.eclass != ExprClass.Variable) {
4832 Report.SymbolRelatedToPreviousError (FieldInfo);
4833 Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4834 TypeManager.GetFullNameSignature (FieldInfo));
4835 } else if (var != null && var.IsHoisted) {
4836 AnonymousMethodExpression.Error_AddressOfCapturedVar (var, loc);
4839 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4842 eclass = ExprClass.Variable;
4844 // If the instance expression is a local variable or parameter.
4845 if (var == null || var.VariableInfo == null)
4848 VariableInfo vi = var.VariableInfo;
4849 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
4852 variable_info = vi.GetSubStruct (FieldInfo.Name);
4853 eclass = ExprClass.Variable;
4857 static readonly int [] codes = {
4858 191, // instance, write access
4859 192, // instance, out access
4860 198, // static, write access
4861 199, // static, out access
4862 1648, // member of value instance, write access
4863 1649, // member of value instance, out access
4864 1650, // member of value static, write access
4865 1651 // member of value static, out access
4868 static readonly string [] msgs = {
4869 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4870 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4871 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4872 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4873 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4874 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4875 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4876 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4879 // The return value is always null. Returning a value simplifies calling code.
4880 Expression Report_AssignToReadonly (Expression right_side)
4883 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4887 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4889 Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4894 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4896 IVariableReference var = InstanceExpression as IVariableReference;
4897 if (var != null && var.VariableInfo != null)
4898 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
4900 bool lvalue_instance = !FieldInfo.IsStatic && TypeManager.IsValueType (FieldInfo.DeclaringType);
4901 bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
4903 Expression e = DoResolve (ec, lvalue_instance, out_access);
4908 FieldBase fb = TypeManager.GetField (FieldInfo);
4912 if (FieldInfo.IsInitOnly) {
4913 // InitOnly fields can only be assigned in constructors or initializers
4914 if (!ec.IsInFieldInitializer && !ec.IsConstructor)
4915 return Report_AssignToReadonly (right_side);
4917 if (ec.IsConstructor) {
4918 Type ctype = ec.TypeContainer.CurrentType;
4920 ctype = ec.ContainerType;
4922 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4923 if (!TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
4924 return Report_AssignToReadonly (right_side);
4925 // static InitOnly fields cannot be assigned-to in an instance constructor
4926 if (IsStatic && !ec.IsStatic)
4927 return Report_AssignToReadonly (right_side);
4928 // instance constructors can't modify InitOnly fields of other instances of the same type
4929 if (!IsStatic && !(InstanceExpression is This))
4930 return Report_AssignToReadonly (right_side);
4934 if (right_side == EmptyExpression.OutAccess &&
4935 !IsStatic && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type)) {
4936 Report.SymbolRelatedToPreviousError (DeclaringType);
4937 Report.Warning (197, 1, loc,
4938 "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",
4939 GetSignatureForError ());
4942 eclass = ExprClass.Variable;
4946 bool is_marshal_by_ref ()
4948 return !IsStatic && TypeManager.IsStruct (Type) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type);
4951 public override void CheckMarshalByRefAccess (EmitContext ec)
4953 if (is_marshal_by_ref () && !(InstanceExpression is This)) {
4954 Report.SymbolRelatedToPreviousError (DeclaringType);
4955 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",
4956 GetSignatureForError ());
4960 public override int GetHashCode ()
4962 return FieldInfo.GetHashCode ();
4965 public bool IsFixed {
4968 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
4970 IVariableReference variable = InstanceExpression as IVariableReference;
4971 if (variable != null)
4972 return TypeManager.IsStruct (InstanceExpression.Type) && variable.IsFixed;
4974 IFixedExpression fe = InstanceExpression as IFixedExpression;
4975 return fe != null && fe.IsFixed;
4979 public bool IsHoisted {
4981 IVariableReference hv = InstanceExpression as IVariableReference;
4982 return hv != null && hv.IsHoisted;
4986 public override bool Equals (object obj)
4988 FieldExpr fe = obj as FieldExpr;
4992 if (FieldInfo != fe.FieldInfo)
4995 if (InstanceExpression == null || fe.InstanceExpression == null)
4998 return InstanceExpression.Equals (fe.InstanceExpression);
5001 public void Emit (EmitContext ec, bool leave_copy)
5003 ILGenerator ig = ec.ig;
5004 bool is_volatile = false;
5006 FieldBase f = TypeManager.GetField (FieldInfo);
5008 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
5011 f.SetMemberIsUsed ();
5014 if (FieldInfo.IsStatic){
5016 ig.Emit (OpCodes.Volatile);
5018 ig.Emit (OpCodes.Ldsfld, GetConstructedFieldInfo ());
5021 EmitInstance (ec, false);
5023 // Optimization for build-in types
5024 // TODO: Iterators don't set current container
5025 if (TypeManager.IsStruct (type) && type == ec.DeclContainer.TypeBuilder && ec.CurrentIterator == null) {
5026 LoadFromPtr (ig, type);
5028 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
5030 ig.Emit (OpCodes.Ldflda, GetConstructedFieldInfo ());
5031 ig.Emit (OpCodes.Ldflda, ff.Element);
5034 ig.Emit (OpCodes.Volatile);
5036 ig.Emit (OpCodes.Ldfld, GetConstructedFieldInfo ());
5042 ec.ig.Emit (OpCodes.Dup);
5043 if (!FieldInfo.IsStatic) {
5044 temp = new LocalTemporary (this.Type);
5050 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5052 FieldAttributes fa = FieldInfo.Attributes;
5053 bool is_static = (fa & FieldAttributes.Static) != 0;
5054 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
5055 ILGenerator ig = ec.ig;
5057 if (is_readonly && !ec.IsConstructor){
5058 Report_AssignToReadonly (source);
5062 prepared = prepare_for_load;
5063 EmitInstance (ec, prepared);
5067 ec.ig.Emit (OpCodes.Dup);
5068 if (!FieldInfo.IsStatic) {
5069 temp = new LocalTemporary (this.Type);
5074 FieldBase f = TypeManager.GetField (FieldInfo);
5076 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
5077 ig.Emit (OpCodes.Volatile);
5083 ig.Emit (OpCodes.Stsfld, GetConstructedFieldInfo ());
5085 ig.Emit (OpCodes.Stfld, GetConstructedFieldInfo ());
5094 public override void Emit (EmitContext ec)
5099 public override void EmitSideEffect (EmitContext ec)
5101 FieldBase f = TypeManager.GetField (FieldInfo);
5102 bool is_volatile = f != null && (f.ModFlags & Modifiers.VOLATILE) != 0;
5104 if (is_volatile || is_marshal_by_ref ())
5105 base.EmitSideEffect (ec);
5108 public override void Error_VariableIsUsedBeforeItIsDeclared (string name)
5110 Report.Error (844, loc,
5111 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the field `{1}'",
5112 name, GetSignatureForError ());
5115 public void AddressOf (EmitContext ec, AddressOp mode)
5117 ILGenerator ig = ec.ig;
5119 FieldBase f = TypeManager.GetField (FieldInfo);
5121 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
5122 Report.Warning (420, 1, loc, "`{0}': A volatile field references will not be treated as volatile",
5123 f.GetSignatureForError ());
5126 if ((mode & AddressOp.Store) != 0)
5128 if ((mode & AddressOp.Load) != 0)
5129 f.SetMemberIsUsed ();
5133 // Handle initonly fields specially: make a copy and then
5134 // get the address of the copy.
5137 if (FieldInfo.IsInitOnly){
5139 if (ec.IsConstructor){
5140 if (FieldInfo.IsStatic){
5152 local = ig.DeclareLocal (type);
5153 ig.Emit (OpCodes.Stloc, local);
5154 ig.Emit (OpCodes.Ldloca, local);
5159 if (FieldInfo.IsStatic){
5160 ig.Emit (OpCodes.Ldsflda, GetConstructedFieldInfo ());
5163 EmitInstance (ec, false);
5164 ig.Emit (OpCodes.Ldflda, GetConstructedFieldInfo ());
5168 FieldInfo GetConstructedFieldInfo ()
5170 if (constructed_generic_type == null)
5173 return TypeBuilder.GetField (constructed_generic_type, FieldInfo);
5175 throw new NotSupportedException ();
5179 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5181 FieldInfo = storey.MutateField (FieldInfo);
5182 base.MutateHoistedGenericType (storey);
5188 /// Expression that evaluates to a Property. The Assign class
5189 /// might set the `Value' expression if we are in an assignment.
5191 /// This is not an LValue because we need to re-write the expression, we
5192 /// can not take data from the stack and store it.
5194 public class PropertyExpr : MemberExpr, IAssignMethod {
5195 public readonly PropertyInfo PropertyInfo;
5196 MethodInfo getter, setter;
5201 LocalTemporary temp;
5204 public PropertyExpr (Type container_type, PropertyInfo pi, Location l)
5207 eclass = ExprClass.PropertyAccess;
5211 type = TypeManager.TypeToCoreType (pi.PropertyType);
5213 ResolveAccessors (container_type);
5216 public override string Name {
5218 return PropertyInfo.Name;
5222 public override bool IsInstance {
5228 public override bool IsStatic {
5234 public override Expression CreateExpressionTree (EmitContext ec)
5237 if (IsSingleDimensionalArrayLength ()) {
5238 args = new Arguments (1);
5239 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5240 return CreateExpressionFactoryCall ("ArrayLength", args);
5244 Error_BaseAccessInExpressionTree (loc);
5248 args = new Arguments (2);
5249 if (InstanceExpression == null)
5250 args.Add (new Argument (new NullLiteral (loc)));
5252 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5253 args.Add (new Argument (new TypeOfMethodInfo (getter, loc)));
5254 return CreateExpressionFactoryCall ("Property", args);
5257 public Expression CreateSetterTypeOfExpression ()
5259 return new TypeOfMethodInfo (setter, loc);
5262 public override Type DeclaringType {
5264 return PropertyInfo.DeclaringType;
5268 public override string GetSignatureForError ()
5270 return TypeManager.GetFullNameSignature (PropertyInfo);
5273 void FindAccessors (Type invocation_type)
5275 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
5276 BindingFlags.Static | BindingFlags.Instance |
5277 BindingFlags.DeclaredOnly;
5279 Type current = PropertyInfo.DeclaringType;
5280 for (; current != null; current = current.BaseType) {
5281 MemberInfo[] group = TypeManager.MemberLookup (
5282 invocation_type, invocation_type, current,
5283 MemberTypes.Property, flags, PropertyInfo.Name, null);
5288 if (group.Length != 1)
5289 // Oooops, can this ever happen ?
5292 PropertyInfo pi = (PropertyInfo) group [0];
5295 getter = pi.GetGetMethod (true);
5298 setter = pi.GetSetMethod (true);
5300 MethodInfo accessor = getter != null ? getter : setter;
5302 if (!accessor.IsVirtual)
5308 // We also perform the permission checking here, as the PropertyInfo does not
5309 // hold the information for the accessibility of its setter/getter
5311 // TODO: Refactor to use some kind of cache together with GetPropertyFromAccessor
5312 void ResolveAccessors (Type container_type)
5314 FindAccessors (container_type);
5316 if (getter != null) {
5317 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
5318 IMethodData md = TypeManager.GetMethod (the_getter);
5320 md.SetMemberIsUsed ();
5322 is_static = getter.IsStatic;
5325 if (setter != null) {
5326 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
5327 IMethodData md = TypeManager.GetMethod (the_setter);
5329 md.SetMemberIsUsed ();
5331 is_static = setter.IsStatic;
5335 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5337 if (InstanceExpression != null)
5338 InstanceExpression.MutateHoistedGenericType (storey);
5340 type = storey.MutateType (type);
5342 getter = storey.MutateGenericMethod (getter);
5344 setter = storey.MutateGenericMethod (setter);
5347 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
5350 InstanceExpression = null;
5354 if (InstanceExpression == null) {
5355 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5359 InstanceExpression = InstanceExpression.DoResolve (ec);
5360 if (lvalue_instance && InstanceExpression != null)
5361 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess);
5363 if (InstanceExpression == null)
5366 InstanceExpression.CheckMarshalByRefAccess (ec);
5368 if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) &&
5369 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
5370 !TypeManager.IsNestedChildOf (ec.ContainerType, InstanceExpression.Type) &&
5371 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.ContainerType)) {
5372 Report.SymbolRelatedToPreviousError (PropertyInfo);
5373 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
5380 void Error_PropertyNotFound (MethodInfo mi, bool getter)
5382 // TODO: correctly we should compare arguments but it will lead to bigger changes
5383 if (mi is MethodBuilder) {
5384 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
5388 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
5390 AParametersCollection iparams = TypeManager.GetParameterData (mi);
5391 sig.Append (getter ? "get_" : "set_");
5393 sig.Append (iparams.GetSignatureForError ());
5395 Report.SymbolRelatedToPreviousError (mi);
5396 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
5397 Name, sig.ToString ());
5400 public bool IsAccessibleFrom (Type invocation_type, bool lvalue)
5403 MethodInfo accessor = lvalue ? setter : getter;
5404 if (accessor == null && lvalue)
5406 return accessor != null && IsAccessorAccessible (invocation_type, accessor, out dummy);
5409 bool IsSingleDimensionalArrayLength ()
5411 if (DeclaringType != TypeManager.array_type || getter == null || Name != "Length")
5414 string t_name = InstanceExpression.Type.Name;
5415 int t_name_len = t_name.Length;
5416 return t_name_len > 2 && t_name [t_name_len - 2] == '[';
5419 override public Expression DoResolve (EmitContext ec)
5424 if (getter != null){
5425 if (TypeManager.GetParameterData (getter).Count != 0){
5426 Error_PropertyNotFound (getter, true);
5431 if (getter == null){
5433 // The following condition happens if the PropertyExpr was
5434 // created, but is invalid (ie, the property is inaccessible),
5435 // and we did not want to embed the knowledge about this in
5436 // the caller routine. This only avoids double error reporting.
5441 if (InstanceExpression != EmptyExpression.Null) {
5442 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5443 TypeManager.GetFullNameSignature (PropertyInfo));
5448 bool must_do_cs1540_check = false;
5449 if (getter != null &&
5450 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
5451 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
5452 if (pm != null && pm.HasCustomAccessModifier) {
5453 Report.SymbolRelatedToPreviousError (pm);
5454 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5455 TypeManager.CSharpSignature (getter));
5458 Report.SymbolRelatedToPreviousError (getter);
5459 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
5464 if (!InstanceResolve (ec, false, must_do_cs1540_check))
5468 // Only base will allow this invocation to happen.
5470 if (IsBase && getter.IsAbstract) {
5471 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5474 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
5478 if (!ec.IsInObsoleteScope) {
5479 PropertyBase pb = TypeManager.GetProperty (PropertyInfo);
5481 pb.CheckObsoleteness (loc);
5483 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (PropertyInfo);
5485 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc);
5494 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
5496 if (right_side == EmptyExpression.OutAccess) {
5497 if (ec.CurrentBlock.Toplevel.GetParameterReference (PropertyInfo.Name, loc) is MemberAccess) {
5498 Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5501 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as `ref' or `out' parameter",
5502 GetSignatureForError ());
5507 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5508 Error_CannotModifyIntermediateExpressionValue (ec);
5511 if (setter == null){
5513 // The following condition happens if the PropertyExpr was
5514 // created, but is invalid (ie, the property is inaccessible),
5515 // and we did not want to embed the knowledge about this in
5516 // the caller routine. This only avoids double error reporting.
5521 if (ec.CurrentBlock.Toplevel.GetParameterReference (PropertyInfo.Name, loc) is MemberAccess) {
5522 Report.Error (1947, loc, "A range variable `{0}' cannot be assigned to. Consider using `let' clause to store the value",
5525 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
5526 GetSignatureForError ());
5531 if (TypeManager.GetParameterData (setter).Count != 1){
5532 Error_PropertyNotFound (setter, false);
5536 bool must_do_cs1540_check;
5537 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
5538 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
5539 if (pm != null && pm.HasCustomAccessModifier) {
5540 Report.SymbolRelatedToPreviousError (pm);
5541 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5542 TypeManager.CSharpSignature (setter));
5545 Report.SymbolRelatedToPreviousError (setter);
5546 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
5551 if (!InstanceResolve (ec, TypeManager.IsStruct (PropertyInfo.DeclaringType), must_do_cs1540_check))
5555 // Only base will allow this invocation to happen.
5557 if (IsBase && setter.IsAbstract){
5558 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5561 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe) {
5565 if (!ec.IsInObsoleteScope) {
5566 PropertyBase pb = TypeManager.GetProperty (PropertyInfo);
5568 pb.CheckObsoleteness (loc);
5570 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (PropertyInfo);
5572 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc);
5579 public override void Emit (EmitContext ec)
5584 public void Emit (EmitContext ec, bool leave_copy)
5587 // Special case: length of single dimension array property is turned into ldlen
5589 if (IsSingleDimensionalArrayLength ()) {
5591 EmitInstance (ec, false);
5592 ec.ig.Emit (OpCodes.Ldlen);
5593 ec.ig.Emit (OpCodes.Conv_I4);
5597 Invocation.EmitCall (ec, IsBase, InstanceExpression, getter, null, loc, prepared, false);
5600 ec.ig.Emit (OpCodes.Dup);
5602 temp = new LocalTemporary (this.Type);
5609 // Implements the IAssignMethod interface for assignments
5611 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5613 Expression my_source = source;
5615 if (prepare_for_load) {
5620 ec.ig.Emit (OpCodes.Dup);
5622 temp = new LocalTemporary (this.Type);
5626 } else if (leave_copy) {
5628 temp = new LocalTemporary (this.Type);
5633 Arguments args = new Arguments (1);
5634 args.Add (new Argument (my_source));
5636 Invocation.EmitCall (ec, IsBase, InstanceExpression, setter, args, loc, false, prepared);
5646 /// Fully resolved expression that evaluates to an Event
5648 public class EventExpr : MemberExpr {
5649 public readonly EventInfo EventInfo;
5652 MethodInfo add_accessor, remove_accessor;
5654 public EventExpr (EventInfo ei, Location loc)
5658 eclass = ExprClass.EventAccess;
5660 add_accessor = TypeManager.GetAddMethod (ei);
5661 remove_accessor = TypeManager.GetRemoveMethod (ei);
5662 if (add_accessor.IsStatic || remove_accessor.IsStatic)
5665 if (EventInfo is MyEventBuilder){
5666 MyEventBuilder eb = (MyEventBuilder) EventInfo;
5667 type = eb.EventType;
5670 type = EventInfo.EventHandlerType;
5673 public override string Name {
5675 return EventInfo.Name;
5679 public override bool IsInstance {
5685 public override bool IsStatic {
5691 public override Type DeclaringType {
5693 return EventInfo.DeclaringType;
5697 void Error_AssignmentEventOnly ()
5699 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5700 GetSignatureForError ());
5703 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
5704 SimpleName original)
5707 // If the event is local to this class, we transform ourselves into a FieldExpr
5710 if (EventInfo.DeclaringType == ec.ContainerType ||
5711 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
5712 EventField mi = TypeManager.GetEventField (EventInfo);
5715 if (!ec.IsInObsoleteScope)
5716 mi.CheckObsoleteness (loc);
5718 if ((mi.ModFlags & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0 && !ec.IsInCompoundAssignment)
5719 Error_AssignmentEventOnly ();
5721 FieldExpr ml = new FieldExpr (mi.BackingField.FieldBuilder, loc);
5723 InstanceExpression = null;
5725 return ml.ResolveMemberAccess (ec, left, loc, original);
5729 if (left is This && !ec.IsInCompoundAssignment)
5730 Error_AssignmentEventOnly ();
5732 return base.ResolveMemberAccess (ec, left, loc, original);
5735 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
5738 InstanceExpression = null;
5742 if (InstanceExpression == null) {
5743 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5747 InstanceExpression = InstanceExpression.DoResolve (ec);
5748 if (InstanceExpression == null)
5751 if (IsBase && add_accessor.IsAbstract) {
5752 Error_CannotCallAbstractBase(TypeManager.CSharpSignature(add_accessor));
5757 // This is using the same mechanism as the CS1540 check in PropertyExpr.
5758 // However, in the Event case, we reported a CS0122 instead.
5760 // TODO: Exact copy from PropertyExpr
5762 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
5763 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
5764 !TypeManager.IsNestedChildOf (ec.ContainerType, InstanceExpression.Type) &&
5765 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.ContainerType)) {
5766 Report.SymbolRelatedToPreviousError (EventInfo);
5767 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5774 public bool IsAccessibleFrom (Type invocation_type)
5777 return IsAccessorAccessible (invocation_type, add_accessor, out dummy) &&
5778 IsAccessorAccessible (invocation_type, remove_accessor, out dummy);
5781 public override Expression CreateExpressionTree (EmitContext ec)
5783 throw new NotSupportedException ("ET");
5786 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5788 // contexts where an LValue is valid have already devolved to FieldExprs
5789 Error_CannotAssign ();
5793 public override Expression DoResolve (EmitContext ec)
5795 bool must_do_cs1540_check;
5796 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
5797 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
5798 Report.SymbolRelatedToPreviousError (EventInfo);
5799 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5803 if (!InstanceResolve (ec, must_do_cs1540_check))
5806 if (!ec.IsInCompoundAssignment) {
5807 Error_CannotAssign ();
5811 if (!ec.IsInObsoleteScope) {
5812 EventField ev = TypeManager.GetEventField (EventInfo);
5814 ev.CheckObsoleteness (loc);
5816 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (EventInfo);
5818 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc);
5825 public override void Emit (EmitContext ec)
5827 Error_CannotAssign ();
5830 public void Error_CannotAssign ()
5832 Report.Error (70, loc,
5833 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
5834 GetSignatureForError (), TypeManager.CSharpName (EventInfo.DeclaringType));
5837 public override string GetSignatureForError ()
5839 return TypeManager.CSharpSignature (EventInfo);
5842 public void EmitAddOrRemove (EmitContext ec, bool is_add, Expression source)
5844 Arguments args = new Arguments (1);
5845 args.Add (new Argument (source));
5846 Invocation.EmitCall (ec, IsBase, InstanceExpression, is_add ? add_accessor : remove_accessor, args, loc);
5850 public class TemporaryVariable : VariableReference
5854 public TemporaryVariable (Type type, Location loc)
5858 eclass = ExprClass.Variable;
5861 public override Expression CreateExpressionTree (EmitContext ec)
5863 throw new NotSupportedException ("ET");
5866 public override Expression DoResolve (EmitContext ec)
5871 TypeExpr te = new TypeExpression (type, loc);
5872 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
5873 if (!li.Resolve (ec))
5877 // Don't capture temporary variables except when using
5878 // iterator redirection
5880 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.IsIterator && ec.IsVariableCapturingRequired) {
5881 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
5882 storey.CaptureLocalVariable (ec, li);
5888 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5890 return DoResolve (ec);
5893 public override void Emit (EmitContext ec)
5898 public void EmitAssign (EmitContext ec, Expression source)
5900 EmitAssign (ec, source, false, false);
5903 public override HoistedVariable GetHoistedVariable (EmitContext ec)
5905 return li.HoistedVariableReference;
5908 public override bool IsFixed {
5909 get { return true; }
5912 public override bool IsRef {
5913 get { return false; }
5916 public override string Name {
5917 get { throw new NotImplementedException (); }
5920 public override void SetHasAddressTaken ()
5922 throw new NotImplementedException ();
5925 protected override ILocalVariable Variable {
5929 public override VariableInfo VariableInfo {
5930 get { throw new NotImplementedException (); }
5935 /// Handles `var' contextual keyword; var becomes a keyword only
5936 /// if no type called var exists in a variable scope
5938 class VarExpr : SimpleName
5940 // Used for error reporting only
5941 ArrayList initializer;
5943 public VarExpr (Location loc)
5948 public ArrayList VariableInitializer {
5950 this.initializer = value;
5954 public bool InferType (EmitContext ec, Expression right_side)
5957 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
5959 type = right_side.Type;
5960 if (type == TypeManager.null_type || type == TypeManager.void_type || type == InternalType.AnonymousMethod) {
5961 Report.Error (815, loc, "An implicitly typed local variable declaration cannot be initialized with `{0}'",
5962 right_side.GetSignatureForError ());
5966 eclass = ExprClass.Variable;
5970 protected override void Error_TypeOrNamespaceNotFound (IResolveContext ec)
5972 if (RootContext.Version < LanguageVersion.V_3)
5973 base.Error_TypeOrNamespaceNotFound (ec);
5975 Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");
5978 public override TypeExpr ResolveAsContextualType (IResolveContext rc, bool silent)
5980 TypeExpr te = base.ResolveAsContextualType (rc, true);
5984 if (RootContext.Version < LanguageVersion.V_3)
5985 Report.FeatureIsNotAvailable (loc, "implicitly typed local variable");
5987 if (initializer == null)
5990 if (initializer.Count > 1) {
5991 Location loc_init = ((CSharpParser.VariableDeclaration) initializer[1]).Location;
5992 Report.Error (819, loc_init, "An implicitly typed local variable declaration cannot include multiple declarators");
5997 Expression variable_initializer = ((CSharpParser.VariableDeclaration) initializer[0]).expression_or_array_initializer;
5998 if (variable_initializer == null) {
5999 Report.Error (818, loc, "An implicitly typed local variable declarator must include an initializer");