2 // ecore.cs: Core of the Expression representation for the intermediate tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@seznam.cz)
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
13 namespace Mono.CSharp {
15 using System.Collections;
16 using System.Diagnostics;
17 using System.Reflection;
18 using System.Reflection.Emit;
22 /// The ExprClass class contains the is used to pass the
23 /// classification of an expression (value, variable, namespace,
24 /// type, method group, property access, event access, indexer access,
27 public enum ExprClass : byte {
43 /// This is used to tell Resolve in which types of expressions we're
47 public enum ResolveFlags {
48 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
51 // Returns a type expression.
54 // Returns a method group.
57 TypeParameter = 1 << 3,
59 // Mask of all the expression class flags.
60 MaskExprClass = VariableOrValue | Type | MethodGroup | TypeParameter,
62 // Disable control flow analysis while resolving the expression.
63 // This is used when resolving the instance expression of a field expression.
64 DisableFlowAnalysis = 1 << 10,
66 // Set if this is resolving the first part of a MemberAccess.
67 Intermediate = 1 << 11,
69 // Disable control flow analysis _of struct_ while resolving the expression.
70 // This is used when resolving the instance expression of a field expression.
71 DisableStructFlowAnalysis = 1 << 12,
76 // This is just as a hint to AddressOf of what will be done with the
79 public enum AddressOp {
86 /// This interface is implemented by variables
88 public interface IMemoryLocation {
90 /// The AddressOf method should generate code that loads
91 /// the address of the object and leaves it on the stack.
93 /// The `mode' argument is used to notify the expression
94 /// of whether this will be used to read from the address or
95 /// write to the address.
97 /// This is just a hint that can be used to provide good error
98 /// reporting, and should have no other side effects.
100 void AddressOf (EmitContext ec, AddressOp mode);
104 // An expressions resolved as a direct variable reference
106 public interface IVariableReference : IFixedExpression
108 bool IsHoisted { get; }
110 VariableInfo VariableInfo { get; }
112 void SetHasAddressTaken ();
116 // Implemented by an expression which could be or is always
119 public interface IFixedExpression
121 bool IsFixed { get; }
125 /// Base class for expressions
127 public abstract class Expression {
128 public ExprClass eclass;
130 protected Location loc;
134 set { type = value; }
137 public virtual Location Location {
142 /// Utility wrapper routine for Error, just to beautify the code
144 public void Error (int error, string s)
146 Report.Error (error, loc, s);
149 // Not nice but we have broken hierarchy.
150 public virtual void CheckMarshalByRefAccess (EmitContext ec)
154 public virtual bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
156 Attribute.Error_AttributeArgumentNotValid (loc);
161 public virtual string GetSignatureForError ()
163 return TypeManager.CSharpName (type);
166 public static bool IsAccessorAccessible (Type invocation_type, MethodInfo mi, out bool must_do_cs1540_check)
168 MethodAttributes ma = mi.Attributes & MethodAttributes.MemberAccessMask;
170 must_do_cs1540_check = false; // by default we do not check for this
172 if (ma == MethodAttributes.Public)
176 // If only accessible to the current class or children
178 if (ma == MethodAttributes.Private)
179 return TypeManager.IsPrivateAccessible (invocation_type, mi.DeclaringType) ||
180 TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType);
182 if (TypeManager.IsThisOrFriendAssembly (mi.DeclaringType.Assembly)) {
183 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamORAssem)
186 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamANDAssem)
190 // Family and FamANDAssem require that we derive.
191 // FamORAssem requires that we derive if in different assemblies.
192 if (!TypeManager.IsNestedFamilyAccessible (invocation_type, mi.DeclaringType))
195 if (!TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType))
196 must_do_cs1540_check = true;
201 public virtual bool IsNull {
208 /// Performs semantic analysis on the Expression
212 /// The Resolve method is invoked to perform the semantic analysis
215 /// The return value is an expression (it can be the
216 /// same expression in some cases) or a new
217 /// expression that better represents this node.
219 /// For example, optimizations of Unary (LiteralInt)
220 /// would return a new LiteralInt with a negated
223 /// If there is an error during semantic analysis,
224 /// then an error should be reported (using Report)
225 /// and a null value should be returned.
227 /// There are two side effects expected from calling
228 /// Resolve(): the the field variable "eclass" should
229 /// be set to any value of the enumeration
230 /// `ExprClass' and the type variable should be set
231 /// to a valid type (this is the type of the
234 public abstract Expression DoResolve (EmitContext ec);
236 public virtual Expression DoResolveLValue (EmitContext ec, Expression right_side)
242 // This is used if the expression should be resolved as a type or namespace name.
243 // the default implementation fails.
245 public virtual FullNamedExpression ResolveAsTypeStep (IResolveContext rc, bool silent)
249 EmitContext ec = rc as EmitContext;
253 e.Error_UnexpectedKind (ResolveFlags.Type, loc);
259 // C# 3.0 introduced contextual keywords (var) which behaves like a type if type with
260 // same name exists or as a keyword when no type was found
262 public virtual TypeExpr ResolveAsContextualType (IResolveContext rc, bool silent)
264 return ResolveAsTypeTerminal (rc, silent);
268 // This is used to resolve the expression as a type, a null
269 // value will be returned if the expression is not a type
272 public virtual TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
274 TypeExpr te = ResolveAsBaseTerminal (ec, silent);
278 if (!silent) { // && !(te is TypeParameterExpr)) {
279 ObsoleteAttribute obsolete_attr = AttributeTester.GetObsoleteAttribute (te.Type);
280 if (obsolete_attr != null && !ec.IsInObsoleteScope) {
281 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location);
285 GenericTypeExpr ct = te as GenericTypeExpr;
287 // Skip constrains check for overrides and explicit implementations
288 // TODO: they should use different overload
289 GenericMethod gm = ec.GenericDeclContainer as GenericMethod;
290 if (gm != null && ((gm.ModFlags & Modifiers.OVERRIDE) != 0 || gm.MemberName.Left != null)) {
295 // TODO: silent flag is ignored
296 ct.CheckConstraints (ec);
302 public TypeExpr ResolveAsBaseTerminal (IResolveContext ec, bool silent)
304 int errors = Report.Errors;
306 FullNamedExpression fne = ResolveAsTypeStep (ec, silent);
311 TypeExpr te = fne as TypeExpr;
313 if (!silent && errors == Report.Errors)
314 fne.Error_UnexpectedKind (null, "type", loc);
318 if (!te.CheckAccessLevel (ec.GenericDeclContainer)) {
319 Report.SymbolRelatedToPreviousError (te.Type);
320 ErrorIsInaccesible (loc, TypeManager.CSharpName (te.Type));
328 public static void ErrorIsInaccesible (Location loc, string name)
330 Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", name);
333 protected static void Error_CannotAccessProtected (Location loc, MemberInfo m, Type qualifier, Type container)
335 Report.Error (1540, loc, "Cannot access protected member `{0}' via a qualifier of type `{1}'."
336 + " The qualifier must be of type `{2}' or derived from it",
337 TypeManager.GetFullNameSignature (m),
338 TypeManager.CSharpName (qualifier),
339 TypeManager.CSharpName (container));
343 public static void Error_InvalidExpressionStatement (Location loc)
345 Report.Error (201, loc, "Only assignment, call, increment, decrement, and new object " +
346 "expressions can be used as a statement");
349 public void Error_InvalidExpressionStatement ()
351 Error_InvalidExpressionStatement (loc);
354 protected void Error_CannotAssign (string to, string roContext)
356 Report.Error (1656, loc, "Cannot assign to `{0}' because it is a `{1}'",
360 public static void Error_VoidInvalidInTheContext (Location loc)
362 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
365 public virtual void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl)
367 Error_ValueCannotBeConvertedCore (ec, loc, target, expl);
370 protected void Error_ValueCannotBeConvertedCore (EmitContext ec, Location loc, Type target, bool expl)
372 // The error was already reported as CS1660
373 if (type == TypeManager.anonymous_method_type)
376 if (TypeManager.IsGenericParameter (Type) && TypeManager.IsGenericParameter (target) && type.Name == target.Name) {
378 string sig1 = type.DeclaringMethod == null ?
379 TypeManager.CSharpName (type.DeclaringType) :
380 TypeManager.CSharpSignature (type.DeclaringMethod);
381 string sig2 = target.DeclaringMethod == null ?
382 TypeManager.CSharpName (target.DeclaringType) :
383 TypeManager.CSharpSignature (target.DeclaringMethod);
384 Report.ExtraInformation (loc,
386 "The generic parameter `{0}' of `{1}' cannot be converted to the generic parameter `{0}' of `{2}' (in the previous ",
387 Type.Name, sig1, sig2));
389 } else if (Type.FullName == target.FullName){
390 Report.ExtraInformation (loc,
392 "The type `{0}' has two conflicting definitions, one comes from `{1}' and the other from `{2}' (in the previous ",
393 Type.FullName, Type.Assembly.FullName, target.Assembly.FullName));
397 Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
398 TypeManager.CSharpName (type), TypeManager.CSharpName (target));
402 Report.DisableReporting ();
403 bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null;
404 Report.EnableReporting ();
407 Report.Error (266, loc, "Cannot implicitly convert type `{0}' to `{1}'. " +
408 "An explicit conversion exists (are you missing a cast?)",
409 TypeManager.CSharpName (Type), TypeManager.CSharpName (target));
413 Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
414 TypeManager.CSharpName (type),
415 TypeManager.CSharpName (target));
418 public virtual void Error_VariableIsUsedBeforeItIsDeclared (string name)
420 Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", name);
423 protected virtual void Error_TypeDoesNotContainDefinition (Type type, string name)
425 Error_TypeDoesNotContainDefinition (loc, type, name);
428 public static void Error_TypeDoesNotContainDefinition (Location loc, Type type, string name)
430 Report.SymbolRelatedToPreviousError (type);
431 Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
432 TypeManager.CSharpName (type), name);
435 protected static void Error_ValueAssignment (Location loc)
437 Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
440 ResolveFlags ExprClassToResolveFlags
445 case ExprClass.Namespace:
446 return ResolveFlags.Type;
448 case ExprClass.MethodGroup:
449 return ResolveFlags.MethodGroup;
451 case ExprClass.TypeParameter:
452 return ResolveFlags.TypeParameter;
454 case ExprClass.Value:
455 case ExprClass.Variable:
456 case ExprClass.PropertyAccess:
457 case ExprClass.EventAccess:
458 case ExprClass.IndexerAccess:
459 return ResolveFlags.VariableOrValue;
462 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
468 /// Resolves an expression and performs semantic analysis on it.
472 /// Currently Resolve wraps DoResolve to perform sanity
473 /// checking and assertion checking on what we expect from Resolve.
475 public Expression Resolve (EmitContext ec, ResolveFlags flags)
477 if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type)
478 return ResolveAsTypeStep (ec, false);
480 bool do_flow_analysis = ec.DoFlowAnalysis;
481 bool omit_struct_analysis = ec.OmitStructFlowAnalysis;
482 if ((flags & ResolveFlags.DisableFlowAnalysis) != 0)
483 do_flow_analysis = false;
484 if ((flags & ResolveFlags.DisableStructFlowAnalysis) != 0)
485 omit_struct_analysis = true;
488 using (ec.WithFlowAnalysis (do_flow_analysis, omit_struct_analysis)) {
489 if (this is SimpleName) {
490 bool intermediate = (flags & ResolveFlags.Intermediate) == ResolveFlags.Intermediate;
491 e = ((SimpleName) this).DoResolve (ec, intermediate);
500 if ((flags & e.ExprClassToResolveFlags) == 0) {
501 e.Error_UnexpectedKind (flags, loc);
505 if (e.type == null && !(e is Namespace)) {
506 throw new Exception (
507 "Expression " + e.GetType () +
508 " did not set its type after Resolve\n" +
509 "called from: " + this.GetType ());
516 /// Resolves an expression and performs semantic analysis on it.
518 public Expression Resolve (EmitContext ec)
520 Expression e = Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
522 if (e != null && e.eclass == ExprClass.MethodGroup && RootContext.Version == LanguageVersion.ISO_1) {
523 ((MethodGroupExpr) e).ReportUsageError ();
529 public Constant ResolveAsConstant (EmitContext ec, MemberCore mc)
531 Expression e = Resolve (ec);
535 Constant c = e as Constant;
539 if (type != null && TypeManager.IsReferenceType (type))
540 Const.Error_ConstantCanBeInitializedWithNullOnly (type, loc, mc.GetSignatureForError ());
542 Const.Error_ExpressionMustBeConstant (loc, mc.GetSignatureForError ());
548 /// Resolves an expression for LValue assignment
552 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
553 /// checking and assertion checking on what we expect from Resolve
555 public Expression ResolveLValue (EmitContext ec, Expression right_side, Location loc)
557 int errors = Report.Errors;
558 bool out_access = right_side == EmptyExpression.OutAccess;
560 Expression e = DoResolveLValue (ec, right_side);
562 if (e != null && out_access && !(e is IMemoryLocation)) {
563 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
564 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
566 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
567 // e.GetType () + " " + e.GetSignatureForError ());
572 if (errors == Report.Errors) {
574 Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
576 Error_ValueAssignment (loc);
581 if (e.eclass == ExprClass.Invalid)
582 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
584 if ((e.type == null) && !(e is GenericTypeExpr))
585 throw new Exception ("Expression " + e + " did not set its type after Resolve");
591 /// Emits the code for the expression
595 /// The Emit method is invoked to generate the code
596 /// for the expression.
598 public abstract void Emit (EmitContext ec);
600 // Emit code to branch to @target if this expression is equivalent to @on_true.
601 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
602 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
603 // including the use of conditional branches. Note also that a branch MUST be emitted
604 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
607 ec.ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
610 // Emit this expression for its side effects, not for its value.
611 // The default implementation is to emit the value, and then throw it away.
612 // Subclasses can provide more efficient implementations, but those MUST be equivalent
613 public virtual void EmitSideEffect (EmitContext ec)
616 ec.ig.Emit (OpCodes.Pop);
620 /// Protected constructor. Only derivate types should
621 /// be able to be created
624 protected Expression ()
626 eclass = ExprClass.Invalid;
631 /// Returns a fully formed expression after a MemberLookup
634 public static Expression ExprClassFromMemberInfo (Type container_type, MemberInfo mi, Location loc)
637 return new EventExpr ((EventInfo) mi, loc);
638 else if (mi is FieldInfo) {
639 FieldInfo fi = (FieldInfo) mi;
640 if (fi.IsLiteral || (fi.IsInitOnly && fi.FieldType == TypeManager.decimal_type))
641 return new ConstantExpr (fi, loc);
642 return new FieldExpr (fi, loc);
643 } else if (mi is PropertyInfo)
644 return new PropertyExpr (container_type, (PropertyInfo) mi, loc);
645 else if (mi is Type) {
646 return new TypeExpression ((System.Type) mi, loc);
652 // TODO: [Obsolete ("Can be removed")]
653 protected static ArrayList almost_matched_members = new ArrayList (4);
656 // FIXME: Probably implement a cache for (t,name,current_access_set)?
658 // This code could use some optimizations, but we need to do some
659 // measurements. For example, we could use a delegate to `flag' when
660 // something can not any longer be a method-group (because it is something
664 // If the return value is an Array, then it is an array of
667 // If the return value is an MemberInfo, it is anything, but a Method
671 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
672 // the arguments here and have MemberLookup return only the methods that
673 // match the argument count/type, unlike we are doing now (we delay this
676 // This is so we can catch correctly attempts to invoke instance methods
677 // from a static body (scan for error 120 in ResolveSimpleName).
680 // FIXME: Potential optimization, have a static ArrayList
683 public static Expression MemberLookup (Type container_type, Type queried_type, string name,
684 MemberTypes mt, BindingFlags bf, Location loc)
686 return MemberLookup (container_type, null, queried_type, name, mt, bf, loc);
690 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
691 // `qualifier_type' or null to lookup members in the current class.
694 public static Expression MemberLookup (Type container_type,
695 Type qualifier_type, Type queried_type,
696 string name, MemberTypes mt,
697 BindingFlags bf, Location loc)
699 almost_matched_members.Clear ();
701 MemberInfo [] mi = TypeManager.MemberLookup (container_type, qualifier_type,
702 queried_type, mt, bf, name, almost_matched_members);
708 bool is_interface = qualifier_type != null && qualifier_type.IsInterface;
709 ArrayList methods = new ArrayList (2);
710 ArrayList non_methods = null;
712 foreach (MemberInfo m in mi) {
713 if (m is MethodBase) {
718 if (non_methods == null) {
719 non_methods = new ArrayList (2);
724 foreach (MemberInfo n_m in non_methods) {
725 if (m.DeclaringType.IsInterface && TypeManager.ImplementsInterface (m.DeclaringType, n_m.DeclaringType))
728 Report.SymbolRelatedToPreviousError (m);
729 Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
730 TypeManager.GetFullNameSignature (m), TypeManager.GetFullNameSignature (n_m));
735 if (methods.Count == 0)
736 return ExprClassFromMemberInfo (container_type, (MemberInfo)non_methods [0], loc);
738 if (non_methods != null) {
739 MethodBase method = (MethodBase) methods [0];
740 MemberInfo non_method = (MemberInfo) non_methods [0];
741 if (method.DeclaringType == non_method.DeclaringType) {
742 // Cannot happen with C# code, but is valid in IL
743 Report.SymbolRelatedToPreviousError (method);
744 Report.SymbolRelatedToPreviousError (non_method);
745 Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
746 TypeManager.GetFullNameSignature (non_method),
747 TypeManager.CSharpSignature (method));
752 Report.SymbolRelatedToPreviousError (method);
753 Report.SymbolRelatedToPreviousError (non_method);
754 Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and non-method `{1}'. Using method `{0}'",
755 TypeManager.CSharpSignature (method), TypeManager.GetFullNameSignature (non_method));
759 return new MethodGroupExpr (methods, queried_type, loc);
762 if (mi [0] is MethodBase)
763 return new MethodGroupExpr (mi, queried_type, loc);
765 return ExprClassFromMemberInfo (container_type, mi [0], loc);
768 public const MemberTypes AllMemberTypes =
769 MemberTypes.Constructor |
773 MemberTypes.NestedType |
774 MemberTypes.Property;
776 public const BindingFlags AllBindingFlags =
777 BindingFlags.Public |
778 BindingFlags.Static |
779 BindingFlags.Instance;
781 public static Expression MemberLookup (Type container_type, Type queried_type,
782 string name, Location loc)
784 return MemberLookup (container_type, null, queried_type, name,
785 AllMemberTypes, AllBindingFlags, loc);
788 public static Expression MemberLookup (Type container_type, Type qualifier_type,
789 Type queried_type, string name, Location loc)
791 return MemberLookup (container_type, qualifier_type, queried_type,
792 name, AllMemberTypes, AllBindingFlags, loc);
795 public static MethodGroupExpr MethodLookup (Type container_type, Type queried_type,
796 string name, Location loc)
798 return (MethodGroupExpr)MemberLookup (container_type, null, queried_type, name,
799 MemberTypes.Method, AllBindingFlags, loc);
803 /// This is a wrapper for MemberLookup that is not used to "probe", but
804 /// to find a final definition. If the final definition is not found, we
805 /// look for private members and display a useful debugging message if we
808 protected Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
809 Type queried_type, string name,
810 MemberTypes mt, BindingFlags bf,
815 int errors = Report.Errors;
816 e = MemberLookup (ec.ContainerType, qualifier_type, queried_type, name, mt, bf, loc);
818 if (e != null || errors != Report.Errors)
821 // No errors were reported by MemberLookup, but there was an error.
822 return Error_MemberLookupFailed (ec.ContainerType, qualifier_type, queried_type,
826 protected virtual Expression Error_MemberLookupFailed (Type container_type, Type qualifier_type,
827 Type queried_type, string name, string class_name,
828 MemberTypes mt, BindingFlags bf)
830 MemberInfo[] lookup = null;
831 if (queried_type == null) {
832 class_name = "global::";
834 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
835 mt, (bf & ~BindingFlags.Public) | BindingFlags.NonPublic,
838 if (lookup != null) {
839 Expression e = Error_MemberLookupFailed (queried_type, lookup);
842 // FIXME: This is still very wrong, it should be done inside
843 // OverloadResolve to do correct arguments matching.
844 // Requires MemberLookup accessiblity check removal
846 if (e == null || (mt & (MemberTypes.Method | MemberTypes.Constructor)) == 0) {
847 MemberInfo mi = lookup[0];
848 Report.SymbolRelatedToPreviousError (mi);
849 if (qualifier_type != null && container_type != null && qualifier_type != container_type &&
850 TypeManager.IsNestedFamilyAccessible (container_type, mi.DeclaringType)) {
851 // Although a derived class can access protected members of
852 // its base class it cannot do so through an instance of the
853 // base class (CS1540). If the qualifier_type is a base of the
854 // ec.ContainerType and the lookup succeeds with the latter one,
855 // then we are in this situation.
856 Error_CannotAccessProtected (loc, mi, qualifier_type, container_type);
858 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (mi));
865 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
866 AllMemberTypes, AllBindingFlags | BindingFlags.NonPublic,
870 if (lookup == null) {
871 if (class_name != null) {
872 Report.Error (103, loc, "The name `{0}' does not exist in the current context",
875 Error_TypeDoesNotContainDefinition (queried_type, name);
880 if (TypeManager.MemberLookup (queried_type, null, queried_type,
881 AllMemberTypes, AllBindingFlags |
882 BindingFlags.NonPublic, name, null) == null) {
883 if ((lookup.Length == 1) && (lookup [0] is Type)) {
884 Type t = (Type) lookup [0];
886 Report.Error (305, loc,
887 "Using the generic type `{0}' " +
888 "requires {1} type arguments",
889 TypeManager.CSharpName (t),
890 TypeManager.GetNumberOfTypeArguments (t).ToString ());
895 return Error_MemberLookupFailed (queried_type, lookup);
898 protected virtual Expression Error_MemberLookupFailed (Type type, MemberInfo[] members)
900 for (int i = 0; i < members.Length; ++i) {
901 if (!(members [i] is MethodBase))
905 // By default propagate the closest candidates upwards
906 return new MethodGroupExpr (members, type, loc, true);
909 protected virtual void Error_NegativeArrayIndex (Location loc)
911 throw new NotImplementedException ();
914 protected void Error_PointerInsideExpressionTree ()
916 Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
920 /// Returns an expression that can be used to invoke operator true
921 /// on the expression if it exists.
923 static public Expression GetOperatorTrue (EmitContext ec, Expression e, Location loc)
925 return GetOperatorTrueOrFalse (ec, e, true, loc);
929 /// Returns an expression that can be used to invoke operator false
930 /// on the expression if it exists.
932 static public Expression GetOperatorFalse (EmitContext ec, Expression e, Location loc)
934 return GetOperatorTrueOrFalse (ec, e, false, loc);
937 static Expression GetOperatorTrueOrFalse (EmitContext ec, Expression e, bool is_true, Location loc)
939 MethodGroupExpr operator_group;
940 string mname = Operator.GetMetadataName (is_true ? Operator.OpType.True : Operator.OpType.False);
941 operator_group = MethodLookup (ec.ContainerType, e.Type, mname, loc) as MethodGroupExpr;
942 if (operator_group == null)
945 ArrayList arguments = new ArrayList (1);
946 arguments.Add (new Argument (e, Argument.AType.Expression));
947 operator_group = operator_group.OverloadResolve (
948 ec, ref arguments, false, loc);
950 if (operator_group == null)
953 return new UserOperatorCall (operator_group, arguments, null, loc);
957 /// Resolves the expression `e' into a boolean expression: either through
958 /// an implicit conversion, or through an `operator true' invocation
960 public static Expression ResolveBoolean (EmitContext ec, Expression e, Location loc)
966 if (e.Type == TypeManager.bool_type)
969 Expression converted = Convert.ImplicitConversion (ec, e, TypeManager.bool_type, Location.Null);
971 if (converted != null)
975 // If no implicit conversion to bool exists, try using `operator true'
977 converted = Expression.GetOperatorTrue (ec, e, loc);
978 if (converted == null){
979 e.Error_ValueCannotBeConverted (ec, loc, TypeManager.bool_type, false);
985 public virtual string ExprClassName
989 case ExprClass.Invalid:
991 case ExprClass.Value:
993 case ExprClass.Variable:
995 case ExprClass.Namespace:
999 case ExprClass.MethodGroup:
1000 return "method group";
1001 case ExprClass.PropertyAccess:
1002 return "property access";
1003 case ExprClass.EventAccess:
1004 return "event access";
1005 case ExprClass.IndexerAccess:
1006 return "indexer access";
1007 case ExprClass.Nothing:
1009 case ExprClass.TypeParameter:
1010 return "type parameter";
1012 throw new Exception ("Should not happen");
1017 /// Reports that we were expecting `expr' to be of class `expected'
1019 public void Error_UnexpectedKind (DeclSpace ds, string expected, Location loc)
1021 Error_UnexpectedKind (ds, expected, ExprClassName, loc);
1024 public void Error_UnexpectedKind (DeclSpace ds, string expected, string was, Location loc)
1026 string name = GetSignatureForError ();
1028 name = ds.GetSignatureForError () + '.' + name;
1030 Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
1031 name, was, expected);
1034 public void Error_UnexpectedKind (ResolveFlags flags, Location loc)
1036 string [] valid = new string [4];
1039 if ((flags & ResolveFlags.VariableOrValue) != 0) {
1040 valid [count++] = "variable";
1041 valid [count++] = "value";
1044 if ((flags & ResolveFlags.Type) != 0)
1045 valid [count++] = "type";
1047 if ((flags & ResolveFlags.MethodGroup) != 0)
1048 valid [count++] = "method group";
1051 valid [count++] = "unknown";
1053 StringBuilder sb = new StringBuilder (valid [0]);
1054 for (int i = 1; i < count - 1; i++) {
1056 sb.Append (valid [i]);
1059 sb.Append ("' or `");
1060 sb.Append (valid [count - 1]);
1063 Report.Error (119, loc,
1064 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1067 public static void UnsafeError (Location loc)
1069 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1073 // Load the object from the pointer.
1075 public static void LoadFromPtr (ILGenerator ig, Type t)
1077 if (t == TypeManager.int32_type)
1078 ig.Emit (OpCodes.Ldind_I4);
1079 else if (t == TypeManager.uint32_type)
1080 ig.Emit (OpCodes.Ldind_U4);
1081 else if (t == TypeManager.short_type)
1082 ig.Emit (OpCodes.Ldind_I2);
1083 else if (t == TypeManager.ushort_type)
1084 ig.Emit (OpCodes.Ldind_U2);
1085 else if (t == TypeManager.char_type)
1086 ig.Emit (OpCodes.Ldind_U2);
1087 else if (t == TypeManager.byte_type)
1088 ig.Emit (OpCodes.Ldind_U1);
1089 else if (t == TypeManager.sbyte_type)
1090 ig.Emit (OpCodes.Ldind_I1);
1091 else if (t == TypeManager.uint64_type)
1092 ig.Emit (OpCodes.Ldind_I8);
1093 else if (t == TypeManager.int64_type)
1094 ig.Emit (OpCodes.Ldind_I8);
1095 else if (t == TypeManager.float_type)
1096 ig.Emit (OpCodes.Ldind_R4);
1097 else if (t == TypeManager.double_type)
1098 ig.Emit (OpCodes.Ldind_R8);
1099 else if (t == TypeManager.bool_type)
1100 ig.Emit (OpCodes.Ldind_I1);
1101 else if (t == TypeManager.intptr_type)
1102 ig.Emit (OpCodes.Ldind_I);
1103 else if (TypeManager.IsEnumType (t)) {
1104 if (t == TypeManager.enum_type)
1105 ig.Emit (OpCodes.Ldind_Ref);
1107 LoadFromPtr (ig, TypeManager.GetEnumUnderlyingType (t));
1108 } else if (TypeManager.IsStruct (t) || TypeManager.IsGenericParameter (t))
1109 ig.Emit (OpCodes.Ldobj, t);
1110 else if (t.IsPointer)
1111 ig.Emit (OpCodes.Ldind_I);
1113 ig.Emit (OpCodes.Ldind_Ref);
1117 // The stack contains the pointer and the value of type `type'
1119 public static void StoreFromPtr (ILGenerator ig, Type type)
1121 if (TypeManager.IsEnumType (type))
1122 type = TypeManager.GetEnumUnderlyingType (type);
1123 if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
1124 ig.Emit (OpCodes.Stind_I4);
1125 else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
1126 ig.Emit (OpCodes.Stind_I8);
1127 else if (type == TypeManager.char_type || type == TypeManager.short_type ||
1128 type == TypeManager.ushort_type)
1129 ig.Emit (OpCodes.Stind_I2);
1130 else if (type == TypeManager.float_type)
1131 ig.Emit (OpCodes.Stind_R4);
1132 else if (type == TypeManager.double_type)
1133 ig.Emit (OpCodes.Stind_R8);
1134 else if (type == TypeManager.byte_type || type == TypeManager.sbyte_type ||
1135 type == TypeManager.bool_type)
1136 ig.Emit (OpCodes.Stind_I1);
1137 else if (type == TypeManager.intptr_type)
1138 ig.Emit (OpCodes.Stind_I);
1139 else if (TypeManager.IsStruct (type) || TypeManager.IsGenericParameter (type))
1140 ig.Emit (OpCodes.Stobj, type);
1142 ig.Emit (OpCodes.Stind_Ref);
1146 // Returns the size of type `t' if known, otherwise, 0
1148 public static int GetTypeSize (Type t)
1150 t = TypeManager.TypeToCoreType (t);
1151 if (t == TypeManager.int32_type ||
1152 t == TypeManager.uint32_type ||
1153 t == TypeManager.float_type)
1155 else if (t == TypeManager.int64_type ||
1156 t == TypeManager.uint64_type ||
1157 t == TypeManager.double_type)
1159 else if (t == TypeManager.byte_type ||
1160 t == TypeManager.sbyte_type ||
1161 t == TypeManager.bool_type)
1163 else if (t == TypeManager.short_type ||
1164 t == TypeManager.char_type ||
1165 t == TypeManager.ushort_type)
1167 else if (t == TypeManager.decimal_type)
1173 protected void Error_CannotCallAbstractBase (string name)
1175 Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
1178 protected void Error_CannotModifyIntermediateExpressionValue (EmitContext ec)
1180 Report.SymbolRelatedToPreviousError (type);
1181 if (ec.CurrentInitializerVariable != null) {
1182 Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
1183 TypeManager.CSharpName (type), GetSignatureForError ());
1185 Report.Error (1612, loc, "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
1186 GetSignatureForError ());
1190 public void Error_ExpressionCannotBeGeneric (Location loc)
1192 Report.Error (307, loc, "The {0} `{1}' cannot be used with type arguments",
1193 ExprClassName, GetSignatureForError ());
1197 // Converts `source' to an int, uint, long or ulong.
1199 public Expression ConvertExpressionToArrayIndex (EmitContext ec, Expression source)
1201 Expression converted;
1203 using (ec.With (EmitContext.Flags.CheckState, true)) {
1204 converted = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, source.loc);
1205 if (converted == null)
1206 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, source.loc);
1207 if (converted == null)
1208 converted = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, source.loc);
1209 if (converted == null)
1210 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, source.loc);
1212 if (converted == null) {
1213 source.Error_ValueCannotBeConverted (ec, source.loc, TypeManager.int32_type, false);
1219 // Only positive constants are allowed at compile time
1221 Constant c = converted as Constant;
1224 Error_NegativeArrayIndex (source.loc);
1229 return new ArrayIndexCast (converted).Resolve (ec);
1233 // Derived classes implement this method by cloning the fields that
1234 // could become altered during the Resolve stage
1236 // Only expressions that are created for the parser need to implement
1239 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1241 throw new NotImplementedException (
1243 "CloneTo not implemented for expression {0}", this.GetType ()));
1247 // Clones an expression created by the parser.
1249 // We only support expressions created by the parser so far, not
1250 // expressions that have been resolved (many more classes would need
1251 // to implement CloneTo).
1253 // This infrastructure is here merely for Lambda expressions which
1254 // compile the same code using different type values for the same
1255 // arguments to find the correct overload
1257 public Expression Clone (CloneContext clonectx)
1259 Expression cloned = (Expression) MemberwiseClone ();
1260 CloneTo (clonectx, cloned);
1266 // Implementation of expression to expression tree conversion
1268 public abstract Expression CreateExpressionTree (EmitContext ec);
1270 protected Expression CreateExpressionFactoryCall (string name, ArrayList args)
1272 return CreateExpressionFactoryCall (name, null, args, loc);
1275 protected Expression CreateExpressionFactoryCall (string name, TypeArguments typeArguments, ArrayList args)
1277 return CreateExpressionFactoryCall (name, typeArguments, args, loc);
1280 public static Expression CreateExpressionFactoryCall (string name, TypeArguments typeArguments, ArrayList args, Location loc)
1282 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (loc), name, typeArguments, loc), args);
1285 protected static TypeExpr CreateExpressionTypeExpression (Location loc)
1287 TypeExpr texpr = TypeManager.expression_type_expr;
1288 if (texpr == null) {
1289 Type t = TypeManager.CoreLookupType ("System.Linq.Expressions", "Expression", Kind.Class, true);
1293 TypeManager.expression_type_expr = texpr = new TypeExpression (t, Location.Null);
1299 public virtual void MutateHoistedGenericType (AnonymousMethodStorey storey)
1301 // TODO: It should probably be type = storey.MutateType (type);
1306 /// This is just a base class for expressions that can
1307 /// appear on statements (invocations, object creation,
1308 /// assignments, post/pre increment and decrement). The idea
1309 /// being that they would support an extra Emition interface that
1310 /// does not leave a result on the stack.
1312 public abstract class ExpressionStatement : Expression {
1314 public virtual ExpressionStatement ResolveStatement (EmitContext ec)
1316 Expression e = Resolve (ec);
1320 ExpressionStatement es = e as ExpressionStatement;
1322 Error_InvalidExpressionStatement ();
1328 /// Requests the expression to be emitted in a `statement'
1329 /// context. This means that no new value is left on the
1330 /// stack after invoking this method (constrasted with
1331 /// Emit that will always leave a value on the stack).
1333 public abstract void EmitStatement (EmitContext ec);
1335 public override void EmitSideEffect (EmitContext ec)
1342 /// This kind of cast is used to encapsulate the child
1343 /// whose type is child.Type into an expression that is
1344 /// reported to return "return_type". This is used to encapsulate
1345 /// expressions which have compatible types, but need to be dealt
1346 /// at higher levels with.
1348 /// For example, a "byte" expression could be encapsulated in one
1349 /// of these as an "unsigned int". The type for the expression
1350 /// would be "unsigned int".
1353 public abstract class TypeCast : Expression
1355 protected readonly Expression child;
1357 protected TypeCast (Expression child, Type return_type)
1359 eclass = child.eclass;
1360 loc = child.Location;
1365 public override Expression CreateExpressionTree (EmitContext ec)
1367 ArrayList args = new ArrayList (2);
1368 args.Add (new Argument (child.CreateExpressionTree (ec)));
1369 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1371 if (type.IsPointer || child.Type.IsPointer)
1372 Error_PointerInsideExpressionTree ();
1374 return CreateExpressionFactoryCall (ec.CheckState ? "ConvertChecked" : "Convert", args);
1377 public override Expression DoResolve (EmitContext ec)
1379 // This should never be invoked, we are born in fully
1380 // initialized state.
1385 public override void Emit (EmitContext ec)
1390 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
1392 return child.GetAttributableValue (ec, value_type, out value);
1395 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1397 type = storey.MutateType (type);
1398 child.MutateHoistedGenericType (storey);
1401 protected override void CloneTo (CloneContext clonectx, Expression t)
1406 public override bool IsNull {
1407 get { return child.IsNull; }
1411 public class EmptyCast : TypeCast {
1412 EmptyCast (Expression child, Type target_type)
1413 : base (child, target_type)
1417 public static Expression Create (Expression child, Type type)
1419 Constant c = child as Constant;
1421 return new EmptyConstantCast (c, type);
1423 EmptyCast e = child as EmptyCast;
1425 return new EmptyCast (e.child, type);
1427 return new EmptyCast (child, type);
1430 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1432 child.EmitBranchable (ec, label, on_true);
1435 public override void EmitSideEffect (EmitContext ec)
1437 child.EmitSideEffect (ec);
1442 // Used for predefined class library user casts (no obsolete check, etc.)
1444 public class OperatorCast : TypeCast {
1445 MethodInfo conversion_operator;
1447 public OperatorCast (Expression child, Type target_type)
1448 : this (child, target_type, false)
1452 public OperatorCast (Expression child, Type target_type, bool find_explicit)
1453 : base (child, target_type)
1455 conversion_operator = GetConversionOperator (find_explicit);
1456 if (conversion_operator == null)
1457 throw new InternalErrorException ("Outer conversion routine is out of sync");
1460 // Returns the implicit operator that converts from
1461 // 'child.Type' to our target type (type)
1462 MethodInfo GetConversionOperator (bool find_explicit)
1464 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1468 mi = TypeManager.MemberLookup (child.Type, child.Type, child.Type, MemberTypes.Method,
1469 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1472 mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1473 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1476 foreach (MethodInfo oper in mi) {
1477 AParametersCollection pd = TypeManager.GetParameterData (oper);
1479 if (pd.Types [0] == child.Type && TypeManager.TypeToCoreType (oper.ReturnType) == type)
1486 public override void Emit (EmitContext ec)
1489 ec.ig.Emit (OpCodes.Call, conversion_operator);
1494 /// This is a numeric cast to a Decimal
1496 public class CastToDecimal : OperatorCast {
1497 public CastToDecimal (Expression child)
1498 : this (child, false)
1502 public CastToDecimal (Expression child, bool find_explicit)
1503 : base (child, TypeManager.decimal_type, find_explicit)
1509 /// This is an explicit numeric cast from a Decimal
1511 public class CastFromDecimal : TypeCast
1513 static IDictionary operators;
1515 public CastFromDecimal (Expression child, Type return_type)
1516 : base (child, return_type)
1518 if (child.Type != TypeManager.decimal_type)
1519 throw new InternalErrorException (
1520 "The expected type is Decimal, instead it is " + child.Type.FullName);
1523 // Returns the explicit operator that converts from an
1524 // express of type System.Decimal to 'type'.
1525 public Expression Resolve ()
1527 if (operators == null) {
1528 MemberInfo[] all_oper = TypeManager.MemberLookup (TypeManager.decimal_type,
1529 TypeManager.decimal_type, TypeManager.decimal_type, MemberTypes.Method,
1530 BindingFlags.Static | BindingFlags.Public, "op_Explicit", null);
1532 operators = new System.Collections.Specialized.HybridDictionary ();
1533 foreach (MethodInfo oper in all_oper) {
1534 AParametersCollection pd = TypeManager.GetParameterData (oper);
1535 if (pd.Types [0] == TypeManager.decimal_type)
1536 operators.Add (TypeManager.TypeToCoreType (oper.ReturnType), oper);
1540 return operators.Contains (type) ? this : null;
1543 public override void Emit (EmitContext ec)
1545 ILGenerator ig = ec.ig;
1548 ig.Emit (OpCodes.Call, (MethodInfo)operators [type]);
1554 // Constant specialization of EmptyCast.
1555 // We need to special case this since an empty cast of
1556 // a constant is still a constant.
1558 public class EmptyConstantCast : Constant
1560 public readonly Constant child;
1562 public EmptyConstantCast(Constant child, Type type)
1563 : base (child.Location)
1565 eclass = child.eclass;
1570 public override string AsString ()
1572 return child.AsString ();
1575 public override object GetValue ()
1577 return child.GetValue ();
1580 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
1582 // FIXME: check that 'type' can be converted to 'target_type' first
1583 return child.ConvertExplicitly (in_checked_context, target_type);
1586 public override Expression CreateExpressionTree (EmitContext ec)
1588 ArrayList args = new ArrayList (2);
1589 args.Add (new Argument (child.CreateExpressionTree (ec)));
1590 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1592 Error_PointerInsideExpressionTree ();
1594 return CreateExpressionFactoryCall ("Convert", args);
1597 public override Constant Increment ()
1599 return child.Increment ();
1602 public override bool IsDefaultValue {
1603 get { return child.IsDefaultValue; }
1606 public override bool IsNegative {
1607 get { return child.IsNegative; }
1610 public override bool IsNull {
1611 get { return child.IsNull; }
1614 public override bool IsZeroInteger {
1615 get { return child.IsZeroInteger; }
1618 public override void Emit (EmitContext ec)
1623 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1625 child.EmitBranchable (ec, label, on_true);
1628 // Only to make verifier happy
1629 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1630 ec.ig.Emit (OpCodes.Unbox_Any, type);
1634 public override void EmitSideEffect (EmitContext ec)
1636 child.EmitSideEffect (ec);
1639 public override Constant ConvertImplicitly (Type target_type)
1641 // FIXME: Do we need to check user conversions?
1642 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1644 return child.ConvertImplicitly (target_type);
1647 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1649 child.MutateHoistedGenericType (storey);
1655 /// This class is used to wrap literals which belong inside Enums
1657 public class EnumConstant : Constant {
1658 public Constant Child;
1660 public EnumConstant (Constant child, Type enum_type):
1661 base (child.Location)
1663 eclass = child.eclass;
1668 public override Expression DoResolve (EmitContext ec)
1670 // This should never be invoked, we are born in fully
1671 // initialized state.
1676 public override void Emit (EmitContext ec)
1681 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1683 Child.EmitBranchable (ec, label, on_true);
1686 public override void EmitSideEffect (EmitContext ec)
1688 Child.EmitSideEffect (ec);
1691 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
1693 value = GetTypedValue ();
1697 public override string GetSignatureForError()
1699 return TypeManager.CSharpName (Type);
1702 public override object GetValue ()
1704 return Child.GetValue ();
1707 public override object GetTypedValue ()
1709 // FIXME: runtime is not ready to work with just emited enums
1710 if (!RootContext.StdLib) {
1711 return Child.GetValue ();
1715 // Small workaround for big problem
1716 // System.Enum.ToObject cannot be called on dynamic types
1717 // EnumBuilder has to be used, but we cannot use EnumBuilder
1718 // because it does not properly support generics
1720 // This works only sometimes
1722 if (type.Module == RootContext.ToplevelTypes.Builder)
1723 return Child.GetValue ();
1726 return System.Enum.ToObject (type, Child.GetValue ());
1729 public override string AsString ()
1731 return Child.AsString ();
1734 public override Constant Increment()
1736 return new EnumConstant (Child.Increment (), type);
1739 public override bool IsDefaultValue {
1741 return Child.IsDefaultValue;
1745 public override bool IsZeroInteger {
1746 get { return Child.IsZeroInteger; }
1749 public override bool IsNegative {
1751 return Child.IsNegative;
1755 public override Constant ConvertExplicitly(bool in_checked_context, Type target_type)
1757 if (Child.Type == target_type)
1760 return Child.ConvertExplicitly (in_checked_context, target_type);
1763 public override Constant ConvertImplicitly (Type type)
1765 Type this_type = TypeManager.DropGenericTypeArguments (Type);
1766 type = TypeManager.DropGenericTypeArguments (type);
1768 if (this_type == type) {
1769 // This is workaround of mono bug. It can be removed when the latest corlib spreads enough
1770 if (TypeManager.IsEnumType (type.UnderlyingSystemType))
1773 Type child_type = TypeManager.DropGenericTypeArguments (Child.Type);
1774 if (type.UnderlyingSystemType != child_type)
1775 Child = Child.ConvertImplicitly (type.UnderlyingSystemType);
1779 if (!Convert.ImplicitStandardConversionExists (this, type)){
1783 return Child.ConvertImplicitly(type);
1789 /// This kind of cast is used to encapsulate Value Types in objects.
1791 /// The effect of it is to box the value type emitted by the previous
1794 public class BoxedCast : TypeCast {
1796 public BoxedCast (Expression expr, Type target_type)
1797 : base (expr, target_type)
1799 eclass = ExprClass.Value;
1802 public override Expression DoResolve (EmitContext ec)
1804 // This should never be invoked, we are born in fully
1805 // initialized state.
1810 public override void Emit (EmitContext ec)
1814 ec.ig.Emit (OpCodes.Box, child.Type);
1817 public override void EmitSideEffect (EmitContext ec)
1819 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1820 // so, we need to emit the box+pop instructions in most cases
1821 if (TypeManager.IsStruct (child.Type) &&
1822 (type == TypeManager.object_type || type == TypeManager.value_type))
1823 child.EmitSideEffect (ec);
1825 base.EmitSideEffect (ec);
1829 public class UnboxCast : TypeCast {
1830 public UnboxCast (Expression expr, Type return_type)
1831 : base (expr, return_type)
1835 public override Expression DoResolve (EmitContext ec)
1837 // This should never be invoked, we are born in fully
1838 // initialized state.
1843 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1845 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
1846 Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
1847 return base.DoResolveLValue (ec, right_side);
1850 public override void Emit (EmitContext ec)
1854 ILGenerator ig = ec.ig;
1857 ig.Emit (OpCodes.Unbox_Any, type);
1859 ig.Emit (OpCodes.Unbox, type);
1860 LoadFromPtr (ig, type);
1864 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1866 type = storey.MutateType (type);
1867 base.MutateHoistedGenericType (storey);
1872 /// This is used to perform explicit numeric conversions.
1874 /// Explicit numeric conversions might trigger exceptions in a checked
1875 /// context, so they should generate the conv.ovf opcodes instead of
1878 public class ConvCast : TypeCast {
1879 public enum Mode : byte {
1880 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1882 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1883 U2_I1, U2_U1, U2_I2, U2_CH,
1884 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1885 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1886 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH,
1887 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH,
1888 CH_I1, CH_U1, CH_I2,
1889 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1890 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4
1895 public ConvCast (Expression child, Type return_type, Mode m)
1896 : base (child, return_type)
1901 public override Expression DoResolve (EmitContext ec)
1903 // This should never be invoked, we are born in fully
1904 // initialized state.
1909 public override string ToString ()
1911 return String.Format ("ConvCast ({0}, {1})", mode, child);
1914 public override void Emit (EmitContext ec)
1916 ILGenerator ig = ec.ig;
1922 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1923 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1924 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1925 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1926 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1928 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1929 case Mode.U1_CH: /* nothing */ break;
1931 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1932 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1933 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1934 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1935 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1936 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1938 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1939 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1940 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1941 case Mode.U2_CH: /* nothing */ break;
1943 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1944 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1945 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1946 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1947 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1948 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1949 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1951 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1952 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1953 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1954 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1955 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1956 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1958 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1959 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1960 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1961 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1962 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1963 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1964 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1965 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1967 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1968 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1969 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1970 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1971 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1972 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1973 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1974 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1976 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1977 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1978 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1980 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1981 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1982 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1983 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1984 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1985 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1986 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1987 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1988 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1990 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1991 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1992 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1993 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1994 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1995 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1996 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1997 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1998 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1999 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
2003 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
2004 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
2005 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
2006 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
2007 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
2009 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
2010 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
2012 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
2013 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
2014 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
2015 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
2016 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
2017 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
2019 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
2020 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
2021 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
2022 case Mode.U2_CH: /* nothing */ break;
2024 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
2025 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
2026 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
2027 case Mode.I4_U4: /* nothing */ break;
2028 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
2029 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
2030 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
2032 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
2033 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
2034 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
2035 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
2036 case Mode.U4_I4: /* nothing */ break;
2037 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
2039 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
2040 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
2041 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
2042 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
2043 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
2044 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
2045 case Mode.I8_U8: /* nothing */ break;
2046 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
2048 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
2049 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
2050 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
2051 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
2052 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
2053 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
2054 case Mode.U8_I8: /* nothing */ break;
2055 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
2057 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
2058 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
2059 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
2061 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
2062 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
2063 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
2064 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
2065 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
2066 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
2067 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
2068 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
2069 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
2071 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
2072 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
2073 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
2074 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
2075 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
2076 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
2077 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
2078 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
2079 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
2080 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
2086 public class OpcodeCast : TypeCast {
2089 public OpcodeCast (Expression child, Type return_type, OpCode op)
2090 : base (child, return_type)
2095 public override Expression DoResolve (EmitContext ec)
2097 // This should never be invoked, we are born in fully
2098 // initialized state.
2103 public override void Emit (EmitContext ec)
2109 public Type UnderlyingType {
2110 get { return child.Type; }
2115 /// This kind of cast is used to encapsulate a child and cast it
2116 /// to the class requested
2118 public sealed class ClassCast : TypeCast {
2119 readonly bool forced;
2121 public ClassCast (Expression child, Type return_type)
2122 : base (child, return_type)
2126 public ClassCast (Expression child, Type return_type, bool forced)
2127 : base (child, return_type)
2129 this.forced = forced;
2132 public override void Emit (EmitContext ec)
2137 bool gen = TypeManager.IsGenericParameter (child.Type);
2139 ec.ig.Emit (OpCodes.Box, child.Type);
2141 if (type.IsGenericParameter) {
2142 ec.ig.Emit (OpCodes.Unbox_Any, type);
2150 ec.ig.Emit (OpCodes.Castclass, type);
2155 // Created during resolving pahse when an expression is wrapped or constantified
2156 // and original expression can be used later (e.g. for expression trees)
2158 public class ReducedExpression : Expression
2160 sealed class ReducedConstantExpression : EmptyConstantCast
2162 readonly Expression orig_expr;
2164 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2165 : base (expr, expr.Type)
2167 this.orig_expr = orig_expr;
2170 public override Constant ConvertImplicitly (Type target_type)
2172 Constant c = base.ConvertImplicitly (target_type);
2174 c = new ReducedConstantExpression (c, orig_expr);
2178 public override Expression CreateExpressionTree (EmitContext ec)
2180 return orig_expr.CreateExpressionTree (ec);
2183 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
2186 // Even if resolved result is a constant original expression was not
2187 // and attribute accepts constants only
2189 Attribute.Error_AttributeArgumentNotValid (orig_expr.Location);
2194 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
2196 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
2198 c = new ReducedConstantExpression (c, orig_expr);
2203 sealed class ReducedExpressionStatement : ExpressionStatement
2205 readonly Expression orig_expr;
2206 readonly ExpressionStatement stm;
2208 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
2210 this.orig_expr = orig;
2212 this.loc = orig.Location;
2215 public override Expression CreateExpressionTree (EmitContext ec)
2217 return orig_expr.CreateExpressionTree (ec);
2220 public override Expression DoResolve (EmitContext ec)
2222 eclass = stm.eclass;
2227 public override void Emit (EmitContext ec)
2232 public override void EmitStatement (EmitContext ec)
2234 stm.EmitStatement (ec);
2237 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2239 stm.MutateHoistedGenericType (storey);
2243 readonly Expression expr, orig_expr;
2245 private ReducedExpression (Expression expr, Expression orig_expr)
2248 this.orig_expr = orig_expr;
2249 this.loc = orig_expr.Location;
2252 public static Constant Create (Constant expr, Expression original_expr)
2254 return new ReducedConstantExpression (expr, original_expr);
2257 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
2259 return new ReducedExpressionStatement (s, orig);
2262 public static Expression Create (Expression expr, Expression original_expr)
2264 Constant c = expr as Constant;
2266 return Create (c, original_expr);
2268 ExpressionStatement s = expr as ExpressionStatement;
2270 return Create (s, original_expr);
2272 return new ReducedExpression (expr, original_expr);
2275 public override Expression CreateExpressionTree (EmitContext ec)
2277 return orig_expr.CreateExpressionTree (ec);
2280 public override Expression DoResolve (EmitContext ec)
2282 eclass = expr.eclass;
2287 public override void Emit (EmitContext ec)
2292 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2294 expr.EmitBranchable (ec, target, on_true);
2297 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2299 expr.MutateHoistedGenericType (storey);
2304 // Unresolved type name expressions
2306 public abstract class ATypeNameExpression : FullNamedExpression
2308 public readonly string Name;
2309 protected TypeArguments targs;
2311 protected ATypeNameExpression (string name, Location l)
2317 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2324 public bool HasTypeArguments {
2326 return targs != null;
2330 public override bool Equals (object obj)
2332 ATypeNameExpression atne = obj as ATypeNameExpression;
2333 return atne != null && atne.Name == Name &&
2334 (targs == null || targs.Equals (atne.targs));
2337 public override int GetHashCode ()
2339 return Name.GetHashCode ();
2342 public override string GetSignatureForError ()
2344 if (targs != null) {
2345 return TypeManager.RemoveGenericArity (Name) + "<" +
2346 targs.GetSignatureForError () + ">";
2354 /// SimpleName expressions are formed of a single word and only happen at the beginning
2355 /// of a dotted-name.
2357 public class SimpleName : ATypeNameExpression {
2360 public SimpleName (string name, Location l)
2365 public SimpleName (string name, TypeArguments args, Location l)
2366 : base (name, args, l)
2370 public SimpleName (string name, TypeParameter[] type_params, Location l)
2373 targs = new TypeArguments ();
2374 foreach (TypeParameter type_param in type_params)
2375 targs.Add (new TypeParameterExpr (type_param, l));
2378 public static string RemoveGenericArity (string name)
2381 StringBuilder sb = null;
2383 int pos = name.IndexOf ('`', start);
2388 sb.Append (name.Substring (start));
2393 sb = new StringBuilder ();
2394 sb.Append (name.Substring (start, pos-start));
2397 while ((pos < name.Length) && Char.IsNumber (name [pos]))
2401 } while (start < name.Length);
2403 return sb.ToString ();
2406 public SimpleName GetMethodGroup ()
2408 return new SimpleName (RemoveGenericArity (Name), targs, loc);
2411 public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
2413 if (ec.IsInFieldInitializer)
2414 Report.Error (236, l,
2415 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2418 Report.Error (120, l,
2419 "An object reference is required to access non-static member `{0}'",
2423 public bool IdenticalNameAndTypeName (EmitContext ec, Expression resolved_to, Location loc)
2425 return resolved_to != null && resolved_to.Type != null &&
2426 resolved_to.Type.Name == Name &&
2427 (ec.DeclContainer.LookupNamespaceOrType (Name, loc, /* ignore_cs0104 = */ true) != null);
2430 public override Expression DoResolve (EmitContext ec)
2432 return SimpleNameResolve (ec, null, false);
2435 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
2437 return SimpleNameResolve (ec, right_side, false);
2441 public Expression DoResolve (EmitContext ec, bool intermediate)
2443 return SimpleNameResolve (ec, null, intermediate);
2446 static bool IsNestedChild (Type t, Type parent)
2448 while (parent != null) {
2449 if (TypeManager.IsNestedChildOf (t, TypeManager.DropGenericTypeArguments (parent)))
2452 parent = parent.BaseType;
2458 FullNamedExpression ResolveNested (IResolveContext ec, Type t)
2460 if (!TypeManager.IsGenericTypeDefinition (t) && !TypeManager.IsGenericType (t))
2463 DeclSpace ds = ec.DeclContainer;
2464 while (ds != null && !IsNestedChild (t, ds.TypeBuilder))
2470 Type[] gen_params = TypeManager.GetTypeArguments (t);
2472 int arg_count = targs != null ? targs.Count : 0;
2474 for (; (ds != null) && ds.IsGeneric; ds = ds.Parent) {
2475 if (arg_count + ds.CountTypeParameters == gen_params.Length) {
2476 TypeArguments new_args = new TypeArguments ();
2477 foreach (TypeParameter param in ds.TypeParameters)
2478 new_args.Add (new TypeParameterExpr (param, loc));
2481 new_args.Add (targs);
2483 return new GenericTypeExpr (t, new_args, loc);
2490 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2492 FullNamedExpression fne = ec.GenericDeclContainer.LookupGeneric (Name, loc);
2494 return fne.ResolveAsTypeStep (ec, silent);
2496 int errors = Report.Errors;
2497 fne = ec.DeclContainer.LookupNamespaceOrType (Name, loc, /*ignore_cs0104=*/ false);
2500 if (fne.Type == null)
2503 FullNamedExpression nested = ResolveNested (ec, fne.Type);
2505 return nested.ResolveAsTypeStep (ec, false);
2507 if (targs != null) {
2508 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2509 return ct.ResolveAsTypeStep (ec, false);
2515 if (silent || errors != Report.Errors)
2518 Error_TypeOrNamespaceNotFound (ec);
2522 protected virtual void Error_TypeOrNamespaceNotFound (IResolveContext ec)
2524 MemberCore mc = ec.DeclContainer.GetDefinition (Name);
2526 Error_UnexpectedKind (ec.DeclContainer, "type", GetMemberType (mc), loc);
2530 string ns = ec.DeclContainer.NamespaceEntry.NS.Name;
2531 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2532 foreach (Assembly a in GlobalRootNamespace.Instance.Assemblies) {
2533 Type type = a.GetType (fullname);
2535 Report.SymbolRelatedToPreviousError (type);
2536 Expression.ErrorIsInaccesible (loc, TypeManager.CSharpName (type));
2541 Type t = ec.DeclContainer.LookupAnyGeneric (Name);
2543 Namespace.Error_InvalidNumberOfTypeArguments (t, loc);
2547 if (targs != null) {
2548 FullNamedExpression retval = ec.DeclContainer.LookupNamespaceOrType (SimpleName.RemoveGenericArity (Name), loc, true);
2549 if (retval != null) {
2550 Namespace.Error_TypeArgumentsCannotBeUsed (retval, loc);
2555 NamespaceEntry.Error_NamespaceNotFound (loc, Name);
2558 // TODO: I am still not convinced about this. If someone else will need it
2559 // implement this as virtual property in MemberCore hierarchy
2560 public static string GetMemberType (MemberCore mc)
2566 if (mc is FieldBase)
2568 if (mc is MethodCore)
2570 if (mc is EnumMember)
2578 Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2584 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2590 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2597 /// 7.5.2: Simple Names.
2599 /// Local Variables and Parameters are handled at
2600 /// parse time, so they never occur as SimpleNames.
2602 /// The `intermediate' flag is used by MemberAccess only
2603 /// and it is used to inform us that it is ok for us to
2604 /// avoid the static check, because MemberAccess might end
2605 /// up resolving the Name as a Type name and the access as
2606 /// a static type access.
2608 /// ie: Type Type; .... { Type.GetType (""); }
2610 /// Type is both an instance variable and a Type; Type.GetType
2611 /// is the static method not an instance method of type.
2613 Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2615 Expression e = null;
2618 // Stage 1: Performed by the parser (binding to locals or parameters).
2620 Block current_block = ec.CurrentBlock;
2621 if (current_block != null){
2622 LocalInfo vi = current_block.GetLocalInfo (Name);
2624 LocalVariableReference var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2625 if (right_side != null) {
2626 return var.ResolveLValue (ec, right_side, loc);
2628 ResolveFlags rf = ResolveFlags.VariableOrValue;
2630 rf |= ResolveFlags.DisableFlowAnalysis;
2631 return var.Resolve (ec, rf);
2635 Expression expr = current_block.Toplevel.GetParameterReference (Name, loc);
2637 if (right_side != null)
2638 return expr.ResolveLValue (ec, right_side, loc);
2640 return expr.Resolve (ec);
2645 // Stage 2: Lookup members
2648 Type almost_matched_type = null;
2649 ArrayList almost_matched = null;
2650 for (DeclSpace lookup_ds = ec.DeclContainer; lookup_ds != null; lookup_ds = lookup_ds.Parent) {
2651 // either RootDeclSpace or GenericMethod
2652 if (lookup_ds.TypeBuilder == null)
2655 e = MemberLookup (ec.ContainerType, lookup_ds.TypeBuilder, Name, loc);
2657 PropertyExpr pe = e as PropertyExpr;
2659 AParametersCollection param = TypeManager.GetParameterData (pe.PropertyInfo);
2661 // since TypeManager.MemberLookup doesn't know if we're doing a lvalue access or not,
2662 // it doesn't know which accessor to check permissions against
2663 if (param.IsEmpty && pe.IsAccessibleFrom (ec.ContainerType, right_side != null))
2665 } else if (e is EventExpr) {
2666 if (((EventExpr) e).IsAccessibleFrom (ec.ContainerType))
2668 } else if (targs != null && e is TypeExpression) {
2669 e = new GenericTypeExpr (e.Type, targs, loc).ResolveAsTypeStep (ec, false);
2677 if (almost_matched == null && almost_matched_members.Count > 0) {
2678 almost_matched_type = lookup_ds.TypeBuilder;
2679 almost_matched = (ArrayList) almost_matched_members.Clone ();
2684 if (almost_matched == null && almost_matched_members.Count > 0) {
2685 almost_matched_type = ec.ContainerType;
2686 almost_matched = (ArrayList) almost_matched_members.Clone ();
2688 e = ResolveAsTypeStep (ec, true);
2692 if (current_block != null) {
2693 IKnownVariable ikv = current_block.Explicit.GetKnownVariable (Name);
2695 LocalInfo li = ikv as LocalInfo;
2696 // Supress CS0219 warning
2700 Error_VariableIsUsedBeforeItIsDeclared (Name);
2705 if (RootContext.EvalMode){
2706 FieldInfo fi = Evaluator.LookupField (Name);
2708 return new FieldExpr (fi, loc).Resolve (ec);
2711 if (almost_matched != null)
2712 almost_matched_members = almost_matched;
2713 if (almost_matched_type == null)
2714 almost_matched_type = ec.ContainerType;
2715 return Error_MemberLookupFailed (ec.ContainerType, null, almost_matched_type, Name,
2716 ec.DeclContainer.Name, AllMemberTypes, AllBindingFlags);
2719 if (e is MemberExpr) {
2720 MemberExpr me = (MemberExpr) e;
2723 if (me.IsInstance) {
2724 if (ec.IsStatic || ec.IsInFieldInitializer) {
2726 // Note that an MemberExpr can be both IsInstance and IsStatic.
2727 // An unresolved MethodGroupExpr can contain both kinds of methods
2728 // and each predicate is true if the MethodGroupExpr contains
2729 // at least one of that kind of method.
2733 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2734 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2739 // Pass the buck to MemberAccess and Invocation.
2741 left = EmptyExpression.Null;
2743 left = ec.GetThis (loc);
2746 left = new TypeExpression (ec.ContainerType, loc);
2749 me = me.ResolveMemberAccess (ec, left, loc, null);
2753 if (targs != null) {
2754 if (!targs.Resolve (ec))
2757 me.SetTypeArguments (targs);
2760 if (!me.IsStatic && (me.InstanceExpression != null && me.InstanceExpression != EmptyExpression.Null) &&
2761 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2762 me.InstanceExpression.Type != me.DeclaringType &&
2763 !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2764 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2765 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2766 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2770 return (right_side != null)
2771 ? me.DoResolveLValue (ec, right_side)
2772 : me.DoResolve (ec);
2780 /// Represents a namespace or a type. The name of the class was inspired by
2781 /// section 10.8.1 (Fully Qualified Names).
2783 public abstract class FullNamedExpression : Expression
2785 protected override void CloneTo (CloneContext clonectx, Expression target)
2787 // Do nothing, most unresolved type expressions cannot be
2788 // resolved to different type
2791 public override Expression CreateExpressionTree (EmitContext ec)
2793 throw new NotSupportedException ("ET");
2796 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2798 throw new NotSupportedException ();
2801 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2806 public override void Emit (EmitContext ec)
2808 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2809 GetSignatureForError ());
2814 /// Expression that evaluates to a type
2816 public abstract class TypeExpr : FullNamedExpression {
2817 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2819 TypeExpr t = DoResolveAsTypeStep (ec);
2823 eclass = ExprClass.Type;
2827 override public Expression DoResolve (EmitContext ec)
2829 return ResolveAsTypeTerminal (ec, false);
2832 public virtual bool CheckAccessLevel (DeclSpace ds)
2834 return ds.CheckAccessLevel (Type);
2837 public virtual bool IsClass {
2838 get { return Type.IsClass; }
2841 public virtual bool IsValueType {
2842 get { return TypeManager.IsStruct (Type); }
2845 public virtual bool IsInterface {
2846 get { return Type.IsInterface; }
2849 public virtual bool IsSealed {
2850 get { return Type.IsSealed; }
2853 public virtual bool CanInheritFrom ()
2855 if (Type == TypeManager.enum_type ||
2856 (Type == TypeManager.value_type && RootContext.StdLib) ||
2857 Type == TypeManager.multicast_delegate_type ||
2858 Type == TypeManager.delegate_type ||
2859 Type == TypeManager.array_type)
2865 protected abstract TypeExpr DoResolveAsTypeStep (IResolveContext ec);
2867 public override bool Equals (object obj)
2869 TypeExpr tobj = obj as TypeExpr;
2873 return Type == tobj.Type;
2876 public override int GetHashCode ()
2878 return Type.GetHashCode ();
2881 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2883 type = storey.MutateType (type);
2888 /// Fully resolved Expression that already evaluated to a type
2890 public class TypeExpression : TypeExpr {
2891 public TypeExpression (Type t, Location l)
2894 eclass = ExprClass.Type;
2898 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2903 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2910 // Used to create types from a fully qualified name. These are just used
2911 // by the parser to setup the core types.
2913 public sealed class TypeLookupExpression : TypeExpr {
2914 readonly string ns_name;
2915 readonly string name;
2917 public TypeLookupExpression (string ns, string name)
2921 eclass = ExprClass.Type;
2924 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2927 // It's null only during mscorlib bootstrap when DefineType
2928 // nees to resolve base type of same type
2930 // For instance struct Char : IComparable<char>
2932 // TODO: it could be removed when Resolve starts to use
2933 // DeclSpace instead of Type
2936 Namespace ns = GlobalRootNamespace.Instance.GetNamespace (ns_name, false);
2937 FullNamedExpression fne = ns.Lookup (null, name, loc);
2945 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2950 public override string GetSignatureForError ()
2953 return TypeManager.CSharpName (ns_name + "." + name, null);
2955 return base.GetSignatureForError ();
2960 /// This class denotes an expression which evaluates to a member
2961 /// of a struct or a class.
2963 public abstract class MemberExpr : Expression
2965 protected bool is_base;
2968 /// The name of this member.
2970 public abstract string Name {
2975 // When base.member is used
2977 public bool IsBase {
2978 get { return is_base; }
2979 set { is_base = value; }
2983 /// Whether this is an instance member.
2985 public abstract bool IsInstance {
2990 /// Whether this is a static member.
2992 public abstract bool IsStatic {
2997 /// The type which declares this member.
2999 public abstract Type DeclaringType {
3004 /// The instance expression associated with this member, if it's a
3005 /// non-static member.
3007 public Expression InstanceExpression;
3009 public static void error176 (Location loc, string name)
3011 Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
3012 "with an instance reference, qualify it with a type name instead", name);
3015 public static void Error_BaseAccessInExpressionTree (Location loc)
3017 Report.Error (831, loc, "An expression tree may not contain a base access");
3020 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3022 if (InstanceExpression != null)
3023 InstanceExpression.MutateHoistedGenericType (storey);
3026 // TODO: possible optimalization
3027 // Cache resolved constant result in FieldBuilder <-> expression map
3028 public virtual MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3029 SimpleName original)
3033 // original == null || original.Resolve (...) ==> left
3036 if (left is TypeExpr) {
3037 left = left.ResolveAsBaseTerminal (ec, false);
3041 // TODO: Same problem as in class.cs, TypeTerminal does not
3042 // always do all necessary checks
3043 ObsoleteAttribute oa = AttributeTester.GetObsoleteAttribute (left.Type);
3044 if (oa != null && !ec.IsInObsoleteScope) {
3045 AttributeTester.Report_ObsoleteMessage (oa, left.GetSignatureForError (), loc);
3048 GenericTypeExpr ct = left as GenericTypeExpr;
3049 if (ct != null && !ct.CheckConstraints (ec))
3054 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3062 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3065 return ResolveExtensionMemberAccess (left);
3068 InstanceExpression = left;
3072 protected virtual MemberExpr ResolveExtensionMemberAccess (Expression left)
3074 error176 (loc, GetSignatureForError ());
3078 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3083 if (InstanceExpression == EmptyExpression.Null) {
3084 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3088 if (TypeManager.IsValueType (InstanceExpression.Type)) {
3089 if (InstanceExpression is IMemoryLocation) {
3090 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
3092 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
3093 InstanceExpression.Emit (ec);
3095 t.AddressOf (ec, AddressOp.Store);
3098 InstanceExpression.Emit (ec);
3100 if (prepare_for_load)
3101 ec.ig.Emit (OpCodes.Dup);
3104 public virtual void SetTypeArguments (TypeArguments ta)
3106 // TODO: need to get correct member type
3107 Report.Error (307, loc, "The property `{0}' cannot be used with type arguments",
3108 GetSignatureForError ());
3113 /// Represents group of extension methods
3115 public class ExtensionMethodGroupExpr : MethodGroupExpr
3117 readonly NamespaceEntry namespace_entry;
3118 public Expression ExtensionExpression;
3119 Argument extension_argument;
3121 public ExtensionMethodGroupExpr (ArrayList list, NamespaceEntry n, Type extensionType, Location l)
3122 : base (list, extensionType, l)
3124 this.namespace_entry = n;
3127 public override bool IsStatic {
3128 get { return true; }
3131 public bool IsTopLevel {
3132 get { return namespace_entry == null; }
3135 public override void EmitArguments (EmitContext ec, ArrayList arguments)
3137 if (arguments == null)
3138 arguments = new ArrayList (1);
3139 arguments.Insert (0, extension_argument);
3140 base.EmitArguments (ec, arguments);
3143 public override void EmitCall (EmitContext ec, ArrayList arguments)
3145 if (arguments == null)
3146 arguments = new ArrayList (1);
3147 arguments.Insert (0, extension_argument);
3148 base.EmitCall (ec, arguments);
3151 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3153 extension_argument.Expr.MutateHoistedGenericType (storey);
3154 base.MutateHoistedGenericType (storey);
3157 public override MethodGroupExpr OverloadResolve (EmitContext ec, ref ArrayList arguments, bool may_fail, Location loc)
3159 if (arguments == null)
3160 arguments = new ArrayList (1);
3162 arguments.Insert (0, new Argument (ExtensionExpression));
3163 MethodGroupExpr mg = ResolveOverloadExtensions (ec, arguments, namespace_entry, loc);
3165 // Store resolved argument and restore original arguments
3167 ((ExtensionMethodGroupExpr)mg).extension_argument = (Argument)arguments [0];
3168 arguments.RemoveAt (0);
3173 MethodGroupExpr ResolveOverloadExtensions (EmitContext ec, ArrayList arguments, NamespaceEntry ns, Location loc)
3175 // Use normal resolve rules
3176 MethodGroupExpr mg = base.OverloadResolve (ec, ref arguments, ns != null, loc);
3184 ExtensionMethodGroupExpr e = ns.LookupExtensionMethod (type, null, Name, loc);
3186 return base.OverloadResolve (ec, ref arguments, false, loc);
3188 e.ExtensionExpression = ExtensionExpression;
3189 e.SetTypeArguments (type_arguments);
3190 return e.ResolveOverloadExtensions (ec, arguments, e.namespace_entry, loc);
3195 /// MethodGroupExpr represents a group of method candidates which
3196 /// can be resolved to the best method overload
3198 public class MethodGroupExpr : MemberExpr
3200 public interface IErrorHandler
3202 bool AmbiguousCall (MethodBase ambiguous);
3203 bool NoExactMatch (EmitContext ec, MethodBase method);
3206 public IErrorHandler CustomErrorHandler;
3207 public MethodBase [] Methods;
3208 MethodBase best_candidate;
3209 // TODO: make private
3210 public TypeArguments type_arguments;
3211 bool identical_type_name;
3212 bool has_inaccessible_candidates_only;
3216 public MethodGroupExpr (MemberInfo [] mi, Type type, Location l)
3219 Methods = new MethodBase [mi.Length];
3220 mi.CopyTo (Methods, 0);
3223 public MethodGroupExpr (MemberInfo[] mi, Type type, Location l, bool inacessibleCandidatesOnly)
3224 : this (mi, type, l)
3226 has_inaccessible_candidates_only = inacessibleCandidatesOnly;
3229 public MethodGroupExpr (ArrayList list, Type type, Location l)
3233 Methods = (MethodBase[])list.ToArray (typeof (MethodBase));
3235 foreach (MemberInfo m in list){
3236 if (!(m is MethodBase)){
3237 Console.WriteLine ("Name " + m.Name);
3238 Console.WriteLine ("Found a: " + m.GetType ().FullName);
3247 protected MethodGroupExpr (Type type, Location loc)
3250 eclass = ExprClass.MethodGroup;
3251 this.type = typeof (MethodGroupExpr);
3252 queried_type = type;
3255 public override Type DeclaringType {
3257 return queried_type;
3261 public Type DelegateType {
3263 delegate_type = value;
3267 public bool IdenticalTypeName {
3269 return identical_type_name;
3273 public override string GetSignatureForError ()
3275 if (best_candidate != null)
3276 return TypeManager.CSharpSignature (best_candidate);
3278 return TypeManager.CSharpSignature (Methods [0]);
3281 public override string Name {
3283 return Methods [0].Name;
3287 public override bool IsInstance {
3289 if (best_candidate != null)
3290 return !best_candidate.IsStatic;
3292 foreach (MethodBase mb in Methods)
3300 public override bool IsStatic {
3302 if (best_candidate != null)
3303 return best_candidate.IsStatic;
3305 foreach (MethodBase mb in Methods)
3313 public static explicit operator ConstructorInfo (MethodGroupExpr mg)
3315 return (ConstructorInfo)mg.best_candidate;
3318 public static explicit operator MethodInfo (MethodGroupExpr mg)
3320 return (MethodInfo)mg.best_candidate;
3324 // 7.4.3.3 Better conversion from expression
3325 // Returns : 1 if a->p is better,
3326 // 2 if a->q is better,
3327 // 0 if neither is better
3329 static int BetterExpressionConversion (EmitContext ec, Argument a, Type p, Type q)
3331 Type argument_type = TypeManager.TypeToCoreType (a.Type);
3332 if (argument_type == TypeManager.anonymous_method_type && RootContext.Version > LanguageVersion.ISO_2) {
3334 // Uwrap delegate from Expression<T>
3336 if (TypeManager.DropGenericTypeArguments (p) == TypeManager.expression_type) {
3337 p = TypeManager.GetTypeArguments (p) [0];
3339 if (TypeManager.DropGenericTypeArguments (q) == TypeManager.expression_type) {
3340 q = TypeManager.GetTypeArguments (q) [0];
3343 p = Delegate.GetInvokeMethod (null, p).ReturnType;
3344 q = Delegate.GetInvokeMethod (null, q).ReturnType;
3345 if (p == TypeManager.void_type && q != TypeManager.void_type)
3347 if (q == TypeManager.void_type && p != TypeManager.void_type)
3350 if (argument_type == p)
3353 if (argument_type == q)
3357 return BetterTypeConversion (ec, p, q);
3361 // 7.4.3.4 Better conversion from type
3363 public static int BetterTypeConversion (EmitContext ec, Type p, Type q)
3365 if (p == null || q == null)
3366 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3368 if (p == TypeManager.int32_type) {
3369 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3371 } else if (p == TypeManager.int64_type) {
3372 if (q == TypeManager.uint64_type)
3374 } else if (p == TypeManager.sbyte_type) {
3375 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3376 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3378 } else if (p == TypeManager.short_type) {
3379 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3380 q == TypeManager.uint64_type)
3384 if (q == TypeManager.int32_type) {
3385 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3387 } if (q == TypeManager.int64_type) {
3388 if (p == TypeManager.uint64_type)
3390 } else if (q == TypeManager.sbyte_type) {
3391 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3392 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3394 } if (q == TypeManager.short_type) {
3395 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3396 p == TypeManager.uint64_type)
3400 // TODO: this is expensive
3401 Expression p_tmp = new EmptyExpression (p);
3402 Expression q_tmp = new EmptyExpression (q);
3404 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3405 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3407 if (p_to_q && !q_to_p)
3410 if (q_to_p && !p_to_q)
3417 /// Determines "Better function" between candidate
3418 /// and the current best match
3421 /// Returns a boolean indicating :
3422 /// false if candidate ain't better
3423 /// true if candidate is better than the current best match
3425 static bool BetterFunction (EmitContext ec, ArrayList args, int argument_count,
3426 MethodBase candidate, bool candidate_params,
3427 MethodBase best, bool best_params)
3429 AParametersCollection candidate_pd = TypeManager.GetParameterData (candidate);
3430 AParametersCollection best_pd = TypeManager.GetParameterData (best);
3432 bool better_at_least_one = false;
3434 for (int j = 0, c_idx = 0, b_idx = 0; j < argument_count; ++j, ++c_idx, ++b_idx)
3436 Argument a = (Argument) args [j];
3438 Type ct = candidate_pd.Types [c_idx];
3439 Type bt = best_pd.Types [b_idx];
3441 if (candidate_params && candidate_pd.FixedParameters [c_idx].ModFlags == Parameter.Modifier.PARAMS)
3443 ct = TypeManager.GetElementType (ct);
3447 if (best_params && best_pd.FixedParameters [b_idx].ModFlags == Parameter.Modifier.PARAMS)
3449 bt = TypeManager.GetElementType (bt);
3457 int result = BetterExpressionConversion (ec, a, ct, bt);
3459 // for each argument, the conversion to 'ct' should be no worse than
3460 // the conversion to 'bt'.
3464 // for at least one argument, the conversion to 'ct' should be better than
3465 // the conversion to 'bt'.
3467 better_at_least_one = true;
3470 if (better_at_least_one)
3474 // This handles the case
3476 // Add (float f1, float f2, float f3);
3477 // Add (params decimal [] foo);
3479 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3480 // first candidate would've chosen as better.
3486 // The two methods have equal parameter types. Now apply tie-breaking rules
3488 if (TypeManager.IsGenericMethod (best)) {
3489 if (!TypeManager.IsGenericMethod (candidate))
3491 } else if (TypeManager.IsGenericMethod (candidate)) {
3496 // This handles the following cases:
3498 // Trim () is better than Trim (params char[] chars)
3499 // Concat (string s1, string s2, string s3) is better than
3500 // Concat (string s1, params string [] srest)
3501 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3503 if (!candidate_params && best_params)
3505 if (candidate_params && !best_params)
3508 int candidate_param_count = candidate_pd.Count;
3509 int best_param_count = best_pd.Count;
3511 if (candidate_param_count != best_param_count)
3512 // can only happen if (candidate_params && best_params)
3513 return candidate_param_count > best_param_count;
3516 // now, both methods have the same number of parameters, and the parameters have the same types
3517 // Pick the "more specific" signature
3520 MethodBase orig_candidate = TypeManager.DropGenericMethodArguments (candidate);
3521 MethodBase orig_best = TypeManager.DropGenericMethodArguments (best);
3523 AParametersCollection orig_candidate_pd = TypeManager.GetParameterData (orig_candidate);
3524 AParametersCollection orig_best_pd = TypeManager.GetParameterData (orig_best);
3526 bool specific_at_least_once = false;
3527 for (int j = 0; j < candidate_param_count; ++j)
3529 Type ct = orig_candidate_pd.Types [j];
3530 Type bt = orig_best_pd.Types [j];
3533 Type specific = MoreSpecific (ct, bt);
3537 specific_at_least_once = true;
3540 if (specific_at_least_once)
3543 // FIXME: handle lifted operators
3549 protected override MemberExpr ResolveExtensionMemberAccess (Expression left)
3552 return base.ResolveExtensionMemberAccess (left);
3555 // When left side is an expression and at least one candidate method is
3556 // static, it can be extension method
3558 InstanceExpression = left;
3562 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3563 SimpleName original)
3565 if (!(left is TypeExpr) &&
3566 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3567 identical_type_name = true;
3569 return base.ResolveMemberAccess (ec, left, loc, original);
3572 public override Expression CreateExpressionTree (EmitContext ec)
3574 if (best_candidate == null) {
3575 Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3579 if (best_candidate.IsConstructor)
3580 return new TypeOfConstructorInfo (best_candidate, loc);
3582 IMethodData md = TypeManager.GetMethod (best_candidate);
3583 if (md != null && md.IsExcluded ())
3584 Report.Error (765, loc,
3585 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3587 return new TypeOfMethodInfo (best_candidate, loc);
3590 override public Expression DoResolve (EmitContext ec)
3592 if (InstanceExpression != null) {
3593 InstanceExpression = InstanceExpression.DoResolve (ec);
3594 if (InstanceExpression == null)
3601 public void ReportUsageError ()
3603 Report.Error (654, loc, "Method `" + DeclaringType + "." +
3604 Name + "()' is referenced without parentheses");
3607 override public void Emit (EmitContext ec)
3609 ReportUsageError ();
3612 public virtual void EmitArguments (EmitContext ec, ArrayList arguments)
3614 Invocation.EmitArguments (ec, arguments, false, null);
3617 public virtual void EmitCall (EmitContext ec, ArrayList arguments)
3619 Invocation.EmitCall (ec, IsBase, InstanceExpression, best_candidate, arguments, loc);
3622 void Error_AmbiguousCall (MethodBase ambiguous)
3624 if (CustomErrorHandler != null && CustomErrorHandler.AmbiguousCall (ambiguous))
3627 Report.SymbolRelatedToPreviousError (best_candidate);
3628 Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
3629 TypeManager.CSharpSignature (ambiguous), TypeManager.CSharpSignature (best_candidate));
3632 protected virtual void Error_InvalidArguments (EmitContext ec, Location loc, int idx, MethodBase method,
3633 Argument a, AParametersCollection expected_par, Type paramType)
3635 ExtensionMethodGroupExpr emg = this as ExtensionMethodGroupExpr;
3637 if (a is CollectionElementInitializer.ElementInitializerArgument) {
3638 Report.SymbolRelatedToPreviousError (method);
3639 if ((expected_par.FixedParameters [idx].ModFlags & Parameter.Modifier.ISBYREF) != 0) {
3640 Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
3641 TypeManager.CSharpSignature (method));
3644 Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
3645 TypeManager.CSharpSignature (method));
3646 } else if (TypeManager.IsDelegateType (method.DeclaringType)) {
3647 Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
3648 TypeManager.CSharpName (method.DeclaringType));
3650 Report.SymbolRelatedToPreviousError (method);
3652 Report.Error (1928, loc,
3653 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3654 emg.ExtensionExpression.GetSignatureForError (),
3655 emg.Name, TypeManager.CSharpSignature (method));
3657 Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
3658 TypeManager.CSharpSignature (method));
3662 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters [idx].ModFlags;
3664 string index = (idx + 1).ToString ();
3665 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
3666 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
3667 if ((mod & Parameter.Modifier.ISBYREF) == 0)
3668 Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
3669 index, Parameter.GetModifierSignature (a.Modifier));
3671 Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
3672 index, Parameter.GetModifierSignature (mod));
3674 string p1 = a.GetSignatureForError ();
3675 string p2 = TypeManager.CSharpName (paramType);
3678 Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
3679 Report.SymbolRelatedToPreviousError (a.Expr.Type);
3680 Report.SymbolRelatedToPreviousError (paramType);
3683 if (idx == 0 && emg != null) {
3684 Report.Error (1929, loc,
3685 "Extension method instance type `{0}' cannot be converted to `{1}'", p1, p2);
3687 Report.Error (1503, loc,
3688 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
3693 public override void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl)
3695 Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3696 Name, TypeManager.CSharpName (target));
3699 void Error_ArgumentCountWrong (int arg_count)
3701 Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
3702 Name, arg_count.ToString ());
3705 protected virtual int GetApplicableParametersCount (MethodBase method, AParametersCollection parameters)
3707 return parameters.Count;
3710 public static bool IsAncestralType (Type first_type, Type second_type)
3712 return first_type != second_type &&
3713 (TypeManager.IsSubclassOf (second_type, first_type) ||
3714 TypeManager.ImplementsInterface (second_type, first_type));
3718 /// Determines if the candidate method is applicable (section 14.4.2.1)
3719 /// to the given set of arguments
3720 /// A return value rates candidate method compatibility,
3721 /// 0 = the best, int.MaxValue = the worst
3723 public int IsApplicable (EmitContext ec,
3724 ArrayList arguments, int arg_count, ref MethodBase method, ref bool params_expanded_form)
3726 MethodBase candidate = method;
3728 AParametersCollection pd = TypeManager.GetParameterData (candidate);
3729 int param_count = GetApplicableParametersCount (candidate, pd);
3731 if (arg_count != param_count) {
3733 return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
3734 if (arg_count < param_count - 1)
3735 return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
3737 // Initialize expanded form of a method with 1 params parameter
3738 params_expanded_form = param_count == 1 && pd.HasParams;
3743 // 1. Handle generic method using type arguments when specified or type inference
3745 if (TypeManager.IsGenericMethod (candidate)) {
3746 if (type_arguments != null) {
3747 Type [] g_args = candidate.GetGenericArguments ();
3748 if (g_args.Length != type_arguments.Count)
3749 return int.MaxValue - 20000 + Math.Abs (type_arguments.Count - g_args.Length);
3751 // TODO: Don't create new method, create Parameters only
3752 method = ((MethodInfo) candidate).MakeGenericMethod (type_arguments.Arguments);
3754 pd = TypeManager.GetParameterData (candidate);
3756 int score = TypeManager.InferTypeArguments (ec, arguments, ref candidate);
3758 return score - 20000;
3760 if (TypeManager.IsGenericMethodDefinition (candidate))
3761 throw new InternalErrorException ("A generic method `{0}' definition took part in overload resolution",
3762 TypeManager.CSharpSignature (candidate));
3764 pd = TypeManager.GetParameterData (candidate);
3767 if (type_arguments != null)
3768 return int.MaxValue - 15000;
3773 // 2. Each argument has to be implicitly convertible to method parameter
3776 Parameter.Modifier p_mod = 0;
3778 for (int i = 0; i < arg_count; i++) {
3779 Argument a = (Argument) arguments [i];
3780 Parameter.Modifier a_mod = a.Modifier &
3781 ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3783 if (p_mod != Parameter.Modifier.PARAMS) {
3784 p_mod = pd.FixedParameters [i].ModFlags & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3786 if (p_mod == Parameter.Modifier.ARGLIST) {
3787 if (a.Type == typeof (ArglistAccess))
3795 params_expanded_form = true;
3799 if (!params_expanded_form)
3800 score = IsArgumentCompatible (ec, a_mod, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
3802 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && delegate_type == null) {
3803 // It can be applicable in expanded form
3804 score = IsArgumentCompatible (ec, a_mod, a, 0, TypeManager.GetElementType (pt));
3806 params_expanded_form = true;
3810 if (params_expanded_form)
3812 return (arg_count - i) * 2 + score;
3816 if (arg_count != param_count)
3817 params_expanded_form = true;
3822 int IsArgumentCompatible (EmitContext ec, Parameter.Modifier arg_mod, Argument argument, Parameter.Modifier param_mod, Type parameter)
3825 // Types have to be identical when ref or out modifer is used
3827 if (arg_mod != 0 || param_mod != 0) {
3828 if (TypeManager.HasElementType (parameter))
3829 parameter = TypeManager.GetElementType (parameter);
3831 Type a_type = argument.Type;
3832 if (TypeManager.HasElementType (a_type))
3833 a_type = TypeManager.GetElementType (a_type);
3835 if (a_type != parameter)
3838 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter))
3842 if (arg_mod != param_mod)
3848 public static bool IsOverride (MethodBase cand_method, MethodBase base_method)
3850 if (!IsAncestralType (base_method.DeclaringType, cand_method.DeclaringType))
3853 AParametersCollection cand_pd = TypeManager.GetParameterData (cand_method);
3854 AParametersCollection base_pd = TypeManager.GetParameterData (base_method);
3856 if (cand_pd.Count != base_pd.Count)
3859 for (int j = 0; j < cand_pd.Count; ++j)
3861 Parameter.Modifier cm = cand_pd.FixedParameters [j].ModFlags;
3862 Parameter.Modifier bm = base_pd.FixedParameters [j].ModFlags;
3863 Type ct = cand_pd.Types [j];
3864 Type bt = base_pd.Types [j];
3866 if (cm != bm || ct != bt)
3873 public static MethodGroupExpr MakeUnionSet (MethodGroupExpr mg1, MethodGroupExpr mg2, Location loc)
3884 ArrayList all = new ArrayList (mg1.Methods);
3885 foreach (MethodBase m in mg2.Methods){
3886 if (!TypeManager.ArrayContainsMethod (mg1.Methods, m, false))
3890 return new MethodGroupExpr (all, null, loc);
3893 static Type MoreSpecific (Type p, Type q)
3895 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
3897 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
3900 if (TypeManager.HasElementType (p))
3902 Type pe = TypeManager.GetElementType (p);
3903 Type qe = TypeManager.GetElementType (q);
3904 Type specific = MoreSpecific (pe, qe);
3910 else if (TypeManager.IsGenericType (p))
3912 Type[] pargs = TypeManager.GetTypeArguments (p);
3913 Type[] qargs = TypeManager.GetTypeArguments (q);
3915 bool p_specific_at_least_once = false;
3916 bool q_specific_at_least_once = false;
3918 for (int i = 0; i < pargs.Length; i++)
3920 Type specific = MoreSpecific (pargs [i], qargs [i]);
3921 if (specific == pargs [i])
3922 p_specific_at_least_once = true;
3923 if (specific == qargs [i])
3924 q_specific_at_least_once = true;
3927 if (p_specific_at_least_once && !q_specific_at_least_once)
3929 if (!p_specific_at_least_once && q_specific_at_least_once)
3936 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3938 base.MutateHoistedGenericType (storey);
3940 MethodInfo mi = best_candidate as MethodInfo;
3942 best_candidate = storey.MutateGenericMethod (mi);
3946 best_candidate = storey.MutateConstructor ((ConstructorInfo) this);
3950 /// Find the Applicable Function Members (7.4.2.1)
3952 /// me: Method Group expression with the members to select.
3953 /// it might contain constructors or methods (or anything
3954 /// that maps to a method).
3956 /// Arguments: ArrayList containing resolved Argument objects.
3958 /// loc: The location if we want an error to be reported, or a Null
3959 /// location for "probing" purposes.
3961 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3962 /// that is the best match of me on Arguments.
3965 public virtual MethodGroupExpr OverloadResolve (EmitContext ec, ref ArrayList Arguments,
3966 bool may_fail, Location loc)
3968 bool method_params = false;
3969 Type applicable_type = null;
3971 ArrayList candidates = new ArrayList (2);
3972 ArrayList candidate_overrides = null;
3975 // Used to keep a map between the candidate
3976 // and whether it is being considered in its
3977 // normal or expanded form
3979 // false is normal form, true is expanded form
3981 Hashtable candidate_to_form = null;
3983 if (Arguments != null)
3984 arg_count = Arguments.Count;
3986 if (RootContext.Version == LanguageVersion.ISO_1 && Name == "Invoke" && TypeManager.IsDelegateType (DeclaringType)) {
3988 Report.Error (1533, loc, "Invoke cannot be called directly on a delegate");
3992 int nmethods = Methods.Length;
3996 // Methods marked 'override' don't take part in 'applicable_type'
3997 // computation, nor in the actual overload resolution.
3998 // However, they still need to be emitted instead of a base virtual method.
3999 // So, we salt them away into the 'candidate_overrides' array.
4001 // In case of reflected methods, we replace each overriding method with
4002 // its corresponding base virtual method. This is to improve compatibility
4003 // with non-C# libraries which change the visibility of overrides (#75636)
4006 for (int i = 0; i < Methods.Length; ++i) {
4007 MethodBase m = Methods [i];
4008 if (TypeManager.IsOverride (m)) {
4009 if (candidate_overrides == null)
4010 candidate_overrides = new ArrayList ();
4011 candidate_overrides.Add (m);
4012 m = TypeManager.TryGetBaseDefinition (m);
4021 // Enable message recording, it's used mainly by lambda expressions
4023 Report.IMessageRecorder msg_recorder = new Report.MessageRecorder ();
4024 Report.IMessageRecorder prev_recorder = Report.SetMessageRecorder (msg_recorder);
4027 // First we construct the set of applicable methods
4029 bool is_sorted = true;
4030 int best_candidate_rate = int.MaxValue;
4031 for (int i = 0; i < nmethods; i++) {
4032 Type decl_type = Methods [i].DeclaringType;
4035 // If we have already found an applicable method
4036 // we eliminate all base types (Section 14.5.5.1)
4038 if (applicable_type != null && IsAncestralType (decl_type, applicable_type))
4042 // Check if candidate is applicable (section 14.4.2.1)
4044 bool params_expanded_form = false;
4045 int candidate_rate = IsApplicable (ec, Arguments, arg_count, ref Methods [i], ref params_expanded_form);
4047 if (candidate_rate < best_candidate_rate) {
4048 best_candidate_rate = candidate_rate;
4049 best_candidate = Methods [i];
4052 if (params_expanded_form) {
4053 if (candidate_to_form == null)
4054 candidate_to_form = new PtrHashtable ();
4055 MethodBase candidate = Methods [i];
4056 candidate_to_form [candidate] = candidate;
4059 if (candidate_rate != 0 || has_inaccessible_candidates_only) {
4060 if (msg_recorder != null)
4061 msg_recorder.EndSession ();
4065 msg_recorder = null;
4066 candidates.Add (Methods [i]);
4068 if (applicable_type == null)
4069 applicable_type = decl_type;
4070 else if (applicable_type != decl_type) {
4072 if (IsAncestralType (applicable_type, decl_type))
4073 applicable_type = decl_type;
4077 Report.SetMessageRecorder (prev_recorder);
4078 if (msg_recorder != null && !msg_recorder.IsEmpty) {
4080 msg_recorder.PrintMessages ();
4085 int candidate_top = candidates.Count;
4087 if (applicable_type == null) {
4089 // When we found a top level method which does not match and it's
4090 // not an extension method. We start extension methods lookup from here
4092 if (InstanceExpression != null) {
4093 ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (type, Name, loc);
4094 if (ex_method_lookup != null) {
4095 ex_method_lookup.ExtensionExpression = InstanceExpression;
4096 ex_method_lookup.SetTypeArguments (type_arguments);
4097 return ex_method_lookup.OverloadResolve (ec, ref Arguments, may_fail, loc);
4105 // Okay so we have failed to find exact match so we
4106 // return error info about the closest match
4108 if (best_candidate != null) {
4109 if (CustomErrorHandler != null && CustomErrorHandler.NoExactMatch (ec, best_candidate))
4112 AParametersCollection pd = TypeManager.GetParameterData (best_candidate);
4113 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4114 if (arg_count == pd.Count || pd.HasParams) {
4115 if (TypeManager.IsGenericMethodDefinition (best_candidate)) {
4116 if (type_arguments == null) {
4117 Report.Error (411, loc,
4118 "The type arguments for method `{0}' cannot be inferred from " +
4119 "the usage. Try specifying the type arguments explicitly",
4120 TypeManager.CSharpSignature (best_candidate));
4124 Type[] g_args = TypeManager.GetGenericArguments (best_candidate);
4125 if (type_arguments.Count != g_args.Length) {
4126 Report.SymbolRelatedToPreviousError (best_candidate);
4127 Report.Error (305, loc, "Using the generic method `{0}' requires `{1}' type argument(s)",
4128 TypeManager.CSharpSignature (best_candidate),
4129 g_args.Length.ToString ());
4133 if (type_arguments != null && !TypeManager.IsGenericMethod (best_candidate)) {
4134 Namespace.Error_TypeArgumentsCannotBeUsed (best_candidate, loc);
4139 if (has_inaccessible_candidates_only) {
4140 if (InstanceExpression != null && type != ec.ContainerType && TypeManager.IsNestedFamilyAccessible (ec.ContainerType, best_candidate.DeclaringType)) {
4141 // Although a derived class can access protected members of
4142 // its base class it cannot do so through an instance of the
4143 // base class (CS1540). If the qualifier_type is a base of the
4144 // ec.ContainerType and the lookup succeeds with the latter one,
4145 // then we are in this situation.
4146 Error_CannotAccessProtected (loc, best_candidate, queried_type, ec.ContainerType);
4148 Report.SymbolRelatedToPreviousError (best_candidate);
4149 ErrorIsInaccesible (loc, GetSignatureForError ());
4153 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate, cand_params, may_fail, loc))
4156 if (has_inaccessible_candidates_only)
4159 throw new InternalErrorException ("VerifyArgumentsCompat didn't find any problem with rejected candidate " + best_candidate);
4164 // We failed to find any method with correct argument count
4166 if (Name == ConstructorInfo.ConstructorName) {
4167 Report.SymbolRelatedToPreviousError (queried_type);
4168 Report.Error (1729, loc,
4169 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4170 TypeManager.CSharpName (queried_type), arg_count);
4172 Error_ArgumentCountWrong (arg_count);
4180 // At this point, applicable_type is _one_ of the most derived types
4181 // in the set of types containing the methods in this MethodGroup.
4182 // Filter the candidates so that they only contain methods from the
4183 // most derived types.
4186 int finalized = 0; // Number of finalized candidates
4189 // Invariant: applicable_type is a most derived type
4191 // We'll try to complete Section 14.5.5.1 for 'applicable_type' by
4192 // eliminating all it's base types. At the same time, we'll also move
4193 // every unrelated type to the end of the array, and pick the next
4194 // 'applicable_type'.
4196 Type next_applicable_type = null;
4197 int j = finalized; // where to put the next finalized candidate
4198 int k = finalized; // where to put the next undiscarded candidate
4199 for (int i = finalized; i < candidate_top; ++i) {
4200 MethodBase candidate = (MethodBase) candidates [i];
4201 Type decl_type = candidate.DeclaringType;
4203 if (decl_type == applicable_type) {
4204 candidates [k++] = candidates [j];
4205 candidates [j++] = candidates [i];
4209 if (IsAncestralType (decl_type, applicable_type))
4212 if (next_applicable_type != null &&
4213 IsAncestralType (decl_type, next_applicable_type))
4216 candidates [k++] = candidates [i];
4218 if (next_applicable_type == null ||
4219 IsAncestralType (next_applicable_type, decl_type))
4220 next_applicable_type = decl_type;
4223 applicable_type = next_applicable_type;
4226 } while (applicable_type != null);
4230 // Now we actually find the best method
4233 best_candidate = (MethodBase) candidates [0];
4234 method_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4236 for (int ix = 1; ix < candidate_top; ix++) {
4237 MethodBase candidate = (MethodBase) candidates [ix];
4239 if (candidate == best_candidate)
4242 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4244 if (BetterFunction (ec, Arguments, arg_count,
4245 candidate, cand_params,
4246 best_candidate, method_params)) {
4247 best_candidate = candidate;
4248 method_params = cand_params;
4252 // Now check that there are no ambiguities i.e the selected method
4253 // should be better than all the others
4255 MethodBase ambiguous = null;
4256 for (int ix = 1; ix < candidate_top; ix++) {
4257 MethodBase candidate = (MethodBase) candidates [ix];
4259 if (candidate == best_candidate)
4262 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4263 if (!BetterFunction (ec, Arguments, arg_count,
4264 best_candidate, method_params,
4265 candidate, cand_params))
4268 Report.SymbolRelatedToPreviousError (candidate);
4269 ambiguous = candidate;
4273 if (ambiguous != null) {
4274 Error_AmbiguousCall (ambiguous);
4279 // If the method is a virtual function, pick an override closer to the LHS type.
4281 if (!IsBase && best_candidate.IsVirtual) {
4282 if (TypeManager.IsOverride (best_candidate))
4283 throw new InternalErrorException (
4284 "Should not happen. An 'override' method took part in overload resolution: " + best_candidate);
4286 if (candidate_overrides != null) {
4287 Type[] gen_args = null;
4288 bool gen_override = false;
4289 if (TypeManager.IsGenericMethod (best_candidate))
4290 gen_args = TypeManager.GetGenericArguments (best_candidate);
4292 foreach (MethodBase candidate in candidate_overrides) {
4293 if (TypeManager.IsGenericMethod (candidate)) {
4294 if (gen_args == null)
4297 if (gen_args.Length != TypeManager.GetGenericArguments (candidate).Length)
4300 if (gen_args != null)
4304 if (IsOverride (candidate, best_candidate)) {
4305 gen_override = true;
4306 best_candidate = candidate;
4310 if (gen_override && gen_args != null) {
4312 best_candidate = ((MethodInfo) best_candidate).MakeGenericMethod (gen_args);
4319 // And now check if the arguments are all
4320 // compatible, perform conversions if
4321 // necessary etc. and return if everything is
4324 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate,
4325 method_params, may_fail, loc))
4328 if (best_candidate == null)
4331 MethodBase the_method = TypeManager.DropGenericMethodArguments (best_candidate);
4332 if (TypeManager.IsGenericMethodDefinition (the_method) &&
4333 !ConstraintChecker.CheckConstraints (ec, the_method, best_candidate, loc))
4337 // Check ObsoleteAttribute on the best method
4339 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (the_method);
4340 if (oa != null && !ec.IsInObsoleteScope)
4341 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc);
4343 IMethodData data = TypeManager.GetMethod (the_method);
4345 data.SetMemberIsUsed ();
4350 public override void SetTypeArguments (TypeArguments ta)
4352 type_arguments = ta;
4355 public bool VerifyArgumentsCompat (EmitContext ec, ref ArrayList arguments,
4356 int arg_count, MethodBase method,
4357 bool chose_params_expanded,
4358 bool may_fail, Location loc)
4360 AParametersCollection pd = TypeManager.GetParameterData (method);
4362 int errors = Report.Errors;
4363 Parameter.Modifier p_mod = 0;
4365 int a_idx = 0, a_pos = 0;
4367 ArrayList params_initializers = null;
4368 bool has_unsafe_arg = false;
4370 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4371 a = (Argument) arguments [a_idx];
4372 if (p_mod != Parameter.Modifier.PARAMS) {
4373 p_mod = pd.FixedParameters [a_idx].ModFlags;
4374 pt = pd.Types [a_idx];
4375 has_unsafe_arg |= pt.IsPointer;
4377 if (p_mod == Parameter.Modifier.ARGLIST) {
4378 if (a.Type != typeof (ArglistAccess))
4383 if (p_mod == Parameter.Modifier.PARAMS) {
4384 if (chose_params_expanded) {
4385 params_initializers = new ArrayList (arg_count - a_idx);
4386 pt = TypeManager.GetElementType (pt);
4392 // Types have to be identical when ref or out modifer is used
4394 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4395 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4398 if (!TypeManager.IsEqual (a.Expr.Type, pt))
4404 if (delegate_type != null && !Delegate.IsTypeCovariant (a.Expr, pt))
4407 Expression conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4412 // Convert params arguments to an array initializer
4414 if (params_initializers != null) {
4415 // we choose to use 'a.Expr' rather than 'conv' so that
4416 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
4417 params_initializers.Add (a.Expr);
4418 arguments.RemoveAt (a_idx--);
4423 // Update the argument with the implicit conversion
4427 if (a_idx != arg_count) {
4428 if (!may_fail && Report.Errors == errors) {
4429 if (CustomErrorHandler != null)
4430 CustomErrorHandler.NoExactMatch (ec, best_candidate);
4432 Error_InvalidArguments (ec, loc, a_pos, method, a, pd, pt);
4438 // Fill not provided arguments required by params modifier
4440 int param_count = GetApplicableParametersCount (method, pd);
4441 if (params_initializers == null && pd.HasParams && arg_count + 1 == param_count) {
4442 if (arguments == null)
4443 arguments = new ArrayList (1);
4445 pt = pd.Types [param_count - 1];
4446 pt = TypeManager.GetElementType (pt);
4447 has_unsafe_arg |= pt.IsPointer;
4448 params_initializers = new ArrayList (0);
4452 // Append an array argument with all params arguments
4454 if (params_initializers != null) {
4455 arguments.Add (new Argument (
4456 new ArrayCreation (new TypeExpression (pt, loc), "[]",
4457 params_initializers, loc).Resolve (ec)));
4461 if (arg_count < param_count) {
4463 Error_ArgumentCountWrong (arg_count);
4467 if (has_unsafe_arg && !ec.InUnsafe) {
4477 public class ConstantExpr : MemberExpr
4481 public ConstantExpr (FieldInfo constant, Location loc)
4483 this.constant = constant;
4487 public override string Name {
4488 get { throw new NotImplementedException (); }
4491 public override bool IsInstance {
4492 get { return !IsStatic; }
4495 public override bool IsStatic {
4496 get { return constant.IsStatic; }
4499 public override Type DeclaringType {
4500 get { return constant.DeclaringType; }
4503 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc, SimpleName original)
4505 constant = TypeManager.GetGenericFieldDefinition (constant);
4507 IConstant ic = TypeManager.GetConstant (constant);
4509 if (constant.IsLiteral) {
4510 ic = new ExternalConstant (constant);
4512 ic = ExternalConstant.CreateDecimal (constant);
4513 // HACK: decimal field was not resolved as constant
4515 return new FieldExpr (constant, loc).ResolveMemberAccess (ec, left, loc, original);
4517 TypeManager.RegisterConstant (constant, ic);
4520 return base.ResolveMemberAccess (ec, left, loc, original);
4523 public override Expression CreateExpressionTree (EmitContext ec)
4525 throw new NotSupportedException ("ET");
4528 public override Expression DoResolve (EmitContext ec)
4530 IConstant ic = TypeManager.GetConstant (constant);
4531 if (ic.ResolveValue ()) {
4532 if (!ec.IsInObsoleteScope)
4533 ic.CheckObsoleteness (loc);
4536 return ic.CreateConstantReference (loc);
4539 public override void Emit (EmitContext ec)
4541 throw new NotSupportedException ();
4544 public override string GetSignatureForError ()
4546 return TypeManager.GetFullNameSignature (constant);
4551 /// Fully resolved expression that evaluates to a Field
4553 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariableReference {
4554 public FieldInfo FieldInfo;
4555 readonly Type constructed_generic_type;
4556 VariableInfo variable_info;
4558 LocalTemporary temp;
4561 protected FieldExpr (Location l)
4566 public FieldExpr (FieldInfo fi, Location l)
4569 type = TypeManager.TypeToCoreType (fi.FieldType);
4573 public FieldExpr (FieldInfo fi, Type genericType, Location l)
4576 if (TypeManager.IsGenericTypeDefinition (genericType))
4578 this.constructed_generic_type = genericType;
4581 public override string Name {
4583 return FieldInfo.Name;
4587 public override bool IsInstance {
4589 return !FieldInfo.IsStatic;
4593 public override bool IsStatic {
4595 return FieldInfo.IsStatic;
4599 public override Type DeclaringType {
4601 return FieldInfo.DeclaringType;
4605 public override string GetSignatureForError ()
4607 return TypeManager.GetFullNameSignature (FieldInfo);
4610 public VariableInfo VariableInfo {
4612 return variable_info;
4616 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
4617 SimpleName original)
4619 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
4620 Type t = fi.FieldType;
4622 if (t.IsPointer && !ec.InUnsafe) {
4626 return base.ResolveMemberAccess (ec, left, loc, original);
4629 public void SetHasAddressTaken ()
4631 IVariableReference vr = InstanceExpression as IVariableReference;
4633 vr.SetHasAddressTaken ();
4636 public override Expression CreateExpressionTree (EmitContext ec)
4638 Expression instance;
4639 if (InstanceExpression == null) {
4640 instance = new NullLiteral (loc);
4642 instance = InstanceExpression.CreateExpressionTree (ec);
4645 ArrayList args = new ArrayList (2);
4646 args.Add (new Argument (instance));
4647 args.Add (new Argument (CreateTypeOfExpression ()));
4648 return CreateExpressionFactoryCall ("Field", args);
4651 public Expression CreateTypeOfExpression ()
4653 return new TypeOfField (GetConstructedFieldInfo (), loc);
4656 override public Expression DoResolve (EmitContext ec)
4658 return DoResolve (ec, false, false);
4661 Expression DoResolve (EmitContext ec, bool lvalue_instance, bool out_access)
4663 if (!FieldInfo.IsStatic){
4664 if (InstanceExpression == null){
4666 // This can happen when referencing an instance field using
4667 // a fully qualified type expression: TypeName.InstanceField = xxx
4669 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4673 // Resolve the field's instance expression while flow analysis is turned
4674 // off: when accessing a field "a.b", we must check whether the field
4675 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4677 if (lvalue_instance) {
4678 using (ec.With (EmitContext.Flags.DoFlowAnalysis, false)) {
4679 Expression right_side =
4680 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4682 if (InstanceExpression != EmptyExpression.Null)
4683 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side, loc);
4686 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
4688 if (InstanceExpression != EmptyExpression.Null)
4689 InstanceExpression = InstanceExpression.Resolve (ec, rf);
4692 if (InstanceExpression == null)
4695 using (ec.Set (EmitContext.Flags.OmitStructFlowAnalysis)) {
4696 InstanceExpression.CheckMarshalByRefAccess (ec);
4700 // TODO: the code above uses some non-standard multi-resolve rules
4701 if (eclass != ExprClass.Invalid)
4704 if (!ec.IsInObsoleteScope) {
4705 FieldBase f = TypeManager.GetField (FieldInfo);
4707 f.CheckObsoleteness (loc);
4709 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
4711 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
4715 IFixedBuffer fb = AttributeTester.GetFixedBuffer (FieldInfo);
4716 IVariableReference var = InstanceExpression as IVariableReference;
4719 IFixedExpression fe = InstanceExpression as IFixedExpression;
4720 if (!ec.InFixedInitializer && (fe == null || !fe.IsFixed)) {
4721 Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4724 if (InstanceExpression.eclass != ExprClass.Variable) {
4725 Report.SymbolRelatedToPreviousError (FieldInfo);
4726 Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4727 TypeManager.GetFullNameSignature (FieldInfo));
4728 } else if (var != null && var.IsHoisted) {
4729 AnonymousMethodExpression.Error_AddressOfCapturedVar (var, loc);
4732 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4735 eclass = ExprClass.Variable;
4737 // If the instance expression is a local variable or parameter.
4738 if (var == null || var.VariableInfo == null)
4741 VariableInfo vi = var.VariableInfo;
4742 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
4745 variable_info = vi.GetSubStruct (FieldInfo.Name);
4746 eclass = ExprClass.Variable;
4750 static readonly int [] codes = {
4751 191, // instance, write access
4752 192, // instance, out access
4753 198, // static, write access
4754 199, // static, out access
4755 1648, // member of value instance, write access
4756 1649, // member of value instance, out access
4757 1650, // member of value static, write access
4758 1651 // member of value static, out access
4761 static readonly string [] msgs = {
4762 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4763 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4764 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4765 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4766 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4767 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4768 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4769 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4772 // The return value is always null. Returning a value simplifies calling code.
4773 Expression Report_AssignToReadonly (Expression right_side)
4776 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4780 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4782 Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4787 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4789 IVariableReference var = InstanceExpression as IVariableReference;
4790 if (var != null && var.VariableInfo != null)
4791 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
4793 bool lvalue_instance = !FieldInfo.IsStatic && TypeManager.IsValueType (FieldInfo.DeclaringType);
4794 bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
4796 Expression e = DoResolve (ec, lvalue_instance, out_access);
4801 FieldBase fb = TypeManager.GetField (FieldInfo);
4805 if (FieldInfo.IsInitOnly) {
4806 // InitOnly fields can only be assigned in constructors or initializers
4807 if (!ec.IsInFieldInitializer && !ec.IsConstructor)
4808 return Report_AssignToReadonly (right_side);
4810 if (ec.IsConstructor) {
4811 Type ctype = ec.TypeContainer.CurrentType;
4813 ctype = ec.ContainerType;
4815 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4816 if (!TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
4817 return Report_AssignToReadonly (right_side);
4818 // static InitOnly fields cannot be assigned-to in an instance constructor
4819 if (IsStatic && !ec.IsStatic)
4820 return Report_AssignToReadonly (right_side);
4821 // instance constructors can't modify InitOnly fields of other instances of the same type
4822 if (!IsStatic && !(InstanceExpression is This))
4823 return Report_AssignToReadonly (right_side);
4827 if (right_side == EmptyExpression.OutAccess &&
4828 !IsStatic && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type)) {
4829 Report.SymbolRelatedToPreviousError (DeclaringType);
4830 Report.Warning (197, 1, loc,
4831 "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",
4832 GetSignatureForError ());
4835 eclass = ExprClass.Variable;
4839 bool is_marshal_by_ref ()
4841 return !IsStatic && TypeManager.IsStruct (Type) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type);
4844 public override void CheckMarshalByRefAccess (EmitContext ec)
4846 if (is_marshal_by_ref () && !(InstanceExpression is This)) {
4847 Report.SymbolRelatedToPreviousError (DeclaringType);
4848 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",
4849 GetSignatureForError ());
4853 public override int GetHashCode ()
4855 return FieldInfo.GetHashCode ();
4858 public bool IsFixed {
4861 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
4863 IVariableReference variable = InstanceExpression as IVariableReference;
4864 if (variable != null)
4865 return TypeManager.IsStruct (InstanceExpression.Type) && variable.IsFixed;
4867 IFixedExpression fe = InstanceExpression as IFixedExpression;
4868 return fe != null && fe.IsFixed;
4872 public bool IsHoisted {
4874 IVariableReference hv = InstanceExpression as IVariableReference;
4875 return hv != null && hv.IsHoisted;
4879 public override bool Equals (object obj)
4881 FieldExpr fe = obj as FieldExpr;
4885 if (FieldInfo != fe.FieldInfo)
4888 if (InstanceExpression == null || fe.InstanceExpression == null)
4891 return InstanceExpression.Equals (fe.InstanceExpression);
4894 public void Emit (EmitContext ec, bool leave_copy)
4896 ILGenerator ig = ec.ig;
4897 bool is_volatile = false;
4899 FieldBase f = TypeManager.GetField (FieldInfo);
4901 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4904 f.SetMemberIsUsed ();
4907 if (FieldInfo.IsStatic){
4909 ig.Emit (OpCodes.Volatile);
4911 ig.Emit (OpCodes.Ldsfld, GetConstructedFieldInfo ());
4914 EmitInstance (ec, false);
4916 // Optimization for build-in types
4917 // TODO: Iterators don't set current container
4918 if (TypeManager.IsStruct (type) && type == ec.DeclContainer.TypeBuilder && ec.CurrentIterator == null) {
4919 LoadFromPtr (ig, type);
4921 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
4923 ig.Emit (OpCodes.Ldflda, GetConstructedFieldInfo ());
4924 ig.Emit (OpCodes.Ldflda, ff.Element);
4927 ig.Emit (OpCodes.Volatile);
4929 ig.Emit (OpCodes.Ldfld, GetConstructedFieldInfo ());
4935 ec.ig.Emit (OpCodes.Dup);
4936 if (!FieldInfo.IsStatic) {
4937 temp = new LocalTemporary (this.Type);
4943 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4945 FieldAttributes fa = FieldInfo.Attributes;
4946 bool is_static = (fa & FieldAttributes.Static) != 0;
4947 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
4948 ILGenerator ig = ec.ig;
4950 if (is_readonly && !ec.IsConstructor){
4951 Report_AssignToReadonly (source);
4955 prepared = prepare_for_load;
4956 EmitInstance (ec, prepared);
4960 ec.ig.Emit (OpCodes.Dup);
4961 if (!FieldInfo.IsStatic) {
4962 temp = new LocalTemporary (this.Type);
4967 FieldBase f = TypeManager.GetField (FieldInfo);
4969 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4970 ig.Emit (OpCodes.Volatile);
4976 ig.Emit (OpCodes.Stsfld, GetConstructedFieldInfo ());
4978 ig.Emit (OpCodes.Stfld, GetConstructedFieldInfo ());
4987 public override void Emit (EmitContext ec)
4992 public override void EmitSideEffect (EmitContext ec)
4994 FieldBase f = TypeManager.GetField (FieldInfo);
4995 bool is_volatile = f != null && (f.ModFlags & Modifiers.VOLATILE) != 0;
4997 if (is_volatile || is_marshal_by_ref ())
4998 base.EmitSideEffect (ec);
5001 public override void Error_VariableIsUsedBeforeItIsDeclared (string name)
5003 Report.Error (844, loc,
5004 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the field `{1}'",
5005 name, GetSignatureForError ());
5008 public void AddressOf (EmitContext ec, AddressOp mode)
5010 ILGenerator ig = ec.ig;
5012 FieldBase f = TypeManager.GetField (FieldInfo);
5014 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
5015 Report.Warning (420, 1, loc, "`{0}': A volatile field references will not be treated as volatile",
5016 f.GetSignatureForError ());
5019 if ((mode & AddressOp.Store) != 0)
5021 if ((mode & AddressOp.Load) != 0)
5022 f.SetMemberIsUsed ();
5026 // Handle initonly fields specially: make a copy and then
5027 // get the address of the copy.
5030 if (FieldInfo.IsInitOnly){
5032 if (ec.IsConstructor){
5033 if (FieldInfo.IsStatic){
5045 local = ig.DeclareLocal (type);
5046 ig.Emit (OpCodes.Stloc, local);
5047 ig.Emit (OpCodes.Ldloca, local);
5052 if (FieldInfo.IsStatic){
5053 ig.Emit (OpCodes.Ldsflda, GetConstructedFieldInfo ());
5056 EmitInstance (ec, false);
5057 ig.Emit (OpCodes.Ldflda, GetConstructedFieldInfo ());
5061 FieldInfo GetConstructedFieldInfo ()
5063 if (constructed_generic_type == null)
5066 return TypeBuilder.GetField (constructed_generic_type, FieldInfo);
5068 throw new NotSupportedException ();
5072 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5074 FieldInfo = storey.MutateField (FieldInfo);
5075 base.MutateHoistedGenericType (storey);
5081 /// Expression that evaluates to a Property. The Assign class
5082 /// might set the `Value' expression if we are in an assignment.
5084 /// This is not an LValue because we need to re-write the expression, we
5085 /// can not take data from the stack and store it.
5087 public class PropertyExpr : MemberExpr, IAssignMethod {
5088 public readonly PropertyInfo PropertyInfo;
5089 MethodInfo getter, setter;
5094 LocalTemporary temp;
5097 public PropertyExpr (Type container_type, PropertyInfo pi, Location l)
5100 eclass = ExprClass.PropertyAccess;
5104 type = TypeManager.TypeToCoreType (pi.PropertyType);
5106 ResolveAccessors (container_type);
5109 public override string Name {
5111 return PropertyInfo.Name;
5115 public override bool IsInstance {
5121 public override bool IsStatic {
5127 public override Expression CreateExpressionTree (EmitContext ec)
5130 if (IsSingleDimensionalArrayLength ()) {
5131 args = new ArrayList (1);
5132 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5133 return CreateExpressionFactoryCall ("ArrayLength", args);
5137 Error_BaseAccessInExpressionTree (loc);
5141 args = new ArrayList (2);
5142 if (InstanceExpression == null)
5143 args.Add (new Argument (new NullLiteral (loc)));
5145 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5146 args.Add (new Argument (new TypeOfMethodInfo (getter, loc)));
5147 return CreateExpressionFactoryCall ("Property", args);
5150 public Expression CreateSetterTypeOfExpression ()
5152 return new TypeOfMethodInfo (setter, loc);
5155 public override Type DeclaringType {
5157 return PropertyInfo.DeclaringType;
5161 public override string GetSignatureForError ()
5163 return TypeManager.GetFullNameSignature (PropertyInfo);
5166 void FindAccessors (Type invocation_type)
5168 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
5169 BindingFlags.Static | BindingFlags.Instance |
5170 BindingFlags.DeclaredOnly;
5172 Type current = PropertyInfo.DeclaringType;
5173 for (; current != null; current = current.BaseType) {
5174 MemberInfo[] group = TypeManager.MemberLookup (
5175 invocation_type, invocation_type, current,
5176 MemberTypes.Property, flags, PropertyInfo.Name, null);
5181 if (group.Length != 1)
5182 // Oooops, can this ever happen ?
5185 PropertyInfo pi = (PropertyInfo) group [0];
5188 getter = pi.GetGetMethod (true);
5191 setter = pi.GetSetMethod (true);
5193 MethodInfo accessor = getter != null ? getter : setter;
5195 if (!accessor.IsVirtual)
5201 // We also perform the permission checking here, as the PropertyInfo does not
5202 // hold the information for the accessibility of its setter/getter
5204 // TODO: Refactor to use some kind of cache together with GetPropertyFromAccessor
5205 void ResolveAccessors (Type container_type)
5207 FindAccessors (container_type);
5209 if (getter != null) {
5210 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
5211 IMethodData md = TypeManager.GetMethod (the_getter);
5213 md.SetMemberIsUsed ();
5215 is_static = getter.IsStatic;
5218 if (setter != null) {
5219 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
5220 IMethodData md = TypeManager.GetMethod (the_setter);
5222 md.SetMemberIsUsed ();
5224 is_static = setter.IsStatic;
5228 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5230 if (InstanceExpression != null)
5231 InstanceExpression.MutateHoistedGenericType (storey);
5233 type = storey.MutateType (type);
5235 getter = storey.MutateGenericMethod (getter);
5237 setter = storey.MutateGenericMethod (setter);
5240 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
5243 InstanceExpression = null;
5247 if (InstanceExpression == null) {
5248 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5252 InstanceExpression = InstanceExpression.DoResolve (ec);
5253 if (lvalue_instance && InstanceExpression != null)
5254 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
5256 if (InstanceExpression == null)
5259 InstanceExpression.CheckMarshalByRefAccess (ec);
5261 if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) &&
5262 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
5263 !TypeManager.IsNestedChildOf (ec.ContainerType, InstanceExpression.Type) &&
5264 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.ContainerType)) {
5265 Report.SymbolRelatedToPreviousError (PropertyInfo);
5266 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
5273 void Error_PropertyNotFound (MethodInfo mi, bool getter)
5275 // TODO: correctly we should compare arguments but it will lead to bigger changes
5276 if (mi is MethodBuilder) {
5277 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
5281 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
5283 AParametersCollection iparams = TypeManager.GetParameterData (mi);
5284 sig.Append (getter ? "get_" : "set_");
5286 sig.Append (iparams.GetSignatureForError ());
5288 Report.SymbolRelatedToPreviousError (mi);
5289 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
5290 Name, sig.ToString ());
5293 public bool IsAccessibleFrom (Type invocation_type, bool lvalue)
5296 MethodInfo accessor = lvalue ? setter : getter;
5297 if (accessor == null && lvalue)
5299 return accessor != null && IsAccessorAccessible (invocation_type, accessor, out dummy);
5302 bool IsSingleDimensionalArrayLength ()
5304 if (DeclaringType != TypeManager.array_type || getter == null || Name != "Length")
5307 string t_name = InstanceExpression.Type.Name;
5308 int t_name_len = t_name.Length;
5309 return t_name_len > 2 && t_name [t_name_len - 2] == '[';
5312 override public Expression DoResolve (EmitContext ec)
5317 if (getter != null){
5318 if (TypeManager.GetParameterData (getter).Count != 0){
5319 Error_PropertyNotFound (getter, true);
5324 if (getter == null){
5326 // The following condition happens if the PropertyExpr was
5327 // created, but is invalid (ie, the property is inaccessible),
5328 // and we did not want to embed the knowledge about this in
5329 // the caller routine. This only avoids double error reporting.
5334 if (InstanceExpression != EmptyExpression.Null) {
5335 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5336 TypeManager.GetFullNameSignature (PropertyInfo));
5341 bool must_do_cs1540_check = false;
5342 if (getter != null &&
5343 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
5344 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
5345 if (pm != null && pm.HasCustomAccessModifier) {
5346 Report.SymbolRelatedToPreviousError (pm);
5347 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5348 TypeManager.CSharpSignature (getter));
5351 Report.SymbolRelatedToPreviousError (getter);
5352 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
5357 if (!InstanceResolve (ec, false, must_do_cs1540_check))
5361 // Only base will allow this invocation to happen.
5363 if (IsBase && getter.IsAbstract) {
5364 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5367 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
5371 if (!ec.IsInObsoleteScope) {
5372 PropertyBase pb = TypeManager.GetProperty (PropertyInfo);
5374 pb.CheckObsoleteness (loc);
5376 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (PropertyInfo);
5378 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc);
5387 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
5389 if (right_side == EmptyExpression.OutAccess) {
5390 if (ec.CurrentBlock.Toplevel.GetParameterReference (PropertyInfo.Name, loc) is MemberAccess) {
5391 Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5394 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as `ref' or `out' parameter",
5395 GetSignatureForError ());
5400 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5401 Error_CannotModifyIntermediateExpressionValue (ec);
5404 if (setter == null){
5406 // The following condition happens if the PropertyExpr was
5407 // created, but is invalid (ie, the property is inaccessible),
5408 // and we did not want to embed the knowledge about this in
5409 // the caller routine. This only avoids double error reporting.
5414 if (ec.CurrentBlock.Toplevel.GetParameterReference (PropertyInfo.Name, loc) is MemberAccess) {
5415 Report.Error (1947, loc, "A range variable `{0}' cannot be assigned to. Consider using `let' clause to store the value",
5418 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
5419 GetSignatureForError ());
5424 if (TypeManager.GetParameterData (setter).Count != 1){
5425 Error_PropertyNotFound (setter, false);
5429 bool must_do_cs1540_check;
5430 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
5431 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
5432 if (pm != null && pm.HasCustomAccessModifier) {
5433 Report.SymbolRelatedToPreviousError (pm);
5434 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5435 TypeManager.CSharpSignature (setter));
5438 Report.SymbolRelatedToPreviousError (setter);
5439 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
5444 if (!InstanceResolve (ec, TypeManager.IsStruct (PropertyInfo.DeclaringType), must_do_cs1540_check))
5448 // Only base will allow this invocation to happen.
5450 if (IsBase && setter.IsAbstract){
5451 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5454 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe) {
5458 if (!ec.IsInObsoleteScope) {
5459 PropertyBase pb = TypeManager.GetProperty (PropertyInfo);
5461 pb.CheckObsoleteness (loc);
5463 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (PropertyInfo);
5465 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc);
5472 public override void Emit (EmitContext ec)
5477 public void Emit (EmitContext ec, bool leave_copy)
5480 // Special case: length of single dimension array property is turned into ldlen
5482 if (IsSingleDimensionalArrayLength ()) {
5484 EmitInstance (ec, false);
5485 ec.ig.Emit (OpCodes.Ldlen);
5486 ec.ig.Emit (OpCodes.Conv_I4);
5490 Invocation.EmitCall (ec, IsBase, InstanceExpression, getter, null, loc, prepared, false);
5493 ec.ig.Emit (OpCodes.Dup);
5495 temp = new LocalTemporary (this.Type);
5502 // Implements the IAssignMethod interface for assignments
5504 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5506 Expression my_source = source;
5508 if (prepare_for_load) {
5513 ec.ig.Emit (OpCodes.Dup);
5515 temp = new LocalTemporary (this.Type);
5519 } else if (leave_copy) {
5521 temp = new LocalTemporary (this.Type);
5526 ArrayList args = new ArrayList (1);
5527 args.Add (new Argument (my_source, Argument.AType.Expression));
5529 Invocation.EmitCall (ec, IsBase, InstanceExpression, setter, args, loc, false, prepared);
5539 /// Fully resolved expression that evaluates to an Event
5541 public class EventExpr : MemberExpr {
5542 public readonly EventInfo EventInfo;
5545 MethodInfo add_accessor, remove_accessor;
5547 public EventExpr (EventInfo ei, Location loc)
5551 eclass = ExprClass.EventAccess;
5553 add_accessor = TypeManager.GetAddMethod (ei);
5554 remove_accessor = TypeManager.GetRemoveMethod (ei);
5555 if (add_accessor.IsStatic || remove_accessor.IsStatic)
5558 if (EventInfo is MyEventBuilder){
5559 MyEventBuilder eb = (MyEventBuilder) EventInfo;
5560 type = eb.EventType;
5563 type = EventInfo.EventHandlerType;
5566 public override string Name {
5568 return EventInfo.Name;
5572 public override bool IsInstance {
5578 public override bool IsStatic {
5584 public override Type DeclaringType {
5586 return EventInfo.DeclaringType;
5590 void Error_AssignmentEventOnly ()
5592 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5593 GetSignatureForError ());
5596 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
5597 SimpleName original)
5600 // If the event is local to this class, we transform ourselves into a FieldExpr
5603 if (EventInfo.DeclaringType == ec.ContainerType ||
5604 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
5605 EventField mi = TypeManager.GetEventField (EventInfo);
5608 if (!ec.IsInObsoleteScope)
5609 mi.CheckObsoleteness (loc);
5611 if ((mi.ModFlags & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0 && !ec.IsInCompoundAssignment)
5612 Error_AssignmentEventOnly ();
5614 FieldExpr ml = new FieldExpr (mi.BackingField.FieldBuilder, loc);
5616 InstanceExpression = null;
5618 return ml.ResolveMemberAccess (ec, left, loc, original);
5622 if (left is This && !ec.IsInCompoundAssignment)
5623 Error_AssignmentEventOnly ();
5625 return base.ResolveMemberAccess (ec, left, loc, original);
5628 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
5631 InstanceExpression = null;
5635 if (InstanceExpression == null) {
5636 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5640 InstanceExpression = InstanceExpression.DoResolve (ec);
5641 if (InstanceExpression == null)
5644 if (IsBase && add_accessor.IsAbstract) {
5645 Error_CannotCallAbstractBase(TypeManager.CSharpSignature(add_accessor));
5650 // This is using the same mechanism as the CS1540 check in PropertyExpr.
5651 // However, in the Event case, we reported a CS0122 instead.
5653 // TODO: Exact copy from PropertyExpr
5655 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
5656 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
5657 !TypeManager.IsNestedChildOf (ec.ContainerType, InstanceExpression.Type) &&
5658 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.ContainerType)) {
5659 Report.SymbolRelatedToPreviousError (EventInfo);
5660 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5667 public bool IsAccessibleFrom (Type invocation_type)
5670 return IsAccessorAccessible (invocation_type, add_accessor, out dummy) &&
5671 IsAccessorAccessible (invocation_type, remove_accessor, out dummy);
5674 public override Expression CreateExpressionTree (EmitContext ec)
5676 throw new NotSupportedException ("ET");
5679 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5681 // contexts where an LValue is valid have already devolved to FieldExprs
5682 Error_CannotAssign ();
5686 public override Expression DoResolve (EmitContext ec)
5688 bool must_do_cs1540_check;
5689 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
5690 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
5691 Report.SymbolRelatedToPreviousError (EventInfo);
5692 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5696 if (!InstanceResolve (ec, must_do_cs1540_check))
5699 if (!ec.IsInCompoundAssignment) {
5700 Error_CannotAssign ();
5704 if (!ec.IsInObsoleteScope) {
5705 EventField ev = TypeManager.GetEventField (EventInfo);
5707 ev.CheckObsoleteness (loc);
5709 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (EventInfo);
5711 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc);
5718 public override void Emit (EmitContext ec)
5720 Error_CannotAssign ();
5723 public void Error_CannotAssign ()
5725 Report.Error (70, loc,
5726 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
5727 GetSignatureForError (), TypeManager.CSharpName (EventInfo.DeclaringType));
5730 public override string GetSignatureForError ()
5732 return TypeManager.CSharpSignature (EventInfo);
5735 public void EmitAddOrRemove (EmitContext ec, bool is_add, Expression source)
5737 ArrayList args = new ArrayList (1);
5738 args.Add (new Argument (source, Argument.AType.Expression));
5739 Invocation.EmitCall (ec, IsBase, InstanceExpression, is_add ? add_accessor : remove_accessor, args, loc);
5743 public class TemporaryVariable : VariableReference
5747 public TemporaryVariable (Type type, Location loc)
5751 eclass = ExprClass.Variable;
5754 public override Expression CreateExpressionTree (EmitContext ec)
5756 throw new NotSupportedException ("ET");
5759 public override Expression DoResolve (EmitContext ec)
5764 TypeExpr te = new TypeExpression (type, loc);
5765 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
5766 if (!li.Resolve (ec))
5770 // Don't capture temporary variables except when using
5771 // iterator redirection
5773 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.IsIterator && ec.IsVariableCapturingRequired) {
5774 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
5775 storey.CaptureLocalVariable (ec, li);
5781 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5783 return DoResolve (ec);
5786 public override void Emit (EmitContext ec)
5791 public void EmitAssign (EmitContext ec, Expression source)
5793 EmitAssign (ec, source, false, false);
5796 public override HoistedVariable GetHoistedVariable (EmitContext ec)
5798 return li.HoistedVariableReference;
5801 public override bool IsFixed {
5802 get { return true; }
5805 public override bool IsRef {
5806 get { return false; }
5809 public override string Name {
5810 get { throw new NotImplementedException (); }
5813 public override void SetHasAddressTaken ()
5815 throw new NotImplementedException ();
5818 protected override ILocalVariable Variable {
5822 public override VariableInfo VariableInfo {
5823 get { throw new NotImplementedException (); }
5828 /// Handles `var' contextual keyword; var becomes a keyword only
5829 /// if no type called var exists in a variable scope
5831 public class VarExpr : SimpleName
5833 // Used for error reporting only
5834 ArrayList initializer;
5836 public VarExpr (Location loc)
5841 public ArrayList VariableInitializer {
5843 this.initializer = value;
5847 public bool InferType (EmitContext ec, Expression right_side)
5850 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
5852 type = right_side.Type;
5853 if (type == TypeManager.null_type || type == TypeManager.void_type || type == TypeManager.anonymous_method_type) {
5854 Report.Error (815, loc, "An implicitly typed local variable declaration cannot be initialized with `{0}'",
5855 right_side.GetSignatureForError ());
5859 eclass = ExprClass.Variable;
5863 protected override void Error_TypeOrNamespaceNotFound (IResolveContext ec)
5865 Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");
5868 public override TypeExpr ResolveAsContextualType (IResolveContext rc, bool silent)
5870 TypeExpr te = base.ResolveAsContextualType (rc, true);
5874 if (initializer == null)
5877 if (initializer.Count > 1) {
5878 Location loc = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [1]).Location;
5879 Report.Error (819, loc, "An implicitly typed local variable declaration cannot include multiple declarators");
5884 Expression variable_initializer = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [0]).expression_or_array_initializer;
5885 if (variable_initializer == null) {
5886 Report.Error (818, loc, "An implicitly typed local variable declarator must include an initializer");