2 // ecore.cs: Core of the Expression representation for the intermediate tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@seznam.cz)
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
13 namespace Mono.CSharp {
15 using System.Collections;
16 using System.Diagnostics;
17 using System.Reflection;
18 using System.Reflection.Emit;
22 /// The ExprClass class contains the is used to pass the
23 /// classification of an expression (value, variable, namespace,
24 /// type, method group, property access, event access, indexer access,
27 public enum ExprClass : byte {
43 /// This is used to tell Resolve in which types of expressions we're
47 public enum ResolveFlags {
48 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
51 // Returns a type expression.
54 // Returns a method group.
57 TypeParameter = 1 << 3,
59 // Mask of all the expression class flags.
60 MaskExprClass = VariableOrValue | Type | MethodGroup | TypeParameter,
62 // Disable control flow analysis while resolving the expression.
63 // This is used when resolving the instance expression of a field expression.
64 DisableFlowAnalysis = 1 << 10,
66 // Set if this is resolving the first part of a MemberAccess.
67 Intermediate = 1 << 11,
69 // Disable control flow analysis _of struct_ while resolving the expression.
70 // This is used when resolving the instance expression of a field expression.
71 DisableStructFlowAnalysis = 1 << 12,
76 // This is just as a hint to AddressOf of what will be done with the
79 public enum AddressOp {
86 /// This interface is implemented by variables
88 public interface IMemoryLocation {
90 /// The AddressOf method should generate code that loads
91 /// the address of the object and leaves it on the stack.
93 /// The `mode' argument is used to notify the expression
94 /// of whether this will be used to read from the address or
95 /// write to the address.
97 /// This is just a hint that can be used to provide good error
98 /// reporting, and should have no other side effects.
100 void AddressOf (EmitContext ec, AddressOp mode);
104 // An expressions resolved as a direct variable reference
106 public interface IVariableReference : IFixedExpression
108 bool IsHoisted { get; }
110 VariableInfo VariableInfo { get; }
112 void SetHasAddressTaken ();
116 // Implemented by an expression which could be or is always
119 public interface IFixedExpression
121 bool IsFixed { get; }
125 /// Base class for expressions
127 public abstract class Expression {
128 public ExprClass eclass;
130 protected Location loc;
134 set { type = value; }
137 public virtual Location Location {
142 /// Utility wrapper routine for Error, just to beautify the code
144 public void Error (int error, string s)
146 Report.Error (error, loc, s);
149 // Not nice but we have broken hierarchy.
150 public virtual void CheckMarshalByRefAccess (EmitContext ec)
154 public virtual bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
156 Attribute.Error_AttributeArgumentNotValid (loc);
161 public virtual string GetSignatureForError ()
163 return TypeManager.CSharpName (type);
166 public static bool IsAccessorAccessible (Type invocation_type, MethodInfo mi, out bool must_do_cs1540_check)
168 MethodAttributes ma = mi.Attributes & MethodAttributes.MemberAccessMask;
170 must_do_cs1540_check = false; // by default we do not check for this
172 if (ma == MethodAttributes.Public)
176 // If only accessible to the current class or children
178 if (ma == MethodAttributes.Private)
179 return TypeManager.IsPrivateAccessible (invocation_type, mi.DeclaringType) ||
180 TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType);
182 if (TypeManager.IsThisOrFriendAssembly (mi.DeclaringType.Assembly)) {
183 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamORAssem)
186 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamANDAssem)
190 // Family and FamANDAssem require that we derive.
191 // FamORAssem requires that we derive if in different assemblies.
192 if (!TypeManager.IsNestedFamilyAccessible (invocation_type, mi.DeclaringType))
195 if (!TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType))
196 must_do_cs1540_check = true;
201 public virtual bool IsNull {
208 /// Performs semantic analysis on the Expression
212 /// The Resolve method is invoked to perform the semantic analysis
215 /// The return value is an expression (it can be the
216 /// same expression in some cases) or a new
217 /// expression that better represents this node.
219 /// For example, optimizations of Unary (LiteralInt)
220 /// would return a new LiteralInt with a negated
223 /// If there is an error during semantic analysis,
224 /// then an error should be reported (using Report)
225 /// and a null value should be returned.
227 /// There are two side effects expected from calling
228 /// Resolve(): the the field variable "eclass" should
229 /// be set to any value of the enumeration
230 /// `ExprClass' and the type variable should be set
231 /// to a valid type (this is the type of the
234 public abstract Expression DoResolve (EmitContext ec);
236 public virtual Expression DoResolveLValue (EmitContext ec, Expression right_side)
242 // This is used if the expression should be resolved as a type or namespace name.
243 // the default implementation fails.
245 public virtual FullNamedExpression ResolveAsTypeStep (IResolveContext rc, bool silent)
249 EmitContext ec = rc as EmitContext;
253 e.Error_UnexpectedKind (ResolveFlags.Type, loc);
259 // C# 3.0 introduced contextual keywords (var) which behaves like a type if type with
260 // same name exists or as a keyword when no type was found
262 public virtual TypeExpr ResolveAsContextualType (IResolveContext rc, bool silent)
264 return ResolveAsTypeTerminal (rc, silent);
268 // This is used to resolve the expression as a type, a null
269 // value will be returned if the expression is not a type
272 public virtual TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
274 TypeExpr te = ResolveAsBaseTerminal (ec, silent);
278 if (!silent) { // && !(te is TypeParameterExpr)) {
279 ObsoleteAttribute obsolete_attr = AttributeTester.GetObsoleteAttribute (te.Type);
280 if (obsolete_attr != null && !ec.IsInObsoleteScope) {
281 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location);
285 GenericTypeExpr ct = te as GenericTypeExpr;
287 // Skip constrains check for overrides and explicit implementations
288 // TODO: they should use different overload
289 GenericMethod gm = ec.GenericDeclContainer as GenericMethod;
290 if (gm != null && ((gm.ModFlags & Modifiers.OVERRIDE) != 0 || gm.MemberName.Left != null)) {
295 // TODO: silent flag is ignored
296 ct.CheckConstraints (ec);
302 public TypeExpr ResolveAsBaseTerminal (IResolveContext ec, bool silent)
304 int errors = Report.Errors;
306 FullNamedExpression fne = ResolveAsTypeStep (ec, silent);
311 TypeExpr te = fne as TypeExpr;
313 if (!silent && errors == Report.Errors)
314 fne.Error_UnexpectedKind (null, "type", loc);
318 if (!te.CheckAccessLevel (ec.GenericDeclContainer)) {
319 Report.SymbolRelatedToPreviousError (te.Type);
320 ErrorIsInaccesible (loc, TypeManager.CSharpName (te.Type));
328 public static void ErrorIsInaccesible (Location loc, string name)
330 Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", name);
333 protected static void Error_CannotAccessProtected (Location loc, MemberInfo m, Type qualifier, Type container)
335 Report.Error (1540, loc, "Cannot access protected member `{0}' via a qualifier of type `{1}'."
336 + " The qualifier must be of type `{2}' or derived from it",
337 TypeManager.GetFullNameSignature (m),
338 TypeManager.CSharpName (qualifier),
339 TypeManager.CSharpName (container));
343 public static void Error_InvalidExpressionStatement (Location loc)
345 Report.Error (201, loc, "Only assignment, call, increment, decrement, and new object " +
346 "expressions can be used as a statement");
349 public void Error_InvalidExpressionStatement ()
351 Error_InvalidExpressionStatement (loc);
354 protected void Error_CannotAssign (string to, string roContext)
356 Report.Error (1656, loc, "Cannot assign to `{0}' because it is a `{1}'",
360 public static void Error_VoidInvalidInTheContext (Location loc)
362 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
365 public virtual void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl)
367 // The error was already reported as CS1660
368 if (type == TypeManager.anonymous_method_type)
371 if (TypeManager.IsGenericParameter (Type) && TypeManager.IsGenericParameter (target) && type.Name == target.Name) {
373 string sig1 = type.DeclaringMethod == null ?
374 TypeManager.CSharpName (type.DeclaringType) :
375 TypeManager.CSharpSignature (type.DeclaringMethod);
376 string sig2 = target.DeclaringMethod == null ?
377 TypeManager.CSharpName (target.DeclaringType) :
378 TypeManager.CSharpSignature (target.DeclaringMethod);
379 Report.ExtraInformation (loc,
381 "The generic parameter `{0}' of `{1}' cannot be converted to the generic parameter `{0}' of `{2}' (in the previous ",
382 Type.Name, sig1, sig2));
384 } else if (Type.FullName == target.FullName){
385 Report.ExtraInformation (loc,
387 "The type `{0}' has two conflicting definitions, one comes from `{1}' and the other from `{2}' (in the previous ",
388 Type.FullName, Type.Assembly.FullName, target.Assembly.FullName));
392 Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
393 TypeManager.CSharpName (type), TypeManager.CSharpName (target));
397 Report.DisableReporting ();
398 bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null;
399 Report.EnableReporting ();
402 Report.Error (266, loc, "Cannot implicitly convert type `{0}' to `{1}'. " +
403 "An explicit conversion exists (are you missing a cast?)",
404 TypeManager.CSharpName (Type), TypeManager.CSharpName (target));
408 Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
409 TypeManager.CSharpName (type),
410 TypeManager.CSharpName (target));
413 public virtual void Error_VariableIsUsedBeforeItIsDeclared (string name)
415 Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", name);
418 protected virtual void Error_TypeDoesNotContainDefinition (Type type, string name)
420 Error_TypeDoesNotContainDefinition (loc, type, name);
423 public static void Error_TypeDoesNotContainDefinition (Location loc, Type type, string name)
425 Report.SymbolRelatedToPreviousError (type);
426 Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
427 TypeManager.CSharpName (type), name);
430 protected static void Error_ValueAssignment (Location loc)
432 Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
435 ResolveFlags ExprClassToResolveFlags
440 case ExprClass.Namespace:
441 return ResolveFlags.Type;
443 case ExprClass.MethodGroup:
444 return ResolveFlags.MethodGroup;
446 case ExprClass.TypeParameter:
447 return ResolveFlags.TypeParameter;
449 case ExprClass.Value:
450 case ExprClass.Variable:
451 case ExprClass.PropertyAccess:
452 case ExprClass.EventAccess:
453 case ExprClass.IndexerAccess:
454 return ResolveFlags.VariableOrValue;
457 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
463 /// Resolves an expression and performs semantic analysis on it.
467 /// Currently Resolve wraps DoResolve to perform sanity
468 /// checking and assertion checking on what we expect from Resolve.
470 public Expression Resolve (EmitContext ec, ResolveFlags flags)
472 if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type)
473 return ResolveAsTypeStep (ec, false);
475 bool do_flow_analysis = ec.DoFlowAnalysis;
476 bool omit_struct_analysis = ec.OmitStructFlowAnalysis;
477 if ((flags & ResolveFlags.DisableFlowAnalysis) != 0)
478 do_flow_analysis = false;
479 if ((flags & ResolveFlags.DisableStructFlowAnalysis) != 0)
480 omit_struct_analysis = true;
483 using (ec.WithFlowAnalysis (do_flow_analysis, omit_struct_analysis)) {
484 if (this is SimpleName) {
485 bool intermediate = (flags & ResolveFlags.Intermediate) == ResolveFlags.Intermediate;
486 e = ((SimpleName) this).DoResolve (ec, intermediate);
495 if ((flags & e.ExprClassToResolveFlags) == 0) {
496 e.Error_UnexpectedKind (flags, loc);
500 if (e.type == null && !(e is Namespace)) {
501 throw new Exception (
502 "Expression " + e.GetType () +
503 " did not set its type after Resolve\n" +
504 "called from: " + this.GetType ());
511 /// Resolves an expression and performs semantic analysis on it.
513 public Expression Resolve (EmitContext ec)
515 Expression e = Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
517 if (e != null && e.eclass == ExprClass.MethodGroup && RootContext.Version == LanguageVersion.ISO_1) {
518 ((MethodGroupExpr) e).ReportUsageError ();
524 public Constant ResolveAsConstant (EmitContext ec, MemberCore mc)
526 Expression e = Resolve (ec);
530 Constant c = e as Constant;
534 if (type != null && TypeManager.IsReferenceType (type))
535 Const.Error_ConstantCanBeInitializedWithNullOnly (type, loc, mc.GetSignatureForError ());
537 Const.Error_ExpressionMustBeConstant (loc, mc.GetSignatureForError ());
543 /// Resolves an expression for LValue assignment
547 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
548 /// checking and assertion checking on what we expect from Resolve
550 public Expression ResolveLValue (EmitContext ec, Expression right_side, Location loc)
552 int errors = Report.Errors;
553 bool out_access = right_side == EmptyExpression.OutAccess;
555 Expression e = DoResolveLValue (ec, right_side);
557 if (e != null && out_access && !(e is IMemoryLocation)) {
558 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
559 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
561 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
562 // e.GetType () + " " + e.GetSignatureForError ());
567 if (errors == Report.Errors) {
569 Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
571 Error_ValueAssignment (loc);
576 if (e.eclass == ExprClass.Invalid)
577 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
579 if ((e.type == null) && !(e is GenericTypeExpr))
580 throw new Exception ("Expression " + e + " did not set its type after Resolve");
586 /// Emits the code for the expression
590 /// The Emit method is invoked to generate the code
591 /// for the expression.
593 public abstract void Emit (EmitContext ec);
595 // Emit code to branch to @target if this expression is equivalent to @on_true.
596 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
597 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
598 // including the use of conditional branches. Note also that a branch MUST be emitted
599 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
602 ec.ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
605 // Emit this expression for its side effects, not for its value.
606 // The default implementation is to emit the value, and then throw it away.
607 // Subclasses can provide more efficient implementations, but those MUST be equivalent
608 public virtual void EmitSideEffect (EmitContext ec)
611 ec.ig.Emit (OpCodes.Pop);
615 /// Protected constructor. Only derivate types should
616 /// be able to be created
619 protected Expression ()
621 eclass = ExprClass.Invalid;
626 /// Returns a fully formed expression after a MemberLookup
629 public static Expression ExprClassFromMemberInfo (Type container_type, MemberInfo mi, Location loc)
632 return new EventExpr ((EventInfo) mi, loc);
633 else if (mi is FieldInfo) {
634 FieldInfo fi = (FieldInfo) mi;
635 if (fi.IsLiteral || (fi.IsInitOnly && fi.FieldType == TypeManager.decimal_type))
636 return new ConstantExpr (fi, loc);
637 return new FieldExpr (fi, loc);
638 } else if (mi is PropertyInfo)
639 return new PropertyExpr (container_type, (PropertyInfo) mi, loc);
640 else if (mi is Type) {
641 return new TypeExpression ((System.Type) mi, loc);
647 // TODO: [Obsolete ("Can be removed")]
648 protected static ArrayList almost_matched_members = new ArrayList (4);
651 // FIXME: Probably implement a cache for (t,name,current_access_set)?
653 // This code could use some optimizations, but we need to do some
654 // measurements. For example, we could use a delegate to `flag' when
655 // something can not any longer be a method-group (because it is something
659 // If the return value is an Array, then it is an array of
662 // If the return value is an MemberInfo, it is anything, but a Method
666 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
667 // the arguments here and have MemberLookup return only the methods that
668 // match the argument count/type, unlike we are doing now (we delay this
671 // This is so we can catch correctly attempts to invoke instance methods
672 // from a static body (scan for error 120 in ResolveSimpleName).
675 // FIXME: Potential optimization, have a static ArrayList
678 public static Expression MemberLookup (Type container_type, Type queried_type, string name,
679 MemberTypes mt, BindingFlags bf, Location loc)
681 return MemberLookup (container_type, null, queried_type, name, mt, bf, loc);
685 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
686 // `qualifier_type' or null to lookup members in the current class.
689 public static Expression MemberLookup (Type container_type,
690 Type qualifier_type, Type queried_type,
691 string name, MemberTypes mt,
692 BindingFlags bf, Location loc)
694 almost_matched_members.Clear ();
696 MemberInfo [] mi = TypeManager.MemberLookup (container_type, qualifier_type,
697 queried_type, mt, bf, name, almost_matched_members);
703 bool is_interface = qualifier_type != null && qualifier_type.IsInterface;
704 ArrayList methods = new ArrayList (2);
705 ArrayList non_methods = null;
707 foreach (MemberInfo m in mi) {
708 if (m is MethodBase) {
713 if (non_methods == null) {
714 non_methods = new ArrayList (2);
719 foreach (MemberInfo n_m in non_methods) {
720 if (m.DeclaringType.IsInterface && TypeManager.ImplementsInterface (m.DeclaringType, n_m.DeclaringType))
723 Report.SymbolRelatedToPreviousError (m);
724 Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
725 TypeManager.GetFullNameSignature (m), TypeManager.GetFullNameSignature (n_m));
730 if (methods.Count == 0)
731 return ExprClassFromMemberInfo (container_type, (MemberInfo)non_methods [0], loc);
733 if (non_methods != null) {
734 MethodBase method = (MethodBase) methods [0];
735 MemberInfo non_method = (MemberInfo) non_methods [0];
736 if (method.DeclaringType == non_method.DeclaringType) {
737 // Cannot happen with C# code, but is valid in IL
738 Report.SymbolRelatedToPreviousError (method);
739 Report.SymbolRelatedToPreviousError (non_method);
740 Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
741 TypeManager.GetFullNameSignature (non_method),
742 TypeManager.CSharpSignature (method));
747 Report.SymbolRelatedToPreviousError (method);
748 Report.SymbolRelatedToPreviousError (non_method);
749 Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and non-method `{1}'. Using method `{0}'",
750 TypeManager.CSharpSignature (method), TypeManager.GetFullNameSignature (non_method));
754 return new MethodGroupExpr (methods, queried_type, loc);
757 if (mi [0] is MethodBase)
758 return new MethodGroupExpr (mi, queried_type, loc);
760 return ExprClassFromMemberInfo (container_type, mi [0], loc);
763 public const MemberTypes AllMemberTypes =
764 MemberTypes.Constructor |
768 MemberTypes.NestedType |
769 MemberTypes.Property;
771 public const BindingFlags AllBindingFlags =
772 BindingFlags.Public |
773 BindingFlags.Static |
774 BindingFlags.Instance;
776 public static Expression MemberLookup (Type container_type, Type queried_type,
777 string name, Location loc)
779 return MemberLookup (container_type, null, queried_type, name,
780 AllMemberTypes, AllBindingFlags, loc);
783 public static Expression MemberLookup (Type container_type, Type qualifier_type,
784 Type queried_type, string name, Location loc)
786 return MemberLookup (container_type, qualifier_type, queried_type,
787 name, AllMemberTypes, AllBindingFlags, loc);
790 public static MethodGroupExpr MethodLookup (Type container_type, Type queried_type,
791 string name, Location loc)
793 return (MethodGroupExpr)MemberLookup (container_type, null, queried_type, name,
794 MemberTypes.Method, AllBindingFlags, loc);
798 /// This is a wrapper for MemberLookup that is not used to "probe", but
799 /// to find a final definition. If the final definition is not found, we
800 /// look for private members and display a useful debugging message if we
803 protected Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
804 Type queried_type, string name,
805 MemberTypes mt, BindingFlags bf,
810 int errors = Report.Errors;
811 e = MemberLookup (ec.ContainerType, qualifier_type, queried_type, name, mt, bf, loc);
813 if (e != null || errors != Report.Errors)
816 // No errors were reported by MemberLookup, but there was an error.
817 return Error_MemberLookupFailed (ec.ContainerType, qualifier_type, queried_type,
821 protected virtual Expression Error_MemberLookupFailed (Type container_type, Type qualifier_type,
822 Type queried_type, string name, string class_name,
823 MemberTypes mt, BindingFlags bf)
825 MemberInfo[] lookup = null;
826 if (queried_type == null) {
827 class_name = "global::";
829 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
830 mt, (bf & ~BindingFlags.Public) | BindingFlags.NonPublic,
833 if (lookup != null) {
834 Expression e = Error_MemberLookupFailed (queried_type, lookup);
837 // FIXME: This is still very wrong, it should be done inside
838 // OverloadResolve to do correct arguments matching.
839 // Requires MemberLookup accessiblity check removal
841 if (e == null || (mt & (MemberTypes.Method | MemberTypes.Constructor)) == 0) {
842 MemberInfo mi = lookup[0];
843 Report.SymbolRelatedToPreviousError (mi);
844 if (qualifier_type != null && container_type != null && qualifier_type != container_type &&
845 TypeManager.IsNestedFamilyAccessible (container_type, mi.DeclaringType)) {
846 // Although a derived class can access protected members of
847 // its base class it cannot do so through an instance of the
848 // base class (CS1540). If the qualifier_type is a base of the
849 // ec.ContainerType and the lookup succeeds with the latter one,
850 // then we are in this situation.
851 Error_CannotAccessProtected (loc, mi, qualifier_type, container_type);
853 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (mi));
860 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
861 AllMemberTypes, AllBindingFlags | BindingFlags.NonPublic,
865 if (lookup == null) {
866 if (class_name != null) {
867 Report.Error (103, loc, "The name `{0}' does not exist in the current context",
870 Error_TypeDoesNotContainDefinition (queried_type, name);
875 if (TypeManager.MemberLookup (queried_type, null, queried_type,
876 AllMemberTypes, AllBindingFlags |
877 BindingFlags.NonPublic, name, null) == null) {
878 if ((lookup.Length == 1) && (lookup [0] is Type)) {
879 Type t = (Type) lookup [0];
881 Report.Error (305, loc,
882 "Using the generic type `{0}' " +
883 "requires {1} type arguments",
884 TypeManager.CSharpName (t),
885 TypeManager.GetNumberOfTypeArguments (t).ToString ());
890 return Error_MemberLookupFailed (queried_type, lookup);
893 protected virtual Expression Error_MemberLookupFailed (Type type, MemberInfo[] members)
895 for (int i = 0; i < members.Length; ++i) {
896 if (!(members [i] is MethodBase))
900 // By default propagate the closest candidates upwards
901 return new MethodGroupExpr (members, type, loc, true);
904 protected virtual void Error_NegativeArrayIndex (Location loc)
906 throw new NotImplementedException ();
909 protected void Error_PointerInsideExpressionTree ()
911 Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
915 /// Returns an expression that can be used to invoke operator true
916 /// on the expression if it exists.
918 static public Expression GetOperatorTrue (EmitContext ec, Expression e, Location loc)
920 return GetOperatorTrueOrFalse (ec, e, true, loc);
924 /// Returns an expression that can be used to invoke operator false
925 /// on the expression if it exists.
927 static public Expression GetOperatorFalse (EmitContext ec, Expression e, Location loc)
929 return GetOperatorTrueOrFalse (ec, e, false, loc);
932 static Expression GetOperatorTrueOrFalse (EmitContext ec, Expression e, bool is_true, Location loc)
934 MethodGroupExpr operator_group;
935 string mname = Operator.GetMetadataName (is_true ? Operator.OpType.True : Operator.OpType.False);
936 operator_group = MethodLookup (ec.ContainerType, e.Type, mname, loc) as MethodGroupExpr;
937 if (operator_group == null)
940 ArrayList arguments = new ArrayList (1);
941 arguments.Add (new Argument (e, Argument.AType.Expression));
942 operator_group = operator_group.OverloadResolve (
943 ec, ref arguments, false, loc);
945 if (operator_group == null)
948 return new UserOperatorCall (operator_group, arguments, null, loc);
952 /// Resolves the expression `e' into a boolean expression: either through
953 /// an implicit conversion, or through an `operator true' invocation
955 public static Expression ResolveBoolean (EmitContext ec, Expression e, Location loc)
961 if (e.Type == TypeManager.bool_type)
964 Expression converted = Convert.ImplicitConversion (ec, e, TypeManager.bool_type, Location.Null);
966 if (converted != null)
970 // If no implicit conversion to bool exists, try using `operator true'
972 converted = Expression.GetOperatorTrue (ec, e, loc);
973 if (converted == null){
974 e.Error_ValueCannotBeConverted (ec, loc, TypeManager.bool_type, false);
980 public virtual string ExprClassName
984 case ExprClass.Invalid:
986 case ExprClass.Value:
988 case ExprClass.Variable:
990 case ExprClass.Namespace:
994 case ExprClass.MethodGroup:
995 return "method group";
996 case ExprClass.PropertyAccess:
997 return "property access";
998 case ExprClass.EventAccess:
999 return "event access";
1000 case ExprClass.IndexerAccess:
1001 return "indexer access";
1002 case ExprClass.Nothing:
1004 case ExprClass.TypeParameter:
1005 return "type parameter";
1007 throw new Exception ("Should not happen");
1012 /// Reports that we were expecting `expr' to be of class `expected'
1014 public void Error_UnexpectedKind (DeclSpace ds, string expected, Location loc)
1016 Error_UnexpectedKind (ds, expected, ExprClassName, loc);
1019 public void Error_UnexpectedKind (DeclSpace ds, string expected, string was, Location loc)
1021 string name = GetSignatureForError ();
1023 name = ds.GetSignatureForError () + '.' + name;
1025 Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
1026 name, was, expected);
1029 public void Error_UnexpectedKind (ResolveFlags flags, Location loc)
1031 string [] valid = new string [4];
1034 if ((flags & ResolveFlags.VariableOrValue) != 0) {
1035 valid [count++] = "variable";
1036 valid [count++] = "value";
1039 if ((flags & ResolveFlags.Type) != 0)
1040 valid [count++] = "type";
1042 if ((flags & ResolveFlags.MethodGroup) != 0)
1043 valid [count++] = "method group";
1046 valid [count++] = "unknown";
1048 StringBuilder sb = new StringBuilder (valid [0]);
1049 for (int i = 1; i < count - 1; i++) {
1051 sb.Append (valid [i]);
1054 sb.Append ("' or `");
1055 sb.Append (valid [count - 1]);
1058 Report.Error (119, loc,
1059 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1062 public static void UnsafeError (Location loc)
1064 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1068 // Load the object from the pointer.
1070 public static void LoadFromPtr (ILGenerator ig, Type t)
1072 if (t == TypeManager.int32_type)
1073 ig.Emit (OpCodes.Ldind_I4);
1074 else if (t == TypeManager.uint32_type)
1075 ig.Emit (OpCodes.Ldind_U4);
1076 else if (t == TypeManager.short_type)
1077 ig.Emit (OpCodes.Ldind_I2);
1078 else if (t == TypeManager.ushort_type)
1079 ig.Emit (OpCodes.Ldind_U2);
1080 else if (t == TypeManager.char_type)
1081 ig.Emit (OpCodes.Ldind_U2);
1082 else if (t == TypeManager.byte_type)
1083 ig.Emit (OpCodes.Ldind_U1);
1084 else if (t == TypeManager.sbyte_type)
1085 ig.Emit (OpCodes.Ldind_I1);
1086 else if (t == TypeManager.uint64_type)
1087 ig.Emit (OpCodes.Ldind_I8);
1088 else if (t == TypeManager.int64_type)
1089 ig.Emit (OpCodes.Ldind_I8);
1090 else if (t == TypeManager.float_type)
1091 ig.Emit (OpCodes.Ldind_R4);
1092 else if (t == TypeManager.double_type)
1093 ig.Emit (OpCodes.Ldind_R8);
1094 else if (t == TypeManager.bool_type)
1095 ig.Emit (OpCodes.Ldind_I1);
1096 else if (t == TypeManager.intptr_type)
1097 ig.Emit (OpCodes.Ldind_I);
1098 else if (TypeManager.IsEnumType (t)) {
1099 if (t == TypeManager.enum_type)
1100 ig.Emit (OpCodes.Ldind_Ref);
1102 LoadFromPtr (ig, TypeManager.GetEnumUnderlyingType (t));
1103 } else if (t.IsValueType || TypeManager.IsGenericParameter (t))
1104 ig.Emit (OpCodes.Ldobj, t);
1105 else if (t.IsPointer)
1106 ig.Emit (OpCodes.Ldind_I);
1108 ig.Emit (OpCodes.Ldind_Ref);
1112 // The stack contains the pointer and the value of type `type'
1114 public static void StoreFromPtr (ILGenerator ig, Type type)
1116 if (TypeManager.IsEnumType (type))
1117 type = TypeManager.GetEnumUnderlyingType (type);
1118 if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
1119 ig.Emit (OpCodes.Stind_I4);
1120 else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
1121 ig.Emit (OpCodes.Stind_I8);
1122 else if (type == TypeManager.char_type || type == TypeManager.short_type ||
1123 type == TypeManager.ushort_type)
1124 ig.Emit (OpCodes.Stind_I2);
1125 else if (type == TypeManager.float_type)
1126 ig.Emit (OpCodes.Stind_R4);
1127 else if (type == TypeManager.double_type)
1128 ig.Emit (OpCodes.Stind_R8);
1129 else if (type == TypeManager.byte_type || type == TypeManager.sbyte_type ||
1130 type == TypeManager.bool_type)
1131 ig.Emit (OpCodes.Stind_I1);
1132 else if (type == TypeManager.intptr_type)
1133 ig.Emit (OpCodes.Stind_I);
1134 else if (type.IsValueType || TypeManager.IsGenericParameter (type))
1135 ig.Emit (OpCodes.Stobj, type);
1137 ig.Emit (OpCodes.Stind_Ref);
1141 // Returns the size of type `t' if known, otherwise, 0
1143 public static int GetTypeSize (Type t)
1145 t = TypeManager.TypeToCoreType (t);
1146 if (t == TypeManager.int32_type ||
1147 t == TypeManager.uint32_type ||
1148 t == TypeManager.float_type)
1150 else if (t == TypeManager.int64_type ||
1151 t == TypeManager.uint64_type ||
1152 t == TypeManager.double_type)
1154 else if (t == TypeManager.byte_type ||
1155 t == TypeManager.sbyte_type ||
1156 t == TypeManager.bool_type)
1158 else if (t == TypeManager.short_type ||
1159 t == TypeManager.char_type ||
1160 t == TypeManager.ushort_type)
1162 else if (t == TypeManager.decimal_type)
1168 protected void Error_CannotCallAbstractBase (string name)
1170 Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
1173 protected void Error_CannotModifyIntermediateExpressionValue (EmitContext ec)
1175 Report.SymbolRelatedToPreviousError (type);
1176 if (ec.CurrentInitializerVariable != null) {
1177 Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
1178 TypeManager.CSharpName (type), GetSignatureForError ());
1180 Report.Error (1612, loc, "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
1181 GetSignatureForError ());
1185 public void Error_ExpressionCannotBeGeneric (Location loc)
1187 Report.Error (307, loc, "The {0} `{1}' cannot be used with type arguments",
1188 ExprClassName, GetSignatureForError ());
1192 // Converts `source' to an int, uint, long or ulong.
1194 public Expression ConvertExpressionToArrayIndex (EmitContext ec, Expression source)
1196 Expression converted;
1198 using (ec.With (EmitContext.Flags.CheckState, true)) {
1199 converted = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, source.loc);
1200 if (converted == null)
1201 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, source.loc);
1202 if (converted == null)
1203 converted = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, source.loc);
1204 if (converted == null)
1205 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, source.loc);
1207 if (converted == null) {
1208 source.Error_ValueCannotBeConverted (ec, source.loc, TypeManager.int32_type, false);
1214 // Only positive constants are allowed at compile time
1216 Constant c = converted as Constant;
1219 Error_NegativeArrayIndex (source.loc);
1224 return new ArrayIndexCast (converted).Resolve (ec);
1228 // Derived classes implement this method by cloning the fields that
1229 // could become altered during the Resolve stage
1231 // Only expressions that are created for the parser need to implement
1234 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1236 throw new NotImplementedException (
1238 "CloneTo not implemented for expression {0}", this.GetType ()));
1242 // Clones an expression created by the parser.
1244 // We only support expressions created by the parser so far, not
1245 // expressions that have been resolved (many more classes would need
1246 // to implement CloneTo).
1248 // This infrastructure is here merely for Lambda expressions which
1249 // compile the same code using different type values for the same
1250 // arguments to find the correct overload
1252 public Expression Clone (CloneContext clonectx)
1254 Expression cloned = (Expression) MemberwiseClone ();
1255 CloneTo (clonectx, cloned);
1261 // Implementation of expression to expression tree conversion
1263 public abstract Expression CreateExpressionTree (EmitContext ec);
1265 protected Expression CreateExpressionFactoryCall (string name, ArrayList args)
1267 return CreateExpressionFactoryCall (name, null, args, loc);
1270 protected Expression CreateExpressionFactoryCall (string name, TypeArguments typeArguments, ArrayList args)
1272 return CreateExpressionFactoryCall (name, typeArguments, args, loc);
1275 public static Expression CreateExpressionFactoryCall (string name, TypeArguments typeArguments, ArrayList args, Location loc)
1277 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (loc), name, typeArguments, loc), args);
1280 protected static TypeExpr CreateExpressionTypeExpression (Location loc)
1282 TypeExpr texpr = TypeManager.expression_type_expr;
1283 if (texpr == null) {
1284 Type t = TypeManager.CoreLookupType ("System.Linq.Expressions", "Expression", Kind.Class, true);
1288 TypeManager.expression_type_expr = texpr = new TypeExpression (t, Location.Null);
1294 public virtual void MutateHoistedGenericType (AnonymousMethodStorey storey)
1296 // TODO: It should probably be type = storey.MutateType (type);
1301 /// This is just a base class for expressions that can
1302 /// appear on statements (invocations, object creation,
1303 /// assignments, post/pre increment and decrement). The idea
1304 /// being that they would support an extra Emition interface that
1305 /// does not leave a result on the stack.
1307 public abstract class ExpressionStatement : Expression {
1309 public virtual ExpressionStatement ResolveStatement (EmitContext ec)
1311 Expression e = Resolve (ec);
1315 ExpressionStatement es = e as ExpressionStatement;
1317 Error_InvalidExpressionStatement ();
1323 /// Requests the expression to be emitted in a `statement'
1324 /// context. This means that no new value is left on the
1325 /// stack after invoking this method (constrasted with
1326 /// Emit that will always leave a value on the stack).
1328 public abstract void EmitStatement (EmitContext ec);
1330 public override void EmitSideEffect (EmitContext ec)
1337 /// This kind of cast is used to encapsulate the child
1338 /// whose type is child.Type into an expression that is
1339 /// reported to return "return_type". This is used to encapsulate
1340 /// expressions which have compatible types, but need to be dealt
1341 /// at higher levels with.
1343 /// For example, a "byte" expression could be encapsulated in one
1344 /// of these as an "unsigned int". The type for the expression
1345 /// would be "unsigned int".
1348 public abstract class TypeCast : Expression
1350 protected readonly Expression child;
1352 protected TypeCast (Expression child, Type return_type)
1354 eclass = child.eclass;
1355 loc = child.Location;
1360 public override Expression CreateExpressionTree (EmitContext ec)
1362 ArrayList args = new ArrayList (2);
1363 args.Add (new Argument (child.CreateExpressionTree (ec)));
1364 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1366 if (type.IsPointer || child.Type.IsPointer)
1367 Error_PointerInsideExpressionTree ();
1369 return CreateExpressionFactoryCall (ec.CheckState ? "ConvertChecked" : "Convert", args);
1372 public override Expression DoResolve (EmitContext ec)
1374 // This should never be invoked, we are born in fully
1375 // initialized state.
1380 public override void Emit (EmitContext ec)
1385 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
1387 return child.GetAttributableValue (ec, value_type, out value);
1390 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1392 type = storey.MutateType (type);
1393 child.MutateHoistedGenericType (storey);
1396 protected override void CloneTo (CloneContext clonectx, Expression t)
1401 public override bool IsNull {
1402 get { return child.IsNull; }
1406 public class EmptyCast : TypeCast {
1407 EmptyCast (Expression child, Type target_type)
1408 : base (child, target_type)
1412 public static Expression Create (Expression child, Type type)
1414 Constant c = child as Constant;
1416 return new EmptyConstantCast (c, type);
1418 EmptyCast e = child as EmptyCast;
1420 return new EmptyCast (e.child, type);
1422 return new EmptyCast (child, type);
1425 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1427 child.EmitBranchable (ec, label, on_true);
1430 public override void EmitSideEffect (EmitContext ec)
1432 child.EmitSideEffect (ec);
1437 // Used for predefined class library user casts (no obsolete check, etc.)
1439 public class OperatorCast : TypeCast {
1440 MethodInfo conversion_operator;
1442 public OperatorCast (Expression child, Type target_type)
1443 : this (child, target_type, false)
1447 public OperatorCast (Expression child, Type target_type, bool find_explicit)
1448 : base (child, target_type)
1450 conversion_operator = GetConversionOperator (find_explicit);
1451 if (conversion_operator == null)
1452 throw new InternalErrorException ("Outer conversion routine is out of sync");
1455 // Returns the implicit operator that converts from
1456 // 'child.Type' to our target type (type)
1457 MethodInfo GetConversionOperator (bool find_explicit)
1459 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1463 mi = TypeManager.MemberLookup (child.Type, child.Type, child.Type, MemberTypes.Method,
1464 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1467 mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1468 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1471 foreach (MethodInfo oper in mi) {
1472 AParametersCollection pd = TypeManager.GetParameterData (oper);
1474 if (pd.Types [0] == child.Type && TypeManager.TypeToCoreType (oper.ReturnType) == type)
1481 public override void Emit (EmitContext ec)
1484 ec.ig.Emit (OpCodes.Call, conversion_operator);
1489 /// This is a numeric cast to a Decimal
1491 public class CastToDecimal : OperatorCast {
1492 public CastToDecimal (Expression child)
1493 : this (child, false)
1497 public CastToDecimal (Expression child, bool find_explicit)
1498 : base (child, TypeManager.decimal_type, find_explicit)
1504 /// This is an explicit numeric cast from a Decimal
1506 public class CastFromDecimal : TypeCast
1508 static IDictionary operators;
1510 public CastFromDecimal (Expression child, Type return_type)
1511 : base (child, return_type)
1513 if (child.Type != TypeManager.decimal_type)
1514 throw new InternalErrorException (
1515 "The expected type is Decimal, instead it is " + child.Type.FullName);
1518 // Returns the explicit operator that converts from an
1519 // express of type System.Decimal to 'type'.
1520 public Expression Resolve ()
1522 if (operators == null) {
1523 MemberInfo[] all_oper = TypeManager.MemberLookup (TypeManager.decimal_type,
1524 TypeManager.decimal_type, TypeManager.decimal_type, MemberTypes.Method,
1525 BindingFlags.Static | BindingFlags.Public, "op_Explicit", null);
1527 operators = new System.Collections.Specialized.HybridDictionary ();
1528 foreach (MethodInfo oper in all_oper) {
1529 AParametersCollection pd = TypeManager.GetParameterData (oper);
1530 if (pd.Types [0] == TypeManager.decimal_type)
1531 operators.Add (TypeManager.TypeToCoreType (oper.ReturnType), oper);
1535 return operators.Contains (type) ? this : null;
1538 public override void Emit (EmitContext ec)
1540 ILGenerator ig = ec.ig;
1543 ig.Emit (OpCodes.Call, (MethodInfo)operators [type]);
1549 // Constant specialization of EmptyCast.
1550 // We need to special case this since an empty cast of
1551 // a constant is still a constant.
1553 public class EmptyConstantCast : Constant
1555 public readonly Constant child;
1557 public EmptyConstantCast(Constant child, Type type)
1558 : base (child.Location)
1560 eclass = child.eclass;
1565 public override string AsString ()
1567 return child.AsString ();
1570 public override object GetValue ()
1572 return child.GetValue ();
1575 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
1577 // FIXME: check that 'type' can be converted to 'target_type' first
1578 return child.ConvertExplicitly (in_checked_context, target_type);
1581 public override Expression CreateExpressionTree (EmitContext ec)
1583 ArrayList args = new ArrayList (2);
1584 args.Add (new Argument (child.CreateExpressionTree (ec)));
1585 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1587 Error_PointerInsideExpressionTree ();
1589 return CreateExpressionFactoryCall ("Convert", args);
1592 public override Constant Increment ()
1594 return child.Increment ();
1597 public override bool IsDefaultValue {
1598 get { return child.IsDefaultValue; }
1601 public override bool IsNegative {
1602 get { return child.IsNegative; }
1605 public override bool IsNull {
1606 get { return child.IsNull; }
1609 public override bool IsZeroInteger {
1610 get { return child.IsZeroInteger; }
1613 public override void Emit (EmitContext ec)
1618 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1620 child.EmitBranchable (ec, label, on_true);
1623 public override void EmitSideEffect (EmitContext ec)
1625 child.EmitSideEffect (ec);
1628 public override Constant ConvertImplicitly (Type target_type)
1630 // FIXME: Do we need to check user conversions?
1631 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1633 return child.ConvertImplicitly (target_type);
1636 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1638 child.MutateHoistedGenericType (storey);
1644 /// This class is used to wrap literals which belong inside Enums
1646 public class EnumConstant : Constant {
1647 public Constant Child;
1649 public EnumConstant (Constant child, Type enum_type):
1650 base (child.Location)
1652 eclass = child.eclass;
1657 public override Expression DoResolve (EmitContext ec)
1659 // This should never be invoked, we are born in fully
1660 // initialized state.
1665 public override void Emit (EmitContext ec)
1670 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1672 Child.EmitBranchable (ec, label, on_true);
1675 public override void EmitSideEffect (EmitContext ec)
1677 Child.EmitSideEffect (ec);
1680 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
1682 value = GetTypedValue ();
1686 public override string GetSignatureForError()
1688 return TypeManager.CSharpName (Type);
1691 public override object GetValue ()
1693 return Child.GetValue ();
1696 public override object GetTypedValue ()
1698 // FIXME: runtime is not ready to work with just emited enums
1699 if (!RootContext.StdLib) {
1700 return Child.GetValue ();
1704 // Small workaround for big problem
1705 // System.Enum.ToObject cannot be called on dynamic types
1706 // EnumBuilder has to be used, but we cannot use EnumBuilder
1707 // because it does not properly support generics
1709 // This works only sometimes
1711 if (type.Module == CodeGen.Module.Builder)
1712 return Child.GetValue ();
1715 return System.Enum.ToObject (type, Child.GetValue ());
1718 public override string AsString ()
1720 return Child.AsString ();
1723 public override Constant Increment()
1725 return new EnumConstant (Child.Increment (), type);
1728 public override bool IsDefaultValue {
1730 return Child.IsDefaultValue;
1734 public override bool IsZeroInteger {
1735 get { return Child.IsZeroInteger; }
1738 public override bool IsNegative {
1740 return Child.IsNegative;
1744 public override Constant ConvertExplicitly(bool in_checked_context, Type target_type)
1746 if (Child.Type == target_type)
1749 return Child.ConvertExplicitly (in_checked_context, target_type);
1752 public override Constant ConvertImplicitly (Type type)
1754 Type this_type = TypeManager.DropGenericTypeArguments (Type);
1755 type = TypeManager.DropGenericTypeArguments (type);
1757 if (this_type == type) {
1758 // This is workaround of mono bug. It can be removed when the latest corlib spreads enough
1759 if (TypeManager.IsEnumType (type.UnderlyingSystemType))
1762 Type child_type = TypeManager.DropGenericTypeArguments (Child.Type);
1763 if (type.UnderlyingSystemType != child_type)
1764 Child = Child.ConvertImplicitly (type.UnderlyingSystemType);
1768 if (!Convert.ImplicitStandardConversionExists (this, type)){
1772 return Child.ConvertImplicitly(type);
1778 /// This kind of cast is used to encapsulate Value Types in objects.
1780 /// The effect of it is to box the value type emitted by the previous
1783 public class BoxedCast : TypeCast {
1785 public BoxedCast (Expression expr, Type target_type)
1786 : base (expr, target_type)
1788 eclass = ExprClass.Value;
1791 public override Expression DoResolve (EmitContext ec)
1793 // This should never be invoked, we are born in fully
1794 // initialized state.
1799 public override void Emit (EmitContext ec)
1803 ec.ig.Emit (OpCodes.Box, child.Type);
1806 public override void EmitSideEffect (EmitContext ec)
1808 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1809 // so, we need to emit the box+pop instructions in most cases
1810 if (child.Type.IsValueType &&
1811 (type == TypeManager.object_type || type == TypeManager.value_type))
1812 child.EmitSideEffect (ec);
1814 base.EmitSideEffect (ec);
1818 public class UnboxCast : TypeCast {
1819 public UnboxCast (Expression expr, Type return_type)
1820 : base (expr, return_type)
1824 public override Expression DoResolve (EmitContext ec)
1826 // This should never be invoked, we are born in fully
1827 // initialized state.
1832 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1834 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
1835 Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
1836 return base.DoResolveLValue (ec, right_side);
1839 public override void Emit (EmitContext ec)
1841 ILGenerator ig = ec.ig;
1845 if (type.IsGenericParameter || type.IsGenericType && type.IsValueType)
1846 ig.Emit (OpCodes.Unbox_Any, type);
1850 ig.Emit (OpCodes.Unbox, type);
1852 LoadFromPtr (ig, type);
1856 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1858 type = storey.MutateType (type);
1859 base.MutateHoistedGenericType (storey);
1864 /// This is used to perform explicit numeric conversions.
1866 /// Explicit numeric conversions might trigger exceptions in a checked
1867 /// context, so they should generate the conv.ovf opcodes instead of
1870 public class ConvCast : TypeCast {
1871 public enum Mode : byte {
1872 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1874 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1875 U2_I1, U2_U1, U2_I2, U2_CH,
1876 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1877 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1878 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH,
1879 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH,
1880 CH_I1, CH_U1, CH_I2,
1881 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1882 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4
1887 public ConvCast (Expression child, Type return_type, Mode m)
1888 : base (child, return_type)
1893 public override Expression DoResolve (EmitContext ec)
1895 // This should never be invoked, we are born in fully
1896 // initialized state.
1901 public override string ToString ()
1903 return String.Format ("ConvCast ({0}, {1})", mode, child);
1906 public override void Emit (EmitContext ec)
1908 ILGenerator ig = ec.ig;
1914 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1915 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1916 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1917 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1918 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1920 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1921 case Mode.U1_CH: /* nothing */ break;
1923 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1924 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1925 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1926 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1927 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1928 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1930 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1931 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1932 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1933 case Mode.U2_CH: /* nothing */ break;
1935 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1936 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1937 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1938 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1939 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1940 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1941 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1943 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1944 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1945 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1946 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1947 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1948 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1950 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1951 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1952 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1953 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1954 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1955 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1956 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1957 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1959 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1960 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1961 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1962 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1963 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1964 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1965 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1966 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1968 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1969 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1970 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1972 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1973 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1974 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1975 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1976 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1977 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1978 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1979 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1980 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1982 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1983 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1984 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1985 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1986 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1987 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1988 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1989 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1990 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1991 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1995 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
1996 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
1997 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
1998 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
1999 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
2001 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
2002 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
2004 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
2005 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
2006 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
2007 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
2008 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
2009 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
2011 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
2012 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
2013 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
2014 case Mode.U2_CH: /* nothing */ break;
2016 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
2017 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
2018 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
2019 case Mode.I4_U4: /* nothing */ break;
2020 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
2021 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
2022 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
2024 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
2025 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
2026 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
2027 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
2028 case Mode.U4_I4: /* nothing */ break;
2029 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
2031 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
2032 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
2033 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
2034 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
2035 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
2036 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
2037 case Mode.I8_U8: /* nothing */ break;
2038 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
2040 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
2041 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
2042 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
2043 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
2044 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
2045 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
2046 case Mode.U8_I8: /* nothing */ break;
2047 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
2049 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
2050 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
2051 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
2053 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
2054 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
2055 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
2056 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
2057 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
2058 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
2059 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
2060 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
2061 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
2063 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
2064 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
2065 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
2066 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
2067 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
2068 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
2069 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
2070 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
2071 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
2072 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
2078 public class OpcodeCast : TypeCast {
2081 public OpcodeCast (Expression child, Type return_type, OpCode op)
2082 : base (child, return_type)
2087 public override Expression DoResolve (EmitContext ec)
2089 // This should never be invoked, we are born in fully
2090 // initialized state.
2095 public override void Emit (EmitContext ec)
2101 public Type UnderlyingType {
2102 get { return child.Type; }
2107 /// This kind of cast is used to encapsulate a child and cast it
2108 /// to the class requested
2110 public sealed class ClassCast : TypeCast {
2111 Type child_generic_parameter;
2113 public ClassCast (Expression child, Type return_type)
2114 : base (child, return_type)
2117 if (TypeManager.IsGenericParameter (child.Type))
2118 child_generic_parameter = child.Type;
2121 public override Expression DoResolve (EmitContext ec)
2123 // This should never be invoked, we are born in fully
2124 // initialized state.
2129 public override void Emit (EmitContext ec)
2134 if (child_generic_parameter != null) {
2135 ec.ig.Emit (OpCodes.Box, child_generic_parameter);
2138 if (type.IsGenericParameter)
2139 ec.ig.Emit (OpCodes.Unbox_Any, type);
2140 else if (child_generic_parameter == null)
2142 ec.ig.Emit (OpCodes.Castclass, type);
2145 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2147 type = storey.MutateType (type);
2148 if (child_generic_parameter != null)
2149 child_generic_parameter = storey.MutateGenericArgument (child_generic_parameter);
2151 base.MutateHoistedGenericType (storey);
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 RootNamespace.Global.Assemblies) {
2534 Type type = a.GetType (fullname);
2536 Report.SymbolRelatedToPreviousError (type);
2537 Expression.ErrorIsInaccesible (loc, TypeManager.CSharpName (type));
2542 Type t = ec.DeclContainer.LookupAnyGeneric (Name);
2544 Namespace.Error_InvalidNumberOfTypeArguments (t, loc);
2548 if (targs != null) {
2549 FullNamedExpression retval = ec.DeclContainer.LookupNamespaceOrType (SimpleName.RemoveGenericArity (Name), loc, true);
2550 if (retval != null) {
2551 Namespace.Error_TypeArgumentsCannotBeUsed (retval, loc);
2556 NamespaceEntry.Error_NamespaceNotFound (loc, Name);
2559 // TODO: I am still not convinced about this. If someone else will need it
2560 // implement this as virtual property in MemberCore hierarchy
2561 public static string GetMemberType (MemberCore mc)
2567 if (mc is FieldBase)
2569 if (mc is MethodCore)
2571 if (mc is EnumMember)
2579 Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2585 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2591 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2598 /// 7.5.2: Simple Names.
2600 /// Local Variables and Parameters are handled at
2601 /// parse time, so they never occur as SimpleNames.
2603 /// The `intermediate' flag is used by MemberAccess only
2604 /// and it is used to inform us that it is ok for us to
2605 /// avoid the static check, because MemberAccess might end
2606 /// up resolving the Name as a Type name and the access as
2607 /// a static type access.
2609 /// ie: Type Type; .... { Type.GetType (""); }
2611 /// Type is both an instance variable and a Type; Type.GetType
2612 /// is the static method not an instance method of type.
2614 Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2616 Expression e = null;
2619 // Stage 1: Performed by the parser (binding to locals or parameters).
2621 Block current_block = ec.CurrentBlock;
2622 if (current_block != null){
2623 LocalInfo vi = current_block.GetLocalInfo (Name);
2625 LocalVariableReference var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2626 if (right_side != null) {
2627 return var.ResolveLValue (ec, right_side, loc);
2629 ResolveFlags rf = ResolveFlags.VariableOrValue;
2631 rf |= ResolveFlags.DisableFlowAnalysis;
2632 return var.Resolve (ec, rf);
2636 Expression expr = current_block.Toplevel.GetParameterReference (Name, loc);
2638 if (right_side != null)
2639 return expr.ResolveLValue (ec, right_side, loc);
2641 return expr.Resolve (ec);
2646 // Stage 2: Lookup members
2649 Type almost_matched_type = null;
2650 ArrayList almost_matched = null;
2651 for (DeclSpace lookup_ds = ec.DeclContainer; lookup_ds != null; lookup_ds = lookup_ds.Parent) {
2652 // either RootDeclSpace or GenericMethod
2653 if (lookup_ds.TypeBuilder == null)
2656 e = MemberLookup (ec.ContainerType, lookup_ds.TypeBuilder, Name, loc);
2658 PropertyExpr pe = e as PropertyExpr;
2660 AParametersCollection param = TypeManager.GetParameterData (pe.PropertyInfo);
2662 // since TypeManager.MemberLookup doesn't know if we're doing a lvalue access or not,
2663 // it doesn't know which accessor to check permissions against
2664 if (param.IsEmpty && pe.IsAccessibleFrom (ec.ContainerType, right_side != null))
2666 } else if (e is EventExpr) {
2667 if (((EventExpr) e).IsAccessibleFrom (ec.ContainerType))
2669 } else if (targs != null && e is TypeExpression) {
2670 e = new GenericTypeExpr (e.Type, targs, loc).ResolveAsTypeStep (ec, false);
2678 if (almost_matched == null && almost_matched_members.Count > 0) {
2679 almost_matched_type = lookup_ds.TypeBuilder;
2680 almost_matched = (ArrayList) almost_matched_members.Clone ();
2685 if (almost_matched == null && almost_matched_members.Count > 0) {
2686 almost_matched_type = ec.ContainerType;
2687 almost_matched = (ArrayList) almost_matched_members.Clone ();
2689 e = ResolveAsTypeStep (ec, true);
2693 if (current_block != null) {
2694 IKnownVariable ikv = current_block.Explicit.GetKnownVariable (Name);
2696 LocalInfo li = ikv as LocalInfo;
2697 // Supress CS0219 warning
2701 Error_VariableIsUsedBeforeItIsDeclared (Name);
2706 if (RootContext.EvalMode){
2707 FieldInfo fi = Evaluator.LookupField (Name);
2709 return new FieldExpr (fi, loc).Resolve (ec);
2712 if (almost_matched != null)
2713 almost_matched_members = almost_matched;
2714 if (almost_matched_type == null)
2715 almost_matched_type = ec.ContainerType;
2716 return Error_MemberLookupFailed (ec.ContainerType, null, almost_matched_type, Name,
2717 ec.DeclContainer.Name, AllMemberTypes, AllBindingFlags);
2720 if (e is MemberExpr) {
2721 MemberExpr me = (MemberExpr) e;
2724 if (me.IsInstance) {
2725 if (ec.IsStatic || ec.IsInFieldInitializer) {
2727 // Note that an MemberExpr can be both IsInstance and IsStatic.
2728 // An unresolved MethodGroupExpr can contain both kinds of methods
2729 // and each predicate is true if the MethodGroupExpr contains
2730 // at least one of that kind of method.
2734 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2735 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2740 // Pass the buck to MemberAccess and Invocation.
2742 left = EmptyExpression.Null;
2744 left = ec.GetThis (loc);
2747 left = new TypeExpression (ec.ContainerType, loc);
2750 me = me.ResolveMemberAccess (ec, left, loc, null);
2754 if (targs != null) {
2755 if (!targs.Resolve (ec))
2758 me.SetTypeArguments (targs);
2761 if (!me.IsStatic && (me.InstanceExpression != null) &&
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 AsAccessible (DeclSpace ds)
2840 return ds.IsAccessibleAs (Type);
2843 public virtual bool IsClass {
2844 get { return Type.IsClass; }
2847 public virtual bool IsValueType {
2848 get { return Type.IsValueType; }
2851 public virtual bool IsInterface {
2852 get { return Type.IsInterface; }
2855 public virtual bool IsSealed {
2856 get { return Type.IsSealed; }
2859 public virtual bool CanInheritFrom ()
2861 if (Type == TypeManager.enum_type ||
2862 (Type == TypeManager.value_type && RootContext.StdLib) ||
2863 Type == TypeManager.multicast_delegate_type ||
2864 Type == TypeManager.delegate_type ||
2865 Type == TypeManager.array_type)
2871 protected abstract TypeExpr DoResolveAsTypeStep (IResolveContext ec);
2873 public override bool Equals (object obj)
2875 TypeExpr tobj = obj as TypeExpr;
2879 return Type == tobj.Type;
2882 public override int GetHashCode ()
2884 return Type.GetHashCode ();
2887 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2889 type = storey.MutateType (type);
2894 /// Fully resolved Expression that already evaluated to a type
2896 public class TypeExpression : TypeExpr {
2897 public TypeExpression (Type t, Location l)
2900 eclass = ExprClass.Type;
2904 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2909 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2916 /// Used to create types from a fully qualified name. These are just used
2917 /// by the parser to setup the core types. A TypeLookupExpression is always
2918 /// classified as a type.
2920 public sealed class TypeLookupExpression : TypeExpr {
2921 readonly string name;
2923 public TypeLookupExpression (string name)
2926 eclass = ExprClass.Type;
2929 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2931 // It's null for corlib compilation only
2933 return DoResolveAsTypeStep (ec);
2938 private class UnexpectedType
2942 // This performes recursive type lookup, providing support for generic types.
2943 // For example, given the type:
2945 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]]
2947 // The types will be checked in the following order:
2950 // System.Collections |
2951 // System.Collections.Generic |
2953 // System | recursive call 1 |
2954 // System.Int32 _| | main method call
2956 // System | recursive call 2 |
2957 // System.String _| |
2959 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]] _|
2961 private Type TypeLookup (IResolveContext ec, string name)
2966 FullNamedExpression resolved = null;
2968 Type recursive_type = null;
2969 while (index < name.Length) {
2970 if (name[index] == '[') {
2975 if (name[index] == '[')
2977 else if (name[index] == ']')
2979 } while (braces > 0);
2980 recursive_type = TypeLookup (ec, name.Substring (open + 1, index - open - 1));
2981 if (recursive_type == null || (recursive_type == typeof(UnexpectedType)))
2982 return recursive_type;
2985 if (name[index] == ',')
2987 else if ((name[index] == '.' && !done) || (index == name.Length && name[0] != '[')) {
2988 string substring = name.Substring(dot, index - dot);
2990 if (resolved == null)
2991 resolved = RootNamespace.Global.Lookup (ec.DeclContainer, substring, Location.Null);
2992 else if (resolved is Namespace)
2993 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
2994 else if (type != null)
2995 type = TypeManager.GetNestedType (type, substring);
2999 if (resolved == null)
3001 else if (type == null && resolved is TypeExpr)
3002 type = resolved.Type;
3009 if (name[0] != '[') {
3010 string substring = name.Substring(dot, index - dot);
3013 return TypeManager.GetNestedType (type, substring);
3015 if (resolved != null) {
3016 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
3017 if (resolved is TypeExpr)
3018 return resolved.Type;
3020 if (resolved == null)
3023 resolved.Error_UnexpectedKind (ec.DeclContainer, "type", loc);
3024 return typeof (UnexpectedType);
3030 return recursive_type;
3033 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
3035 Type t = TypeLookup (ec, name);
3037 NamespaceEntry.Error_NamespaceNotFound (loc, name);
3040 if (t == typeof(UnexpectedType))
3046 public override string GetSignatureForError ()
3049 return TypeManager.CSharpName (name, null);
3051 return base.GetSignatureForError ();
3056 /// This class denotes an expression which evaluates to a member
3057 /// of a struct or a class.
3059 public abstract class MemberExpr : Expression
3061 protected bool is_base;
3064 /// The name of this member.
3066 public abstract string Name {
3071 // When base.member is used
3073 public bool IsBase {
3074 get { return is_base; }
3075 set { is_base = value; }
3079 /// Whether this is an instance member.
3081 public abstract bool IsInstance {
3086 /// Whether this is a static member.
3088 public abstract bool IsStatic {
3093 /// The type which declares this member.
3095 public abstract Type DeclaringType {
3100 /// The instance expression associated with this member, if it's a
3101 /// non-static member.
3103 public Expression InstanceExpression;
3105 public static void error176 (Location loc, string name)
3107 Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
3108 "with an instance reference, qualify it with a type name instead", name);
3111 public static void Error_BaseAccessInExpressionTree (Location loc)
3113 Report.Error (831, loc, "An expression tree may not contain a base access");
3116 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3118 if (InstanceExpression != null)
3119 InstanceExpression.MutateHoistedGenericType (storey);
3122 // TODO: possible optimalization
3123 // Cache resolved constant result in FieldBuilder <-> expression map
3124 public virtual MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3125 SimpleName original)
3129 // original == null || original.Resolve (...) ==> left
3132 if (left is TypeExpr) {
3133 left = left.ResolveAsBaseTerminal (ec, false);
3137 // TODO: Same problem as in class.cs, TypeTerminal does not
3138 // always do all necessary checks
3139 ObsoleteAttribute oa = AttributeTester.GetObsoleteAttribute (left.Type);
3140 if (oa != null && !ec.IsInObsoleteScope) {
3141 AttributeTester.Report_ObsoleteMessage (oa, left.GetSignatureForError (), loc);
3144 GenericTypeExpr ct = left as GenericTypeExpr;
3145 if (ct != null && !ct.CheckConstraints (ec))
3150 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3158 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3161 return ResolveExtensionMemberAccess (left);
3164 InstanceExpression = left;
3168 protected virtual MemberExpr ResolveExtensionMemberAccess (Expression left)
3170 error176 (loc, GetSignatureForError ());
3174 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3179 if (InstanceExpression == EmptyExpression.Null) {
3180 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3184 if (InstanceExpression.Type.IsValueType) {
3185 if (InstanceExpression is IMemoryLocation) {
3186 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
3188 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
3189 InstanceExpression.Emit (ec);
3191 t.AddressOf (ec, AddressOp.Store);
3194 InstanceExpression.Emit (ec);
3196 if (prepare_for_load)
3197 ec.ig.Emit (OpCodes.Dup);
3200 public virtual void SetTypeArguments (TypeArguments ta)
3202 // TODO: need to get correct member type
3203 Report.Error (307, loc, "The property `{0}' cannot be used with type arguments",
3204 GetSignatureForError ());
3209 /// Represents group of extension methods
3211 public class ExtensionMethodGroupExpr : MethodGroupExpr
3213 readonly NamespaceEntry namespace_entry;
3214 public Expression ExtensionExpression;
3215 Argument extension_argument;
3217 public ExtensionMethodGroupExpr (ArrayList list, NamespaceEntry n, Type extensionType, Location l)
3218 : base (list, extensionType, l)
3220 this.namespace_entry = n;
3223 public override bool IsStatic {
3224 get { return true; }
3227 public bool IsTopLevel {
3228 get { return namespace_entry == null; }
3231 public override void EmitArguments (EmitContext ec, ArrayList arguments)
3233 if (arguments == null)
3234 arguments = new ArrayList (1);
3235 arguments.Insert (0, extension_argument);
3236 base.EmitArguments (ec, arguments);
3239 public override void EmitCall (EmitContext ec, ArrayList arguments)
3241 if (arguments == null)
3242 arguments = new ArrayList (1);
3243 arguments.Insert (0, extension_argument);
3244 base.EmitCall (ec, arguments);
3247 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3249 extension_argument.Expr.MutateHoistedGenericType (storey);
3250 base.MutateHoistedGenericType (storey);
3253 public override MethodGroupExpr OverloadResolve (EmitContext ec, ref ArrayList arguments, bool may_fail, Location loc)
3255 if (arguments == null)
3256 arguments = new ArrayList (1);
3258 arguments.Insert (0, new Argument (ExtensionExpression));
3259 MethodGroupExpr mg = ResolveOverloadExtensions (ec, arguments, namespace_entry, loc);
3261 // Store resolved argument and restore original arguments
3263 ((ExtensionMethodGroupExpr)mg).extension_argument = (Argument)arguments [0];
3264 arguments.RemoveAt (0);
3269 MethodGroupExpr ResolveOverloadExtensions (EmitContext ec, ArrayList arguments, NamespaceEntry ns, Location loc)
3271 // Use normal resolve rules
3272 MethodGroupExpr mg = base.OverloadResolve (ec, ref arguments, ns != null, loc);
3280 ExtensionMethodGroupExpr e = ns.LookupExtensionMethod (type, null, Name, loc);
3282 return base.OverloadResolve (ec, ref arguments, false, loc);
3284 e.ExtensionExpression = ExtensionExpression;
3285 e.SetTypeArguments (type_arguments);
3286 return e.ResolveOverloadExtensions (ec, arguments, e.namespace_entry, loc);
3291 /// MethodGroupExpr represents a group of method candidates which
3292 /// can be resolved to the best method overload
3294 public class MethodGroupExpr : MemberExpr
3296 public interface IErrorHandler
3298 bool AmbiguousCall (MethodBase ambiguous);
3299 bool NoExactMatch (EmitContext ec, MethodBase method);
3302 public IErrorHandler CustomErrorHandler;
3303 public MethodBase [] Methods;
3304 MethodBase best_candidate;
3305 // TODO: make private
3306 public TypeArguments type_arguments;
3307 bool identical_type_name;
3308 bool has_inaccessible_candidates_only;
3311 public MethodGroupExpr (MemberInfo [] mi, Type type, Location l)
3314 Methods = new MethodBase [mi.Length];
3315 mi.CopyTo (Methods, 0);
3318 public MethodGroupExpr (MemberInfo[] mi, Type type, Location l, bool inacessibleCandidatesOnly)
3319 : this (mi, type, l)
3321 has_inaccessible_candidates_only = inacessibleCandidatesOnly;
3324 public MethodGroupExpr (ArrayList list, Type type, Location l)
3328 Methods = (MethodBase[])list.ToArray (typeof (MethodBase));
3330 foreach (MemberInfo m in list){
3331 if (!(m is MethodBase)){
3332 Console.WriteLine ("Name " + m.Name);
3333 Console.WriteLine ("Found a: " + m.GetType ().FullName);
3342 protected MethodGroupExpr (Type type, Location loc)
3345 eclass = ExprClass.MethodGroup;
3349 public override Type DeclaringType {
3352 // We assume that the top-level type is in the end
3354 return Methods [Methods.Length - 1].DeclaringType;
3355 //return Methods [0].DeclaringType;
3359 public Type DelegateType {
3361 delegate_type = value;
3365 public bool IdenticalTypeName {
3367 return identical_type_name;
3371 public override string GetSignatureForError ()
3373 if (best_candidate != null)
3374 return TypeManager.CSharpSignature (best_candidate);
3376 return TypeManager.CSharpSignature (Methods [0]);
3379 public override string Name {
3381 return Methods [0].Name;
3385 public override bool IsInstance {
3387 if (best_candidate != null)
3388 return !best_candidate.IsStatic;
3390 foreach (MethodBase mb in Methods)
3398 public override bool IsStatic {
3400 if (best_candidate != null)
3401 return best_candidate.IsStatic;
3403 foreach (MethodBase mb in Methods)
3411 public static explicit operator ConstructorInfo (MethodGroupExpr mg)
3413 return (ConstructorInfo)mg.best_candidate;
3416 public static explicit operator MethodInfo (MethodGroupExpr mg)
3418 return (MethodInfo)mg.best_candidate;
3422 // 7.4.3.3 Better conversion from expression
3423 // Returns : 1 if a->p is better,
3424 // 2 if a->q is better,
3425 // 0 if neither is better
3427 static int BetterExpressionConversion (EmitContext ec, Argument a, Type p, Type q)
3429 Type argument_type = TypeManager.TypeToCoreType (a.Type);
3430 if (argument_type == TypeManager.anonymous_method_type && RootContext.Version > LanguageVersion.ISO_2) {
3432 // Uwrap delegate from Expression<T>
3434 if (TypeManager.DropGenericTypeArguments (p) == TypeManager.expression_type) {
3435 p = TypeManager.GetTypeArguments (p) [0];
3437 if (TypeManager.DropGenericTypeArguments (q) == TypeManager.expression_type) {
3438 q = TypeManager.GetTypeArguments (q) [0];
3441 p = Delegate.GetInvokeMethod (null, p).ReturnType;
3442 q = Delegate.GetInvokeMethod (null, q).ReturnType;
3443 if (p == TypeManager.void_type && q != TypeManager.void_type)
3445 if (q == TypeManager.void_type && p != TypeManager.void_type)
3448 if (argument_type == p)
3451 if (argument_type == q)
3455 return BetterTypeConversion (ec, p, q);
3459 // 7.4.3.4 Better conversion from type
3461 public static int BetterTypeConversion (EmitContext ec, Type p, Type q)
3463 if (p == null || q == null)
3464 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3466 if (p == TypeManager.int32_type) {
3467 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3469 } else if (p == TypeManager.int64_type) {
3470 if (q == TypeManager.uint64_type)
3472 } else if (p == TypeManager.sbyte_type) {
3473 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3474 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3476 } else if (p == TypeManager.short_type) {
3477 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3478 q == TypeManager.uint64_type)
3482 if (q == TypeManager.int32_type) {
3483 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3485 } if (q == TypeManager.int64_type) {
3486 if (p == TypeManager.uint64_type)
3488 } else if (q == TypeManager.sbyte_type) {
3489 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3490 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3492 } if (q == TypeManager.short_type) {
3493 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3494 p == TypeManager.uint64_type)
3498 // TODO: this is expensive
3499 Expression p_tmp = new EmptyExpression (p);
3500 Expression q_tmp = new EmptyExpression (q);
3502 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3503 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3505 if (p_to_q && !q_to_p)
3508 if (q_to_p && !p_to_q)
3515 /// Determines "Better function" between candidate
3516 /// and the current best match
3519 /// Returns a boolean indicating :
3520 /// false if candidate ain't better
3521 /// true if candidate is better than the current best match
3523 static bool BetterFunction (EmitContext ec, ArrayList args, int argument_count,
3524 MethodBase candidate, bool candidate_params,
3525 MethodBase best, bool best_params)
3527 AParametersCollection candidate_pd = TypeManager.GetParameterData (candidate);
3528 AParametersCollection best_pd = TypeManager.GetParameterData (best);
3530 bool better_at_least_one = false;
3532 for (int j = 0, c_idx = 0, b_idx = 0; j < argument_count; ++j, ++c_idx, ++b_idx)
3534 Argument a = (Argument) args [j];
3536 Type ct = candidate_pd.Types [c_idx];
3537 Type bt = best_pd.Types [b_idx];
3539 if (candidate_params && candidate_pd.FixedParameters [c_idx].ModFlags == Parameter.Modifier.PARAMS)
3541 ct = TypeManager.GetElementType (ct);
3545 if (best_params && best_pd.FixedParameters [b_idx].ModFlags == Parameter.Modifier.PARAMS)
3547 bt = TypeManager.GetElementType (bt);
3555 int result = BetterExpressionConversion (ec, a, ct, bt);
3557 // for each argument, the conversion to 'ct' should be no worse than
3558 // the conversion to 'bt'.
3562 // for at least one argument, the conversion to 'ct' should be better than
3563 // the conversion to 'bt'.
3565 better_at_least_one = true;
3568 if (better_at_least_one)
3572 // This handles the case
3574 // Add (float f1, float f2, float f3);
3575 // Add (params decimal [] foo);
3577 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3578 // first candidate would've chosen as better.
3584 // The two methods have equal parameter types. Now apply tie-breaking rules
3586 if (TypeManager.IsGenericMethod (best)) {
3587 if (!TypeManager.IsGenericMethod (candidate))
3589 } else if (TypeManager.IsGenericMethod (candidate)) {
3594 // This handles the following cases:
3596 // Trim () is better than Trim (params char[] chars)
3597 // Concat (string s1, string s2, string s3) is better than
3598 // Concat (string s1, params string [] srest)
3599 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3601 if (!candidate_params && best_params)
3603 if (candidate_params && !best_params)
3606 int candidate_param_count = candidate_pd.Count;
3607 int best_param_count = best_pd.Count;
3609 if (candidate_param_count != best_param_count)
3610 // can only happen if (candidate_params && best_params)
3611 return candidate_param_count > best_param_count;
3614 // now, both methods have the same number of parameters, and the parameters have the same types
3615 // Pick the "more specific" signature
3618 MethodBase orig_candidate = TypeManager.DropGenericMethodArguments (candidate);
3619 MethodBase orig_best = TypeManager.DropGenericMethodArguments (best);
3621 AParametersCollection orig_candidate_pd = TypeManager.GetParameterData (orig_candidate);
3622 AParametersCollection orig_best_pd = TypeManager.GetParameterData (orig_best);
3624 bool specific_at_least_once = false;
3625 for (int j = 0; j < candidate_param_count; ++j)
3627 Type ct = orig_candidate_pd.Types [j];
3628 Type bt = orig_best_pd.Types [j];
3631 Type specific = MoreSpecific (ct, bt);
3635 specific_at_least_once = true;
3638 if (specific_at_least_once)
3641 // FIXME: handle lifted operators
3647 protected override MemberExpr ResolveExtensionMemberAccess (Expression left)
3650 return base.ResolveExtensionMemberAccess (left);
3653 // When left side is an expression and at least one candidate method is
3654 // static, it can be extension method
3656 InstanceExpression = left;
3660 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3661 SimpleName original)
3663 if (!(left is TypeExpr) &&
3664 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3665 identical_type_name = true;
3667 return base.ResolveMemberAccess (ec, left, loc, original);
3670 public override Expression CreateExpressionTree (EmitContext ec)
3672 if (best_candidate == null) {
3673 Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3677 if (best_candidate.IsConstructor)
3678 return new TypeOfConstructorInfo (best_candidate, loc);
3680 IMethodData md = TypeManager.GetMethod (best_candidate);
3681 if (md != null && md.IsExcluded ())
3682 Report.Error (765, loc,
3683 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3685 return new TypeOfMethodInfo (best_candidate, loc);
3688 override public Expression DoResolve (EmitContext ec)
3690 if (InstanceExpression != null) {
3691 InstanceExpression = InstanceExpression.DoResolve (ec);
3692 if (InstanceExpression == null)
3699 public void ReportUsageError ()
3701 Report.Error (654, loc, "Method `" + DeclaringType + "." +
3702 Name + "()' is referenced without parentheses");
3705 override public void Emit (EmitContext ec)
3707 ReportUsageError ();
3710 public virtual void EmitArguments (EmitContext ec, ArrayList arguments)
3712 Invocation.EmitArguments (ec, arguments, false, null);
3715 public virtual void EmitCall (EmitContext ec, ArrayList arguments)
3717 Invocation.EmitCall (ec, IsBase, InstanceExpression, best_candidate, arguments, loc);
3720 void Error_AmbiguousCall (MethodBase ambiguous)
3722 if (CustomErrorHandler != null && CustomErrorHandler.AmbiguousCall (ambiguous))
3725 Report.SymbolRelatedToPreviousError (best_candidate);
3726 Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
3727 TypeManager.CSharpSignature (ambiguous), TypeManager.CSharpSignature (best_candidate));
3730 protected virtual void Error_InvalidArguments (EmitContext ec, Location loc, int idx, MethodBase method,
3731 Argument a, AParametersCollection expected_par, Type paramType)
3733 ExtensionMethodGroupExpr emg = this as ExtensionMethodGroupExpr;
3735 if (a is CollectionElementInitializer.ElementInitializerArgument) {
3736 Report.SymbolRelatedToPreviousError (method);
3737 if ((expected_par.FixedParameters [idx].ModFlags & Parameter.Modifier.ISBYREF) != 0) {
3738 Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
3739 TypeManager.CSharpSignature (method));
3742 Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
3743 TypeManager.CSharpSignature (method));
3744 } else if (TypeManager.IsDelegateType (method.DeclaringType)) {
3745 Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
3746 TypeManager.CSharpName (method.DeclaringType));
3748 Report.SymbolRelatedToPreviousError (method);
3750 Report.Error (1928, loc,
3751 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3752 emg.ExtensionExpression.GetSignatureForError (),
3753 emg.Name, TypeManager.CSharpSignature (method));
3755 Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
3756 TypeManager.CSharpSignature (method));
3760 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters [idx].ModFlags;
3762 string index = (idx + 1).ToString ();
3763 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
3764 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
3765 if ((mod & Parameter.Modifier.ISBYREF) == 0)
3766 Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
3767 index, Parameter.GetModifierSignature (a.Modifier));
3769 Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
3770 index, Parameter.GetModifierSignature (mod));
3772 string p1 = a.GetSignatureForError ();
3773 string p2 = TypeManager.CSharpName (paramType);
3776 Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
3777 Report.SymbolRelatedToPreviousError (a.Expr.Type);
3778 Report.SymbolRelatedToPreviousError (paramType);
3781 if (idx == 0 && emg != null) {
3782 Report.Error (1929, loc,
3783 "Extension method instance type `{0}' cannot be converted to `{1}'", p1, p2);
3785 Report.Error (1503, loc,
3786 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
3791 public override void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl)
3793 Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3794 Name, TypeManager.CSharpName (target));
3797 void Error_ArgumentCountWrong (int arg_count)
3799 Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
3800 Name, arg_count.ToString ());
3803 protected virtual int GetApplicableParametersCount (MethodBase method, AParametersCollection parameters)
3805 return parameters.Count;
3808 public static bool IsAncestralType (Type first_type, Type second_type)
3810 return first_type != second_type &&
3811 (TypeManager.IsSubclassOf (second_type, first_type) ||
3812 TypeManager.ImplementsInterface (second_type, first_type));
3816 /// Determines if the candidate method is applicable (section 14.4.2.1)
3817 /// to the given set of arguments
3818 /// A return value rates candidate method compatibility,
3819 /// 0 = the best, int.MaxValue = the worst
3821 public int IsApplicable (EmitContext ec,
3822 ArrayList arguments, int arg_count, ref MethodBase method, ref bool params_expanded_form)
3824 MethodBase candidate = method;
3826 AParametersCollection pd = TypeManager.GetParameterData (candidate);
3827 int param_count = GetApplicableParametersCount (candidate, pd);
3829 if (arg_count != param_count) {
3831 return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
3832 if (arg_count < param_count - 1)
3833 return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
3835 // Initialize expanded form of a method with 1 params parameter
3836 params_expanded_form = param_count == 1 && pd.HasParams;
3841 // 1. Handle generic method using type arguments when specified or type inference
3843 if (TypeManager.IsGenericMethod (candidate)) {
3844 if (type_arguments != null) {
3845 Type [] g_args = candidate.GetGenericArguments ();
3846 if (g_args.Length != type_arguments.Count)
3847 return int.MaxValue - 20000 + Math.Abs (type_arguments.Count - g_args.Length);
3849 // TODO: Don't create new method, create Parameters only
3850 method = ((MethodInfo) candidate).MakeGenericMethod (type_arguments.Arguments);
3852 pd = TypeManager.GetParameterData (candidate);
3854 int score = TypeManager.InferTypeArguments (ec, arguments, ref candidate);
3856 return score - 20000;
3858 if (TypeManager.IsGenericMethodDefinition (candidate))
3859 throw new InternalErrorException ("A generic method `{0}' definition took part in overload resolution",
3860 TypeManager.CSharpSignature (candidate));
3862 pd = TypeManager.GetParameterData (candidate);
3865 if (type_arguments != null)
3866 return int.MaxValue - 15000;
3871 // 2. Each argument has to be implicitly convertible to method parameter
3874 Parameter.Modifier p_mod = 0;
3876 for (int i = 0; i < arg_count; i++) {
3877 Argument a = (Argument) arguments [i];
3878 Parameter.Modifier a_mod = a.Modifier &
3879 ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3881 if (p_mod != Parameter.Modifier.PARAMS) {
3882 p_mod = pd.FixedParameters [i].ModFlags & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3884 if (p_mod == Parameter.Modifier.ARGLIST) {
3885 if (a.Type == TypeManager.runtime_argument_handle_type)
3893 params_expanded_form = true;
3897 if (!params_expanded_form)
3898 score = IsArgumentCompatible (ec, a_mod, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
3900 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && delegate_type == null) {
3901 // It can be applicable in expanded form
3902 score = IsArgumentCompatible (ec, a_mod, a, 0, pt.GetElementType ());
3904 params_expanded_form = true;
3908 if (params_expanded_form)
3910 return (arg_count - i) * 2 + score;
3914 if (arg_count != param_count)
3915 params_expanded_form = true;
3920 int IsArgumentCompatible (EmitContext ec, Parameter.Modifier arg_mod, Argument argument, Parameter.Modifier param_mod, Type parameter)
3923 // Types have to be identical when ref or out modifer is used
3925 if (arg_mod != 0 || param_mod != 0) {
3926 if (TypeManager.HasElementType (parameter))
3927 parameter = parameter.GetElementType ();
3929 Type a_type = argument.Type;
3930 if (TypeManager.HasElementType (a_type))
3931 a_type = a_type.GetElementType ();
3933 if (a_type != parameter)
3936 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter))
3940 if (arg_mod != param_mod)
3946 public static bool IsOverride (MethodBase cand_method, MethodBase base_method)
3948 if (!IsAncestralType (base_method.DeclaringType, cand_method.DeclaringType))
3951 AParametersCollection cand_pd = TypeManager.GetParameterData (cand_method);
3952 AParametersCollection base_pd = TypeManager.GetParameterData (base_method);
3954 if (cand_pd.Count != base_pd.Count)
3957 for (int j = 0; j < cand_pd.Count; ++j)
3959 Parameter.Modifier cm = cand_pd.FixedParameters [j].ModFlags;
3960 Parameter.Modifier bm = base_pd.FixedParameters [j].ModFlags;
3961 Type ct = cand_pd.Types [j];
3962 Type bt = base_pd.Types [j];
3964 if (cm != bm || ct != bt)
3971 public static MethodGroupExpr MakeUnionSet (MethodGroupExpr mg1, MethodGroupExpr mg2, Location loc)
3982 ArrayList all = new ArrayList (mg1.Methods);
3983 foreach (MethodBase m in mg2.Methods){
3984 if (!TypeManager.ArrayContainsMethod (mg1.Methods, m, false))
3988 return new MethodGroupExpr (all, null, loc);
3991 static Type MoreSpecific (Type p, Type q)
3993 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
3995 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
3998 if (TypeManager.HasElementType (p))
4000 Type pe = TypeManager.GetElementType (p);
4001 Type qe = TypeManager.GetElementType (q);
4002 Type specific = MoreSpecific (pe, qe);
4008 else if (TypeManager.IsGenericType (p))
4010 Type[] pargs = TypeManager.GetTypeArguments (p);
4011 Type[] qargs = TypeManager.GetTypeArguments (q);
4013 bool p_specific_at_least_once = false;
4014 bool q_specific_at_least_once = false;
4016 for (int i = 0; i < pargs.Length; i++)
4018 Type specific = MoreSpecific (pargs [i], qargs [i]);
4019 if (specific == pargs [i])
4020 p_specific_at_least_once = true;
4021 if (specific == qargs [i])
4022 q_specific_at_least_once = true;
4025 if (p_specific_at_least_once && !q_specific_at_least_once)
4027 if (!p_specific_at_least_once && q_specific_at_least_once)
4034 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4036 base.MutateHoistedGenericType (storey);
4038 MethodInfo mi = best_candidate as MethodInfo;
4040 best_candidate = storey.MutateGenericMethod (mi);
4044 best_candidate = storey.MutateConstructor ((ConstructorInfo) this);
4048 /// Find the Applicable Function Members (7.4.2.1)
4050 /// me: Method Group expression with the members to select.
4051 /// it might contain constructors or methods (or anything
4052 /// that maps to a method).
4054 /// Arguments: ArrayList containing resolved Argument objects.
4056 /// loc: The location if we want an error to be reported, or a Null
4057 /// location for "probing" purposes.
4059 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4060 /// that is the best match of me on Arguments.
4063 public virtual MethodGroupExpr OverloadResolve (EmitContext ec, ref ArrayList Arguments,
4064 bool may_fail, Location loc)
4066 bool method_params = false;
4067 Type applicable_type = null;
4069 ArrayList candidates = new ArrayList (2);
4070 ArrayList candidate_overrides = null;
4073 // Used to keep a map between the candidate
4074 // and whether it is being considered in its
4075 // normal or expanded form
4077 // false is normal form, true is expanded form
4079 Hashtable candidate_to_form = null;
4081 if (Arguments != null)
4082 arg_count = Arguments.Count;
4084 if (RootContext.Version == LanguageVersion.ISO_1 && Name == "Invoke" && TypeManager.IsDelegateType (DeclaringType)) {
4086 Report.Error (1533, loc, "Invoke cannot be called directly on a delegate");
4090 int nmethods = Methods.Length;
4094 // Methods marked 'override' don't take part in 'applicable_type'
4095 // computation, nor in the actual overload resolution.
4096 // However, they still need to be emitted instead of a base virtual method.
4097 // So, we salt them away into the 'candidate_overrides' array.
4099 // In case of reflected methods, we replace each overriding method with
4100 // its corresponding base virtual method. This is to improve compatibility
4101 // with non-C# libraries which change the visibility of overrides (#75636)
4104 for (int i = 0; i < Methods.Length; ++i) {
4105 MethodBase m = Methods [i];
4106 if (TypeManager.IsOverride (m)) {
4107 if (candidate_overrides == null)
4108 candidate_overrides = new ArrayList ();
4109 candidate_overrides.Add (m);
4110 m = TypeManager.TryGetBaseDefinition (m);
4119 // Enable message recording, it's used mainly by lambda expressions
4121 Report.IMessageRecorder msg_recorder = new Report.MessageRecorder ();
4122 Report.IMessageRecorder prev_recorder = Report.SetMessageRecorder (msg_recorder);
4125 // First we construct the set of applicable methods
4127 bool is_sorted = true;
4128 int best_candidate_rate = int.MaxValue;
4129 for (int i = 0; i < nmethods; i++) {
4130 Type decl_type = Methods [i].DeclaringType;
4133 // If we have already found an applicable method
4134 // we eliminate all base types (Section 14.5.5.1)
4136 if (applicable_type != null && IsAncestralType (decl_type, applicable_type))
4140 // Check if candidate is applicable (section 14.4.2.1)
4142 bool params_expanded_form = false;
4143 int candidate_rate = IsApplicable (ec, Arguments, arg_count, ref Methods [i], ref params_expanded_form);
4145 if (candidate_rate < best_candidate_rate) {
4146 best_candidate_rate = candidate_rate;
4147 best_candidate = Methods [i];
4150 if (params_expanded_form) {
4151 if (candidate_to_form == null)
4152 candidate_to_form = new PtrHashtable ();
4153 MethodBase candidate = Methods [i];
4154 candidate_to_form [candidate] = candidate;
4157 if (candidate_rate != 0 || has_inaccessible_candidates_only) {
4158 if (msg_recorder != null)
4159 msg_recorder.EndSession ();
4163 msg_recorder = null;
4164 candidates.Add (Methods [i]);
4166 if (applicable_type == null)
4167 applicable_type = decl_type;
4168 else if (applicable_type != decl_type) {
4170 if (IsAncestralType (applicable_type, decl_type))
4171 applicable_type = decl_type;
4175 Report.SetMessageRecorder (prev_recorder);
4176 if (msg_recorder != null && !msg_recorder.IsEmpty) {
4178 msg_recorder.PrintMessages ();
4183 int candidate_top = candidates.Count;
4185 if (applicable_type == null) {
4187 // When we found a top level method which does not match and it's
4188 // not an extension method. We start extension methods lookup from here
4190 if (InstanceExpression != null) {
4191 ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (type, Name, loc);
4192 if (ex_method_lookup != null) {
4193 ex_method_lookup.ExtensionExpression = InstanceExpression;
4194 ex_method_lookup.SetTypeArguments (type_arguments);
4195 return ex_method_lookup.OverloadResolve (ec, ref Arguments, may_fail, loc);
4203 // Okay so we have failed to find exact match so we
4204 // return error info about the closest match
4206 if (best_candidate != null) {
4207 if (CustomErrorHandler != null && CustomErrorHandler.NoExactMatch (ec, best_candidate))
4210 AParametersCollection pd = TypeManager.GetParameterData (best_candidate);
4211 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4212 if (arg_count == pd.Count || pd.HasParams) {
4213 if (TypeManager.IsGenericMethodDefinition (best_candidate)) {
4214 if (type_arguments == null) {
4215 Report.Error (411, loc,
4216 "The type arguments for method `{0}' cannot be inferred from " +
4217 "the usage. Try specifying the type arguments explicitly",
4218 TypeManager.CSharpSignature (best_candidate));
4222 Type[] g_args = TypeManager.GetGenericArguments (best_candidate);
4223 if (type_arguments.Count != g_args.Length) {
4224 Report.SymbolRelatedToPreviousError (best_candidate);
4225 Report.Error (305, loc, "Using the generic method `{0}' requires `{1}' type argument(s)",
4226 TypeManager.CSharpSignature (best_candidate),
4227 g_args.Length.ToString ());
4231 if (type_arguments != null && !TypeManager.IsGenericMethod (best_candidate)) {
4232 Namespace.Error_TypeArgumentsCannotBeUsed (best_candidate, loc);
4237 if (has_inaccessible_candidates_only) {
4238 if (InstanceExpression != null && type != ec.ContainerType && TypeManager.IsNestedFamilyAccessible (ec.ContainerType, best_candidate.DeclaringType)) {
4239 // Although a derived class can access protected members of
4240 // its base class it cannot do so through an instance of the
4241 // base class (CS1540). If the qualifier_type is a base of the
4242 // ec.ContainerType and the lookup succeeds with the latter one,
4243 // then we are in this situation.
4244 Error_CannotAccessProtected (loc, best_candidate, type, ec.ContainerType);
4246 Report.SymbolRelatedToPreviousError (best_candidate);
4247 ErrorIsInaccesible (loc, GetSignatureForError ());
4251 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate, cand_params, may_fail, loc))
4254 if (has_inaccessible_candidates_only)
4257 throw new InternalErrorException ("VerifyArgumentsCompat didn't find any problem with rejected candidate " + best_candidate);
4262 // We failed to find any method with correct argument count
4264 if (Name == ConstructorInfo.ConstructorName) {
4265 Report.SymbolRelatedToPreviousError (type);
4266 Report.Error (1729, loc,
4267 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4268 TypeManager.CSharpName (type), arg_count);
4270 Error_ArgumentCountWrong (arg_count);
4278 // At this point, applicable_type is _one_ of the most derived types
4279 // in the set of types containing the methods in this MethodGroup.
4280 // Filter the candidates so that they only contain methods from the
4281 // most derived types.
4284 int finalized = 0; // Number of finalized candidates
4287 // Invariant: applicable_type is a most derived type
4289 // We'll try to complete Section 14.5.5.1 for 'applicable_type' by
4290 // eliminating all it's base types. At the same time, we'll also move
4291 // every unrelated type to the end of the array, and pick the next
4292 // 'applicable_type'.
4294 Type next_applicable_type = null;
4295 int j = finalized; // where to put the next finalized candidate
4296 int k = finalized; // where to put the next undiscarded candidate
4297 for (int i = finalized; i < candidate_top; ++i) {
4298 MethodBase candidate = (MethodBase) candidates [i];
4299 Type decl_type = candidate.DeclaringType;
4301 if (decl_type == applicable_type) {
4302 candidates [k++] = candidates [j];
4303 candidates [j++] = candidates [i];
4307 if (IsAncestralType (decl_type, applicable_type))
4310 if (next_applicable_type != null &&
4311 IsAncestralType (decl_type, next_applicable_type))
4314 candidates [k++] = candidates [i];
4316 if (next_applicable_type == null ||
4317 IsAncestralType (next_applicable_type, decl_type))
4318 next_applicable_type = decl_type;
4321 applicable_type = next_applicable_type;
4324 } while (applicable_type != null);
4328 // Now we actually find the best method
4331 best_candidate = (MethodBase) candidates [0];
4332 method_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4334 for (int ix = 1; ix < candidate_top; ix++) {
4335 MethodBase candidate = (MethodBase) candidates [ix];
4337 if (candidate == best_candidate)
4340 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4342 if (BetterFunction (ec, Arguments, arg_count,
4343 candidate, cand_params,
4344 best_candidate, method_params)) {
4345 best_candidate = candidate;
4346 method_params = cand_params;
4350 // Now check that there are no ambiguities i.e the selected method
4351 // should be better than all the others
4353 MethodBase ambiguous = null;
4354 for (int ix = 1; ix < candidate_top; ix++) {
4355 MethodBase candidate = (MethodBase) candidates [ix];
4357 if (candidate == best_candidate)
4360 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4361 if (!BetterFunction (ec, Arguments, arg_count,
4362 best_candidate, method_params,
4363 candidate, cand_params))
4366 Report.SymbolRelatedToPreviousError (candidate);
4367 ambiguous = candidate;
4371 if (ambiguous != null) {
4372 Error_AmbiguousCall (ambiguous);
4377 // If the method is a virtual function, pick an override closer to the LHS type.
4379 if (!IsBase && best_candidate.IsVirtual) {
4380 if (TypeManager.IsOverride (best_candidate))
4381 throw new InternalErrorException (
4382 "Should not happen. An 'override' method took part in overload resolution: " + best_candidate);
4384 if (candidate_overrides != null) {
4385 Type[] gen_args = null;
4386 bool gen_override = false;
4387 if (TypeManager.IsGenericMethod (best_candidate))
4388 gen_args = TypeManager.GetGenericArguments (best_candidate);
4390 foreach (MethodBase candidate in candidate_overrides) {
4391 if (TypeManager.IsGenericMethod (candidate)) {
4392 if (gen_args == null)
4395 if (gen_args.Length != TypeManager.GetGenericArguments (candidate).Length)
4398 if (gen_args != null)
4402 if (IsOverride (candidate, best_candidate)) {
4403 gen_override = true;
4404 best_candidate = candidate;
4408 if (gen_override && gen_args != null) {
4410 best_candidate = ((MethodInfo) best_candidate).MakeGenericMethod (gen_args);
4417 // And now check if the arguments are all
4418 // compatible, perform conversions if
4419 // necessary etc. and return if everything is
4422 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate,
4423 method_params, may_fail, loc))
4426 if (best_candidate == null)
4429 MethodBase the_method = TypeManager.DropGenericMethodArguments (best_candidate);
4431 if (the_method.IsGenericMethodDefinition &&
4432 !ConstraintChecker.CheckConstraints (ec, the_method, best_candidate, loc))
4437 // Check ObsoleteAttribute on the best method
4439 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (the_method);
4440 if (oa != null && !ec.IsInObsoleteScope)
4441 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc);
4443 IMethodData data = TypeManager.GetMethod (the_method);
4445 data.SetMemberIsUsed ();
4450 public override void SetTypeArguments (TypeArguments ta)
4452 type_arguments = ta;
4455 public bool VerifyArgumentsCompat (EmitContext ec, ref ArrayList arguments,
4456 int arg_count, MethodBase method,
4457 bool chose_params_expanded,
4458 bool may_fail, Location loc)
4460 AParametersCollection pd = TypeManager.GetParameterData (method);
4462 int errors = Report.Errors;
4463 Parameter.Modifier p_mod = 0;
4465 int a_idx = 0, a_pos = 0;
4467 ArrayList params_initializers = null;
4468 bool has_unsafe_arg = false;
4470 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4471 a = (Argument) arguments [a_idx];
4472 if (p_mod != Parameter.Modifier.PARAMS) {
4473 p_mod = pd.FixedParameters [a_idx].ModFlags;
4474 pt = pd.Types [a_idx];
4475 has_unsafe_arg |= pt.IsPointer;
4477 if (p_mod == Parameter.Modifier.ARGLIST) {
4478 if (a.Type != TypeManager.runtime_argument_handle_type)
4483 if (p_mod == Parameter.Modifier.PARAMS) {
4484 if (chose_params_expanded) {
4485 params_initializers = new ArrayList (arg_count - a_idx);
4486 pt = TypeManager.GetElementType (pt);
4492 // Types have to be identical when ref or out modifer is used
4494 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4495 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4498 if (!TypeManager.IsEqual (a.Expr.Type, pt))
4504 if (delegate_type != null && !Delegate.IsTypeCovariant (a.Expr, pt))
4507 Expression conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4512 // Convert params arguments to an array initializer
4514 if (params_initializers != null) {
4515 // we choose to use 'a.Expr' rather than 'conv' so that
4516 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
4517 params_initializers.Add (a.Expr);
4518 arguments.RemoveAt (a_idx--);
4523 // Update the argument with the implicit conversion
4527 if (a_idx != arg_count) {
4528 if (!may_fail && Report.Errors == errors) {
4529 if (CustomErrorHandler != null)
4530 CustomErrorHandler.NoExactMatch (ec, best_candidate);
4532 Error_InvalidArguments (ec, loc, a_pos, method, a, pd, pt);
4538 // Fill not provided arguments required by params modifier
4540 int param_count = GetApplicableParametersCount (method, pd);
4541 if (params_initializers == null && pd.HasParams && arg_count + 1 == param_count) {
4542 if (arguments == null)
4543 arguments = new ArrayList (1);
4545 pt = pd.Types [param_count - 1];
4546 pt = TypeManager.GetElementType (pt);
4547 has_unsafe_arg |= pt.IsPointer;
4548 params_initializers = new ArrayList (0);
4552 // Append an array argument with all params arguments
4554 if (params_initializers != null) {
4555 arguments.Add (new Argument (
4556 new ArrayCreation (new TypeExpression (pt, loc), "[]",
4557 params_initializers, loc).Resolve (ec)));
4561 if (arg_count < param_count) {
4563 Error_ArgumentCountWrong (arg_count);
4567 if (has_unsafe_arg && !ec.InUnsafe) {
4577 public class ConstantExpr : MemberExpr
4581 public ConstantExpr (FieldInfo constant, Location loc)
4583 this.constant = constant;
4587 public override string Name {
4588 get { throw new NotImplementedException (); }
4591 public override bool IsInstance {
4592 get { return !IsStatic; }
4595 public override bool IsStatic {
4596 get { return constant.IsStatic; }
4599 public override Type DeclaringType {
4600 get { return constant.DeclaringType; }
4603 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc, SimpleName original)
4605 constant = TypeManager.GetGenericFieldDefinition (constant);
4607 IConstant ic = TypeManager.GetConstant (constant);
4609 if (constant.IsLiteral) {
4610 ic = new ExternalConstant (constant);
4612 ic = ExternalConstant.CreateDecimal (constant);
4613 // HACK: decimal field was not resolved as constant
4615 return new FieldExpr (constant, loc).ResolveMemberAccess (ec, left, loc, original);
4617 TypeManager.RegisterConstant (constant, ic);
4620 return base.ResolveMemberAccess (ec, left, loc, original);
4623 public override Expression CreateExpressionTree (EmitContext ec)
4625 throw new NotSupportedException ("ET");
4628 public override Expression DoResolve (EmitContext ec)
4630 IConstant ic = TypeManager.GetConstant (constant);
4631 if (ic.ResolveValue ()) {
4632 if (!ec.IsInObsoleteScope)
4633 ic.CheckObsoleteness (loc);
4636 return ic.CreateConstantReference (loc);
4639 public override void Emit (EmitContext ec)
4641 throw new NotSupportedException ();
4644 public override string GetSignatureForError ()
4646 return TypeManager.GetFullNameSignature (constant);
4651 /// Fully resolved expression that evaluates to a Field
4653 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariableReference {
4654 public FieldInfo FieldInfo;
4655 readonly Type constructed_generic_type;
4656 VariableInfo variable_info;
4658 LocalTemporary temp;
4661 protected FieldExpr (Location l)
4666 public FieldExpr (FieldInfo fi, Location l)
4669 type = TypeManager.TypeToCoreType (fi.FieldType);
4673 public FieldExpr (FieldInfo fi, Type genericType, Location l)
4676 if (TypeManager.IsGenericTypeDefinition (genericType))
4678 this.constructed_generic_type = genericType;
4681 public override string Name {
4683 return FieldInfo.Name;
4687 public override bool IsInstance {
4689 return !FieldInfo.IsStatic;
4693 public override bool IsStatic {
4695 return FieldInfo.IsStatic;
4699 public override Type DeclaringType {
4701 return FieldInfo.DeclaringType;
4705 public override string GetSignatureForError ()
4707 return TypeManager.GetFullNameSignature (FieldInfo);
4710 public VariableInfo VariableInfo {
4712 return variable_info;
4716 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
4717 SimpleName original)
4719 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
4720 Type t = fi.FieldType;
4722 if (t.IsPointer && !ec.InUnsafe) {
4726 return base.ResolveMemberAccess (ec, left, loc, original);
4729 public void SetHasAddressTaken ()
4731 IVariableReference vr = InstanceExpression as IVariableReference;
4733 vr.SetHasAddressTaken ();
4736 public override Expression CreateExpressionTree (EmitContext ec)
4738 Expression instance;
4739 if (InstanceExpression == null) {
4740 instance = new NullLiteral (loc);
4742 instance = InstanceExpression.CreateExpressionTree (ec);
4745 ArrayList args = new ArrayList (2);
4746 args.Add (new Argument (instance));
4747 args.Add (new Argument (CreateTypeOfExpression ()));
4748 return CreateExpressionFactoryCall ("Field", args);
4751 public Expression CreateTypeOfExpression ()
4753 return new TypeOfField (GetConstructedFieldInfo (), loc);
4756 override public Expression DoResolve (EmitContext ec)
4758 return DoResolve (ec, false, false);
4761 Expression DoResolve (EmitContext ec, bool lvalue_instance, bool out_access)
4763 if (!FieldInfo.IsStatic){
4764 if (InstanceExpression == null){
4766 // This can happen when referencing an instance field using
4767 // a fully qualified type expression: TypeName.InstanceField = xxx
4769 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4773 // Resolve the field's instance expression while flow analysis is turned
4774 // off: when accessing a field "a.b", we must check whether the field
4775 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4777 if (lvalue_instance) {
4778 using (ec.With (EmitContext.Flags.DoFlowAnalysis, false)) {
4779 Expression right_side =
4780 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4781 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side, loc);
4784 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
4785 InstanceExpression = InstanceExpression.Resolve (ec, rf);
4788 if (InstanceExpression == null)
4791 using (ec.Set (EmitContext.Flags.OmitStructFlowAnalysis)) {
4792 InstanceExpression.CheckMarshalByRefAccess (ec);
4796 // TODO: the code above uses some non-standard multi-resolve rules
4797 if (eclass != ExprClass.Invalid)
4800 if (!ec.IsInObsoleteScope) {
4801 FieldBase f = TypeManager.GetField (FieldInfo);
4803 f.CheckObsoleteness (loc);
4805 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
4807 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
4811 IFixedBuffer fb = AttributeTester.GetFixedBuffer (FieldInfo);
4812 IVariableReference var = InstanceExpression as IVariableReference;
4815 IFixedExpression fe = InstanceExpression as IFixedExpression;
4816 if (!ec.InFixedInitializer && (fe == null || !fe.IsFixed)) {
4817 Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4820 if (InstanceExpression.eclass != ExprClass.Variable) {
4821 Report.SymbolRelatedToPreviousError (FieldInfo);
4822 Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4823 TypeManager.GetFullNameSignature (FieldInfo));
4824 } else if (var != null && var.IsHoisted) {
4825 AnonymousMethodExpression.Error_AddressOfCapturedVar (var, loc);
4828 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4831 eclass = ExprClass.Variable;
4833 // If the instance expression is a local variable or parameter.
4834 if (var == null || var.VariableInfo == null)
4837 VariableInfo vi = var.VariableInfo;
4838 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
4841 variable_info = vi.GetSubStruct (FieldInfo.Name);
4842 eclass = ExprClass.Variable;
4846 static readonly int [] codes = {
4847 191, // instance, write access
4848 192, // instance, out access
4849 198, // static, write access
4850 199, // static, out access
4851 1648, // member of value instance, write access
4852 1649, // member of value instance, out access
4853 1650, // member of value static, write access
4854 1651 // member of value static, out access
4857 static readonly string [] msgs = {
4858 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4859 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4860 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4861 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4862 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4863 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4864 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4865 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4868 // The return value is always null. Returning a value simplifies calling code.
4869 Expression Report_AssignToReadonly (Expression right_side)
4872 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4876 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4878 Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4883 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4885 IVariableReference var = InstanceExpression as IVariableReference;
4886 if (var != null && var.VariableInfo != null)
4887 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
4889 bool lvalue_instance = !FieldInfo.IsStatic && FieldInfo.DeclaringType.IsValueType;
4890 bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
4892 Expression e = DoResolve (ec, lvalue_instance, out_access);
4897 FieldBase fb = TypeManager.GetField (FieldInfo);
4901 if (FieldInfo.IsInitOnly) {
4902 // InitOnly fields can only be assigned in constructors or initializers
4903 if (!ec.IsInFieldInitializer && !ec.IsConstructor)
4904 return Report_AssignToReadonly (right_side);
4906 if (ec.IsConstructor) {
4907 Type ctype = ec.TypeContainer.CurrentType;
4909 ctype = ec.ContainerType;
4911 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4912 if (!TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
4913 return Report_AssignToReadonly (right_side);
4914 // static InitOnly fields cannot be assigned-to in an instance constructor
4915 if (IsStatic && !ec.IsStatic)
4916 return Report_AssignToReadonly (right_side);
4917 // instance constructors can't modify InitOnly fields of other instances of the same type
4918 if (!IsStatic && !(InstanceExpression is This))
4919 return Report_AssignToReadonly (right_side);
4923 if (right_side == EmptyExpression.OutAccess &&
4924 !IsStatic && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type)) {
4925 Report.SymbolRelatedToPreviousError (DeclaringType);
4926 Report.Warning (197, 1, loc,
4927 "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",
4928 GetSignatureForError ());
4931 eclass = ExprClass.Variable;
4935 bool is_marshal_by_ref ()
4937 return !IsStatic && Type.IsValueType && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type);
4940 public override void CheckMarshalByRefAccess (EmitContext ec)
4942 if (is_marshal_by_ref () && !(InstanceExpression is This)) {
4943 Report.SymbolRelatedToPreviousError (DeclaringType);
4944 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",
4945 GetSignatureForError ());
4949 public override int GetHashCode ()
4951 return FieldInfo.GetHashCode ();
4954 public bool IsFixed {
4957 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
4959 IVariableReference variable = InstanceExpression as IVariableReference;
4960 if (variable != null)
4961 return InstanceExpression.Type.IsValueType && variable.IsFixed;
4963 IFixedExpression fe = InstanceExpression as IFixedExpression;
4964 return fe != null && fe.IsFixed;
4968 public bool IsHoisted {
4970 IVariableReference hv = InstanceExpression as IVariableReference;
4971 return hv != null && hv.IsHoisted;
4975 public override bool Equals (object obj)
4977 FieldExpr fe = obj as FieldExpr;
4981 if (FieldInfo != fe.FieldInfo)
4984 if (InstanceExpression == null || fe.InstanceExpression == null)
4987 return InstanceExpression.Equals (fe.InstanceExpression);
4990 public void Emit (EmitContext ec, bool leave_copy)
4992 ILGenerator ig = ec.ig;
4993 bool is_volatile = false;
4995 FieldBase f = TypeManager.GetField (FieldInfo);
4997 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
5000 f.SetMemberIsUsed ();
5003 if (FieldInfo.IsStatic){
5005 ig.Emit (OpCodes.Volatile);
5007 ig.Emit (OpCodes.Ldsfld, GetConstructedFieldInfo ());
5010 EmitInstance (ec, false);
5012 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
5014 ig.Emit (OpCodes.Ldflda, GetConstructedFieldInfo ());
5015 ig.Emit (OpCodes.Ldflda, ff.Element);
5018 ig.Emit (OpCodes.Volatile);
5020 ig.Emit (OpCodes.Ldfld, GetConstructedFieldInfo ());
5025 ec.ig.Emit (OpCodes.Dup);
5026 if (!FieldInfo.IsStatic) {
5027 temp = new LocalTemporary (this.Type);
5033 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5035 FieldAttributes fa = FieldInfo.Attributes;
5036 bool is_static = (fa & FieldAttributes.Static) != 0;
5037 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
5038 ILGenerator ig = ec.ig;
5040 if (is_readonly && !ec.IsConstructor){
5041 Report_AssignToReadonly (source);
5045 prepared = prepare_for_load;
5046 EmitInstance (ec, prepared);
5050 ec.ig.Emit (OpCodes.Dup);
5051 if (!FieldInfo.IsStatic) {
5052 temp = new LocalTemporary (this.Type);
5057 FieldBase f = TypeManager.GetField (FieldInfo);
5059 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
5060 ig.Emit (OpCodes.Volatile);
5066 ig.Emit (OpCodes.Stsfld, GetConstructedFieldInfo ());
5068 ig.Emit (OpCodes.Stfld, GetConstructedFieldInfo ());
5077 public override void Emit (EmitContext ec)
5082 public override void EmitSideEffect (EmitContext ec)
5084 FieldBase f = TypeManager.GetField (FieldInfo);
5085 bool is_volatile = f != null && (f.ModFlags & Modifiers.VOLATILE) != 0;
5087 if (is_volatile || is_marshal_by_ref ())
5088 base.EmitSideEffect (ec);
5091 public override void Error_VariableIsUsedBeforeItIsDeclared (string name)
5093 Report.Error (844, loc,
5094 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the field `{1}'",
5095 name, GetSignatureForError ());
5098 public void AddressOf (EmitContext ec, AddressOp mode)
5100 ILGenerator ig = ec.ig;
5102 FieldBase f = TypeManager.GetField (FieldInfo);
5104 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
5105 Report.Warning (420, 1, loc, "`{0}': A volatile field references will not be treated as volatile",
5106 f.GetSignatureForError ());
5109 if ((mode & AddressOp.Store) != 0)
5111 if ((mode & AddressOp.Load) != 0)
5112 f.SetMemberIsUsed ();
5116 // Handle initonly fields specially: make a copy and then
5117 // get the address of the copy.
5120 if (FieldInfo.IsInitOnly){
5122 if (ec.IsConstructor){
5123 if (FieldInfo.IsStatic){
5135 local = ig.DeclareLocal (type);
5136 ig.Emit (OpCodes.Stloc, local);
5137 ig.Emit (OpCodes.Ldloca, local);
5142 if (FieldInfo.IsStatic){
5143 ig.Emit (OpCodes.Ldsflda, GetConstructedFieldInfo ());
5146 EmitInstance (ec, false);
5147 ig.Emit (OpCodes.Ldflda, GetConstructedFieldInfo ());
5151 FieldInfo GetConstructedFieldInfo ()
5153 if (constructed_generic_type == null)
5156 return TypeBuilder.GetField (constructed_generic_type, FieldInfo);
5158 throw new NotSupportedException ();
5162 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5164 FieldInfo = storey.MutateField (FieldInfo);
5165 base.MutateHoistedGenericType (storey);
5171 /// Expression that evaluates to a Property. The Assign class
5172 /// might set the `Value' expression if we are in an assignment.
5174 /// This is not an LValue because we need to re-write the expression, we
5175 /// can not take data from the stack and store it.
5177 public class PropertyExpr : MemberExpr, IAssignMethod {
5178 public readonly PropertyInfo PropertyInfo;
5179 MethodInfo getter, setter;
5184 LocalTemporary temp;
5187 public PropertyExpr (Type container_type, PropertyInfo pi, Location l)
5190 eclass = ExprClass.PropertyAccess;
5194 type = TypeManager.TypeToCoreType (pi.PropertyType);
5196 ResolveAccessors (container_type);
5199 public override string Name {
5201 return PropertyInfo.Name;
5205 public override bool IsInstance {
5211 public override bool IsStatic {
5217 public override Expression CreateExpressionTree (EmitContext ec)
5220 if (IsSingleDimensionalArrayLength ()) {
5221 args = new ArrayList (1);
5222 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5223 return CreateExpressionFactoryCall ("ArrayLength", args);
5227 Error_BaseAccessInExpressionTree (loc);
5231 args = new ArrayList (2);
5232 if (InstanceExpression == null)
5233 args.Add (new Argument (new NullLiteral (loc)));
5235 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5236 args.Add (new Argument (new TypeOfMethodInfo (getter, loc)));
5237 return CreateExpressionFactoryCall ("Property", args);
5240 public Expression CreateSetterTypeOfExpression ()
5242 return new TypeOfMethodInfo (setter, loc);
5245 public override Type DeclaringType {
5247 return PropertyInfo.DeclaringType;
5251 public override string GetSignatureForError ()
5253 return TypeManager.GetFullNameSignature (PropertyInfo);
5256 void FindAccessors (Type invocation_type)
5258 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
5259 BindingFlags.Static | BindingFlags.Instance |
5260 BindingFlags.DeclaredOnly;
5262 Type current = PropertyInfo.DeclaringType;
5263 for (; current != null; current = current.BaseType) {
5264 MemberInfo[] group = TypeManager.MemberLookup (
5265 invocation_type, invocation_type, current,
5266 MemberTypes.Property, flags, PropertyInfo.Name, null);
5271 if (group.Length != 1)
5272 // Oooops, can this ever happen ?
5275 PropertyInfo pi = (PropertyInfo) group [0];
5278 getter = pi.GetGetMethod (true);
5281 setter = pi.GetSetMethod (true);
5283 MethodInfo accessor = getter != null ? getter : setter;
5285 if (!accessor.IsVirtual)
5291 // We also perform the permission checking here, as the PropertyInfo does not
5292 // hold the information for the accessibility of its setter/getter
5294 // TODO: Refactor to use some kind of cache together with GetPropertyFromAccessor
5295 void ResolveAccessors (Type container_type)
5297 FindAccessors (container_type);
5299 if (getter != null) {
5300 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
5301 IMethodData md = TypeManager.GetMethod (the_getter);
5303 md.SetMemberIsUsed ();
5305 is_static = getter.IsStatic;
5308 if (setter != null) {
5309 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
5310 IMethodData md = TypeManager.GetMethod (the_setter);
5312 md.SetMemberIsUsed ();
5314 is_static = setter.IsStatic;
5318 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5320 if (InstanceExpression != null)
5321 InstanceExpression.MutateHoistedGenericType (storey);
5323 type = storey.MutateType (type);
5325 getter = storey.MutateGenericMethod (getter);
5327 setter = storey.MutateGenericMethod (setter);
5330 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
5333 InstanceExpression = null;
5337 if (InstanceExpression == null) {
5338 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5342 InstanceExpression = InstanceExpression.DoResolve (ec);
5343 if (lvalue_instance && InstanceExpression != null)
5344 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
5346 if (InstanceExpression == null)
5349 InstanceExpression.CheckMarshalByRefAccess (ec);
5351 if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) &&
5352 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
5353 !TypeManager.IsNestedChildOf (ec.ContainerType, InstanceExpression.Type) &&
5354 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.ContainerType)) {
5355 Report.SymbolRelatedToPreviousError (PropertyInfo);
5356 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
5363 void Error_PropertyNotFound (MethodInfo mi, bool getter)
5365 // TODO: correctly we should compare arguments but it will lead to bigger changes
5366 if (mi is MethodBuilder) {
5367 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
5371 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
5373 AParametersCollection iparams = TypeManager.GetParameterData (mi);
5374 sig.Append (getter ? "get_" : "set_");
5376 sig.Append (iparams.GetSignatureForError ());
5378 Report.SymbolRelatedToPreviousError (mi);
5379 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
5380 Name, sig.ToString ());
5383 public bool IsAccessibleFrom (Type invocation_type, bool lvalue)
5386 MethodInfo accessor = lvalue ? setter : getter;
5387 if (accessor == null && lvalue)
5389 return accessor != null && IsAccessorAccessible (invocation_type, accessor, out dummy);
5392 bool IsSingleDimensionalArrayLength ()
5394 if (DeclaringType != TypeManager.array_type || getter == null || Name != "Length")
5397 string t_name = InstanceExpression.Type.Name;
5398 int t_name_len = t_name.Length;
5399 return t_name_len > 2 && t_name [t_name_len - 2] == '[';
5402 override public Expression DoResolve (EmitContext ec)
5407 if (getter != null){
5408 if (TypeManager.GetParameterData (getter).Count != 0){
5409 Error_PropertyNotFound (getter, true);
5414 if (getter == null){
5416 // The following condition happens if the PropertyExpr was
5417 // created, but is invalid (ie, the property is inaccessible),
5418 // and we did not want to embed the knowledge about this in
5419 // the caller routine. This only avoids double error reporting.
5424 if (InstanceExpression != EmptyExpression.Null) {
5425 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5426 TypeManager.GetFullNameSignature (PropertyInfo));
5431 bool must_do_cs1540_check = false;
5432 if (getter != null &&
5433 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
5434 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
5435 if (pm != null && pm.HasCustomAccessModifier) {
5436 Report.SymbolRelatedToPreviousError (pm);
5437 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5438 TypeManager.CSharpSignature (getter));
5441 Report.SymbolRelatedToPreviousError (getter);
5442 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
5447 if (!InstanceResolve (ec, false, must_do_cs1540_check))
5451 // Only base will allow this invocation to happen.
5453 if (IsBase && getter.IsAbstract) {
5454 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5457 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
5461 if (!ec.IsInObsoleteScope) {
5462 PropertyBase pb = TypeManager.GetProperty (PropertyInfo);
5464 pb.CheckObsoleteness (loc);
5466 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (PropertyInfo);
5468 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc);
5477 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
5479 if (right_side == EmptyExpression.OutAccess) {
5480 if (ec.CurrentBlock.Toplevel.GetParameterReference (PropertyInfo.Name, loc) is MemberAccess) {
5481 Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5484 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as `ref' or `out' parameter",
5485 GetSignatureForError ());
5490 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5491 Error_CannotModifyIntermediateExpressionValue (ec);
5494 if (setter == null){
5496 // The following condition happens if the PropertyExpr was
5497 // created, but is invalid (ie, the property is inaccessible),
5498 // and we did not want to embed the knowledge about this in
5499 // the caller routine. This only avoids double error reporting.
5504 if (ec.CurrentBlock.Toplevel.GetParameterReference (PropertyInfo.Name, loc) is MemberAccess) {
5505 Report.Error (1947, loc, "A range variable `{0}' cannot be assigned to. Consider using `let' clause to store the value",
5508 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
5509 GetSignatureForError ());
5514 if (TypeManager.GetParameterData (setter).Count != 1){
5515 Error_PropertyNotFound (setter, false);
5519 bool must_do_cs1540_check;
5520 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
5521 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
5522 if (pm != null && pm.HasCustomAccessModifier) {
5523 Report.SymbolRelatedToPreviousError (pm);
5524 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5525 TypeManager.CSharpSignature (setter));
5528 Report.SymbolRelatedToPreviousError (setter);
5529 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
5534 if (!InstanceResolve (ec, PropertyInfo.DeclaringType.IsValueType, must_do_cs1540_check))
5538 // Only base will allow this invocation to happen.
5540 if (IsBase && setter.IsAbstract){
5541 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5544 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe) {
5548 if (!ec.IsInObsoleteScope) {
5549 PropertyBase pb = TypeManager.GetProperty (PropertyInfo);
5551 pb.CheckObsoleteness (loc);
5553 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (PropertyInfo);
5555 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc);
5562 public override void Emit (EmitContext ec)
5567 public void Emit (EmitContext ec, bool leave_copy)
5570 // Special case: length of single dimension array property is turned into ldlen
5572 if (IsSingleDimensionalArrayLength ()) {
5574 EmitInstance (ec, false);
5575 ec.ig.Emit (OpCodes.Ldlen);
5576 ec.ig.Emit (OpCodes.Conv_I4);
5580 Invocation.EmitCall (ec, IsBase, InstanceExpression, getter, null, loc, prepared, false);
5583 ec.ig.Emit (OpCodes.Dup);
5585 temp = new LocalTemporary (this.Type);
5592 // Implements the IAssignMethod interface for assignments
5594 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5596 Expression my_source = source;
5598 if (prepare_for_load) {
5603 ec.ig.Emit (OpCodes.Dup);
5605 temp = new LocalTemporary (this.Type);
5609 } else if (leave_copy) {
5611 temp = new LocalTemporary (this.Type);
5616 ArrayList args = new ArrayList (1);
5617 args.Add (new Argument (my_source, Argument.AType.Expression));
5619 Invocation.EmitCall (ec, IsBase, InstanceExpression, setter, args, loc, false, prepared);
5629 /// Fully resolved expression that evaluates to an Event
5631 public class EventExpr : MemberExpr {
5632 public readonly EventInfo EventInfo;
5635 MethodInfo add_accessor, remove_accessor;
5637 public EventExpr (EventInfo ei, Location loc)
5641 eclass = ExprClass.EventAccess;
5643 add_accessor = TypeManager.GetAddMethod (ei);
5644 remove_accessor = TypeManager.GetRemoveMethod (ei);
5645 if (add_accessor.IsStatic || remove_accessor.IsStatic)
5648 if (EventInfo is MyEventBuilder){
5649 MyEventBuilder eb = (MyEventBuilder) EventInfo;
5650 type = eb.EventType;
5653 type = EventInfo.EventHandlerType;
5656 public override string Name {
5658 return EventInfo.Name;
5662 public override bool IsInstance {
5668 public override bool IsStatic {
5674 public override Type DeclaringType {
5676 return EventInfo.DeclaringType;
5680 void Error_AssignmentEventOnly ()
5682 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5683 GetSignatureForError ());
5686 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
5687 SimpleName original)
5690 // If the event is local to this class, we transform ourselves into a FieldExpr
5693 if (EventInfo.DeclaringType == ec.ContainerType ||
5694 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
5695 EventField mi = TypeManager.GetEventField (EventInfo);
5698 if (!ec.IsInObsoleteScope)
5699 mi.CheckObsoleteness (loc);
5701 if ((mi.ModFlags & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0 && !ec.IsInCompoundAssignment)
5702 Error_AssignmentEventOnly ();
5704 FieldExpr ml = new FieldExpr (mi.FieldBuilder, loc);
5706 InstanceExpression = null;
5708 return ml.ResolveMemberAccess (ec, left, loc, original);
5712 if (left is This && !ec.IsInCompoundAssignment)
5713 Error_AssignmentEventOnly ();
5715 return base.ResolveMemberAccess (ec, left, loc, original);
5718 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
5721 InstanceExpression = null;
5725 if (InstanceExpression == null) {
5726 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5730 InstanceExpression = InstanceExpression.DoResolve (ec);
5731 if (InstanceExpression == null)
5734 if (IsBase && add_accessor.IsAbstract) {
5735 Error_CannotCallAbstractBase(TypeManager.CSharpSignature(add_accessor));
5740 // This is using the same mechanism as the CS1540 check in PropertyExpr.
5741 // However, in the Event case, we reported a CS0122 instead.
5743 // TODO: Exact copy from PropertyExpr
5745 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
5746 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
5747 !TypeManager.IsNestedChildOf (ec.ContainerType, InstanceExpression.Type) &&
5748 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.ContainerType)) {
5749 Report.SymbolRelatedToPreviousError (EventInfo);
5750 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5757 public bool IsAccessibleFrom (Type invocation_type)
5760 return IsAccessorAccessible (invocation_type, add_accessor, out dummy) &&
5761 IsAccessorAccessible (invocation_type, remove_accessor, out dummy);
5764 public override Expression CreateExpressionTree (EmitContext ec)
5766 throw new NotSupportedException ("ET");
5769 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5771 // contexts where an LValue is valid have already devolved to FieldExprs
5772 Error_CannotAssign ();
5776 public override Expression DoResolve (EmitContext ec)
5778 bool must_do_cs1540_check;
5779 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
5780 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
5781 Report.SymbolRelatedToPreviousError (EventInfo);
5782 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5786 if (!InstanceResolve (ec, must_do_cs1540_check))
5789 if (!ec.IsInCompoundAssignment) {
5790 Error_CannotAssign ();
5794 if (!ec.IsInObsoleteScope) {
5795 EventField ev = TypeManager.GetEventField (EventInfo);
5797 ev.CheckObsoleteness (loc);
5799 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (EventInfo);
5801 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc);
5808 public override void Emit (EmitContext ec)
5810 Error_CannotAssign ();
5813 public void Error_CannotAssign ()
5815 Report.Error (70, loc,
5816 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
5817 GetSignatureForError (), TypeManager.CSharpName (EventInfo.DeclaringType));
5820 public override string GetSignatureForError ()
5822 return TypeManager.CSharpSignature (EventInfo);
5825 public void EmitAddOrRemove (EmitContext ec, bool is_add, Expression source)
5827 ArrayList args = new ArrayList (1);
5828 args.Add (new Argument (source, Argument.AType.Expression));
5829 Invocation.EmitCall (ec, IsBase, InstanceExpression, is_add ? add_accessor : remove_accessor, args, loc);
5833 public class TemporaryVariable : VariableReference
5837 public TemporaryVariable (Type type, Location loc)
5841 eclass = ExprClass.Variable;
5844 public override Expression CreateExpressionTree (EmitContext ec)
5846 throw new NotSupportedException ("ET");
5849 public override Expression DoResolve (EmitContext ec)
5854 TypeExpr te = new TypeExpression (type, loc);
5855 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
5856 if (!li.Resolve (ec))
5860 // Don't capture temporary variables except when using
5861 // iterator redirection
5863 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.IsIterator && ec.IsVariableCapturingRequired) {
5864 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
5865 storey.CaptureLocalVariable (ec, li);
5871 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5873 return DoResolve (ec);
5876 public override void Emit (EmitContext ec)
5881 public void EmitAssign (EmitContext ec, Expression source)
5883 EmitAssign (ec, source, false, false);
5886 public override HoistedVariable GetHoistedVariable (EmitContext ec)
5888 return li.HoistedVariableReference;
5891 public override bool IsFixed {
5892 get { return true; }
5895 public override bool IsRef {
5896 get { return false; }
5899 public override string Name {
5900 get { throw new NotImplementedException (); }
5903 public override void SetHasAddressTaken ()
5905 throw new NotImplementedException ();
5908 protected override ILocalVariable Variable {
5912 public override VariableInfo VariableInfo {
5913 get { throw new NotImplementedException (); }
5918 /// Handles `var' contextual keyword; var becomes a keyword only
5919 /// if no type called var exists in a variable scope
5921 public class VarExpr : SimpleName
5923 // Used for error reporting only
5924 ArrayList initializer;
5926 public VarExpr (Location loc)
5931 public ArrayList VariableInitializer {
5933 this.initializer = value;
5937 public bool InferType (EmitContext ec, Expression right_side)
5940 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
5942 type = right_side.Type;
5943 if (type == TypeManager.null_type || type == TypeManager.void_type || type == TypeManager.anonymous_method_type) {
5944 Report.Error (815, loc, "An implicitly typed local variable declaration cannot be initialized with `{0}'",
5945 right_side.GetSignatureForError ());
5949 eclass = ExprClass.Variable;
5953 protected override void Error_TypeOrNamespaceNotFound (IResolveContext ec)
5955 Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");
5958 public override TypeExpr ResolveAsContextualType (IResolveContext rc, bool silent)
5960 TypeExpr te = base.ResolveAsContextualType (rc, true);
5964 if (initializer == null)
5967 if (initializer.Count > 1) {
5968 Location loc = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [1]).Location;
5969 Report.Error (819, loc, "An implicitly typed local variable declaration cannot include multiple declarators");
5974 Expression variable_initializer = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [0]).expression_or_array_initializer;
5975 if (variable_initializer == null) {
5976 Report.Error (818, loc, "An implicitly typed local variable declarator must include an initializer");