2 // ecore.cs: Core of the Expression representation for the intermediate tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@seznam.cz)
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
13 namespace Mono.CSharp {
15 using System.Collections;
16 using System.Diagnostics;
17 using System.Reflection;
18 using System.Reflection.Emit;
22 /// The ExprClass class contains the is used to pass the
23 /// classification of an expression (value, variable, namespace,
24 /// type, method group, property access, event access, indexer access,
27 public enum ExprClass : byte {
43 /// This is used to tell Resolve in which types of expressions we're
47 public enum ResolveFlags {
48 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
51 // Returns a type expression.
54 // Returns a method group.
57 TypeParameter = 1 << 3,
59 // Mask of all the expression class flags.
60 MaskExprClass = VariableOrValue | Type | MethodGroup | TypeParameter,
62 // Disable control flow analysis while resolving the expression.
63 // This is used when resolving the instance expression of a field expression.
64 DisableFlowAnalysis = 1 << 10,
66 // Set if this is resolving the first part of a MemberAccess.
67 Intermediate = 1 << 11,
69 // Disable control flow analysis _of struct_ while resolving the expression.
70 // This is used when resolving the instance expression of a field expression.
71 DisableStructFlowAnalysis = 1 << 12,
76 // This is just as a hint to AddressOf of what will be done with the
79 public enum AddressOp {
86 /// This interface is implemented by variables
88 public interface IMemoryLocation {
90 /// The AddressOf method should generate code that loads
91 /// the address of the object and leaves it on the stack.
93 /// The `mode' argument is used to notify the expression
94 /// of whether this will be used to read from the address or
95 /// write to the address.
97 /// This is just a hint that can be used to provide good error
98 /// reporting, and should have no other side effects.
100 void AddressOf (EmitContext ec, AddressOp mode);
104 // An expressions resolved as a direct variable reference
106 public interface IVariableReference : IFixedExpression
108 bool IsHoisted { get; }
110 VariableInfo VariableInfo { get; }
112 void SetHasAddressTaken ();
116 // Implemented by an expression which could be or is always
119 public interface IFixedExpression
121 bool IsFixed { get; }
125 /// Base class for expressions
127 public abstract class Expression {
128 public ExprClass eclass;
130 protected Location loc;
134 set { type = value; }
137 public virtual Location Location {
142 /// Utility wrapper routine for Error, just to beautify the code
144 public void Error (int error, string s)
146 Report.Error (error, loc, s);
149 // Not nice but we have broken hierarchy.
150 public virtual void CheckMarshalByRefAccess (EmitContext ec)
154 public virtual bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
156 Attribute.Error_AttributeArgumentNotValid (loc);
161 public virtual string GetSignatureForError ()
163 return TypeManager.CSharpName (type);
166 public static bool IsAccessorAccessible (Type invocation_type, MethodInfo mi, out bool must_do_cs1540_check)
168 MethodAttributes ma = mi.Attributes & MethodAttributes.MemberAccessMask;
170 must_do_cs1540_check = false; // by default we do not check for this
172 if (ma == MethodAttributes.Public)
176 // If only accessible to the current class or children
178 if (ma == MethodAttributes.Private)
179 return TypeManager.IsPrivateAccessible (invocation_type, mi.DeclaringType) ||
180 TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType);
182 if (TypeManager.IsThisOrFriendAssembly (mi.DeclaringType.Assembly)) {
183 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamORAssem)
186 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamANDAssem)
190 // Family and FamANDAssem require that we derive.
191 // FamORAssem requires that we derive if in different assemblies.
192 if (!TypeManager.IsNestedFamilyAccessible (invocation_type, mi.DeclaringType))
195 if (!TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType))
196 must_do_cs1540_check = true;
201 public virtual bool IsNull {
208 /// Performs semantic analysis on the Expression
212 /// The Resolve method is invoked to perform the semantic analysis
215 /// The return value is an expression (it can be the
216 /// same expression in some cases) or a new
217 /// expression that better represents this node.
219 /// For example, optimizations of Unary (LiteralInt)
220 /// would return a new LiteralInt with a negated
223 /// If there is an error during semantic analysis,
224 /// then an error should be reported (using Report)
225 /// and a null value should be returned.
227 /// There are two side effects expected from calling
228 /// Resolve(): the the field variable "eclass" should
229 /// be set to any value of the enumeration
230 /// `ExprClass' and the type variable should be set
231 /// to a valid type (this is the type of the
234 public abstract Expression DoResolve (EmitContext ec);
236 public virtual Expression DoResolveLValue (EmitContext ec, Expression right_side)
242 // This is used if the expression should be resolved as a type or namespace name.
243 // the default implementation fails.
245 public virtual FullNamedExpression ResolveAsTypeStep (IResolveContext rc, bool silent)
249 EmitContext ec = rc as EmitContext;
253 e.Error_UnexpectedKind (ResolveFlags.Type, loc);
259 // C# 3.0 introduced contextual keywords (var) which behaves like a type if type with
260 // same name exists or as a keyword when no type was found
262 public virtual TypeExpr ResolveAsContextualType (IResolveContext rc, bool silent)
264 return ResolveAsTypeTerminal (rc, silent);
268 // This is used to resolve the expression as a type, a null
269 // value will be returned if the expression is not a type
272 public virtual TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
274 TypeExpr te = ResolveAsBaseTerminal (ec, silent);
278 if (!silent) { // && !(te is TypeParameterExpr)) {
279 ObsoleteAttribute obsolete_attr = AttributeTester.GetObsoleteAttribute (te.Type);
280 if (obsolete_attr != null && !ec.IsInObsoleteScope) {
281 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location);
285 GenericTypeExpr ct = te as GenericTypeExpr;
287 // Skip constrains check for overrides and explicit implementations
288 // TODO: they should use different overload
289 GenericMethod gm = ec.GenericDeclContainer as GenericMethod;
290 if (gm != null && ((gm.ModFlags & Modifiers.OVERRIDE) != 0 || gm.MemberName.Left != null)) {
295 // TODO: silent flag is ignored
296 ct.CheckConstraints (ec);
297 ct.VerifyVariantTypeParameters ();
303 public TypeExpr ResolveAsBaseTerminal (IResolveContext ec, bool silent)
305 int errors = Report.Errors;
307 FullNamedExpression fne = ResolveAsTypeStep (ec, silent);
312 TypeExpr te = fne as TypeExpr;
314 if (!silent && errors == Report.Errors)
315 fne.Error_UnexpectedKind (null, "type", loc);
319 if (!te.CheckAccessLevel (ec.GenericDeclContainer)) {
320 Report.SymbolRelatedToPreviousError (te.Type);
321 ErrorIsInaccesible (loc, TypeManager.CSharpName (te.Type));
329 public static void ErrorIsInaccesible (Location loc, string name)
331 Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", name);
334 protected static void Error_CannotAccessProtected (Location loc, MemberInfo m, Type qualifier, Type container)
336 Report.Error (1540, loc, "Cannot access protected member `{0}' via a qualifier of type `{1}'."
337 + " The qualifier must be of type `{2}' or derived from it",
338 TypeManager.GetFullNameSignature (m),
339 TypeManager.CSharpName (qualifier),
340 TypeManager.CSharpName (container));
344 public static void Error_InvalidExpressionStatement (Location loc)
346 Report.Error (201, loc, "Only assignment, call, increment, decrement, and new object " +
347 "expressions can be used as a statement");
350 public void Error_InvalidExpressionStatement ()
352 Error_InvalidExpressionStatement (loc);
355 protected void Error_CannotAssign (string to, string roContext)
357 Report.Error (1656, loc, "Cannot assign to `{0}' because it is a `{1}'",
361 public static void Error_VoidInvalidInTheContext (Location loc)
363 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
366 public virtual void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl)
368 // The error was already reported as CS1660
369 if (type == TypeManager.anonymous_method_type)
372 if (TypeManager.IsGenericParameter (Type) && TypeManager.IsGenericParameter (target) && type.Name == target.Name) {
374 string sig1 = type.DeclaringMethod == null ?
375 TypeManager.CSharpName (type.DeclaringType) :
376 TypeManager.CSharpSignature (type.DeclaringMethod);
377 string sig2 = target.DeclaringMethod == null ?
378 TypeManager.CSharpName (target.DeclaringType) :
379 TypeManager.CSharpSignature (target.DeclaringMethod);
380 Report.ExtraInformation (loc,
382 "The generic parameter `{0}' of `{1}' cannot be converted to the generic parameter `{0}' of `{2}' (in the previous ",
383 Type.Name, sig1, sig2));
385 } else if (Type.FullName == target.FullName){
386 Report.ExtraInformation (loc,
388 "The type `{0}' has two conflicting definitions, one comes from `{1}' and the other from `{2}' (in the previous ",
389 Type.FullName, Type.Assembly.FullName, target.Assembly.FullName));
393 Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
394 TypeManager.CSharpName (type), TypeManager.CSharpName (target));
398 Report.DisableReporting ();
399 bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null;
400 Report.EnableReporting ();
403 Report.Error (266, loc, "Cannot implicitly convert type `{0}' to `{1}'. " +
404 "An explicit conversion exists (are you missing a cast?)",
405 TypeManager.CSharpName (Type), TypeManager.CSharpName (target));
409 Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
410 TypeManager.CSharpName (type),
411 TypeManager.CSharpName (target));
414 public virtual void Error_VariableIsUsedBeforeItIsDeclared (string name)
416 Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", name);
419 protected virtual void Error_TypeDoesNotContainDefinition (Type type, string name)
421 Error_TypeDoesNotContainDefinition (loc, type, name);
424 public static void Error_TypeDoesNotContainDefinition (Location loc, Type type, string name)
426 Report.SymbolRelatedToPreviousError (type);
427 Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
428 TypeManager.CSharpName (type), name);
431 protected static void Error_ValueAssignment (Location loc)
433 Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
436 ResolveFlags ExprClassToResolveFlags
441 case ExprClass.Namespace:
442 return ResolveFlags.Type;
444 case ExprClass.MethodGroup:
445 return ResolveFlags.MethodGroup;
447 case ExprClass.TypeParameter:
448 return ResolveFlags.TypeParameter;
450 case ExprClass.Value:
451 case ExprClass.Variable:
452 case ExprClass.PropertyAccess:
453 case ExprClass.EventAccess:
454 case ExprClass.IndexerAccess:
455 return ResolveFlags.VariableOrValue;
458 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
464 /// Resolves an expression and performs semantic analysis on it.
468 /// Currently Resolve wraps DoResolve to perform sanity
469 /// checking and assertion checking on what we expect from Resolve.
471 public Expression Resolve (EmitContext ec, ResolveFlags flags)
473 if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type)
474 return ResolveAsTypeStep (ec, false);
476 bool do_flow_analysis = ec.DoFlowAnalysis;
477 bool omit_struct_analysis = ec.OmitStructFlowAnalysis;
478 if ((flags & ResolveFlags.DisableFlowAnalysis) != 0)
479 do_flow_analysis = false;
480 if ((flags & ResolveFlags.DisableStructFlowAnalysis) != 0)
481 omit_struct_analysis = true;
484 using (ec.WithFlowAnalysis (do_flow_analysis, omit_struct_analysis)) {
485 if (this is SimpleName) {
486 bool intermediate = (flags & ResolveFlags.Intermediate) == ResolveFlags.Intermediate;
487 e = ((SimpleName) this).DoResolve (ec, intermediate);
496 if ((flags & e.ExprClassToResolveFlags) == 0) {
497 e.Error_UnexpectedKind (flags, loc);
501 if (e.type == null && !(e is Namespace)) {
502 throw new Exception (
503 "Expression " + e.GetType () +
504 " did not set its type after Resolve\n" +
505 "called from: " + this.GetType ());
512 /// Resolves an expression and performs semantic analysis on it.
514 public Expression Resolve (EmitContext ec)
516 Expression e = Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
518 if (e != null && e.eclass == ExprClass.MethodGroup && RootContext.Version == LanguageVersion.ISO_1) {
519 ((MethodGroupExpr) e).ReportUsageError ();
525 public Constant ResolveAsConstant (EmitContext ec, MemberCore mc)
527 Expression e = Resolve (ec);
531 Constant c = e as Constant;
535 if (type != null && TypeManager.IsReferenceType (type))
536 Const.Error_ConstantCanBeInitializedWithNullOnly (type, loc, mc.GetSignatureForError ());
538 Const.Error_ExpressionMustBeConstant (loc, mc.GetSignatureForError ());
544 /// Resolves an expression for LValue assignment
548 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
549 /// checking and assertion checking on what we expect from Resolve
551 public Expression ResolveLValue (EmitContext ec, Expression right_side, Location loc)
553 int errors = Report.Errors;
554 bool out_access = right_side == EmptyExpression.OutAccess;
556 Expression e = DoResolveLValue (ec, right_side);
558 if (e != null && out_access && !(e is IMemoryLocation)) {
559 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
560 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
562 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
563 // e.GetType () + " " + e.GetSignatureForError ());
568 if (errors == Report.Errors) {
570 Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
572 Error_ValueAssignment (loc);
577 if (e.eclass == ExprClass.Invalid)
578 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
580 if ((e.type == null) && !(e is GenericTypeExpr))
581 throw new Exception ("Expression " + e + " did not set its type after Resolve");
587 /// Emits the code for the expression
591 /// The Emit method is invoked to generate the code
592 /// for the expression.
594 public abstract void Emit (EmitContext ec);
596 // Emit code to branch to @target if this expression is equivalent to @on_true.
597 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
598 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
599 // including the use of conditional branches. Note also that a branch MUST be emitted
600 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
603 ec.ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
606 // Emit this expression for its side effects, not for its value.
607 // The default implementation is to emit the value, and then throw it away.
608 // Subclasses can provide more efficient implementations, but those MUST be equivalent
609 public virtual void EmitSideEffect (EmitContext ec)
612 ec.ig.Emit (OpCodes.Pop);
616 /// Protected constructor. Only derivate types should
617 /// be able to be created
620 protected Expression ()
622 eclass = ExprClass.Invalid;
627 /// Returns a fully formed expression after a MemberLookup
630 public static Expression ExprClassFromMemberInfo (Type container_type, MemberInfo mi, Location loc)
633 return new EventExpr ((EventInfo) mi, loc);
634 else if (mi is FieldInfo) {
635 FieldInfo fi = (FieldInfo) mi;
636 if (fi.IsLiteral || (fi.IsInitOnly && fi.FieldType == TypeManager.decimal_type))
637 return new ConstantExpr (fi, loc);
638 return new FieldExpr (fi, loc);
639 } else if (mi is PropertyInfo)
640 return new PropertyExpr (container_type, (PropertyInfo) mi, loc);
641 else if (mi is Type) {
642 return new TypeExpression ((System.Type) mi, loc);
648 // TODO: [Obsolete ("Can be removed")]
649 protected static ArrayList almost_matched_members = new ArrayList (4);
652 // FIXME: Probably implement a cache for (t,name,current_access_set)?
654 // This code could use some optimizations, but we need to do some
655 // measurements. For example, we could use a delegate to `flag' when
656 // something can not any longer be a method-group (because it is something
660 // If the return value is an Array, then it is an array of
663 // If the return value is an MemberInfo, it is anything, but a Method
667 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
668 // the arguments here and have MemberLookup return only the methods that
669 // match the argument count/type, unlike we are doing now (we delay this
672 // This is so we can catch correctly attempts to invoke instance methods
673 // from a static body (scan for error 120 in ResolveSimpleName).
676 // FIXME: Potential optimization, have a static ArrayList
679 public static Expression MemberLookup (Type container_type, Type queried_type, string name,
680 MemberTypes mt, BindingFlags bf, Location loc)
682 return MemberLookup (container_type, null, queried_type, name, mt, bf, loc);
686 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
687 // `qualifier_type' or null to lookup members in the current class.
690 public static Expression MemberLookup (Type container_type,
691 Type qualifier_type, Type queried_type,
692 string name, MemberTypes mt,
693 BindingFlags bf, Location loc)
695 almost_matched_members.Clear ();
697 MemberInfo [] mi = TypeManager.MemberLookup (container_type, qualifier_type,
698 queried_type, mt, bf, name, almost_matched_members);
704 bool is_interface = qualifier_type != null && qualifier_type.IsInterface;
705 ArrayList methods = new ArrayList (2);
706 ArrayList non_methods = null;
708 foreach (MemberInfo m in mi) {
709 if (m is MethodBase) {
714 if (non_methods == null) {
715 non_methods = new ArrayList (2);
720 foreach (MemberInfo n_m in non_methods) {
721 if (m.DeclaringType.IsInterface && TypeManager.ImplementsInterface (m.DeclaringType, n_m.DeclaringType))
724 Report.SymbolRelatedToPreviousError (m);
725 Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
726 TypeManager.GetFullNameSignature (m), TypeManager.GetFullNameSignature (n_m));
731 if (methods.Count == 0)
732 return ExprClassFromMemberInfo (container_type, (MemberInfo)non_methods [0], loc);
734 if (non_methods != null) {
735 MethodBase method = (MethodBase) methods [0];
736 MemberInfo non_method = (MemberInfo) non_methods [0];
737 if (method.DeclaringType == non_method.DeclaringType) {
738 // Cannot happen with C# code, but is valid in IL
739 Report.SymbolRelatedToPreviousError (method);
740 Report.SymbolRelatedToPreviousError (non_method);
741 Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
742 TypeManager.GetFullNameSignature (non_method),
743 TypeManager.CSharpSignature (method));
748 Report.SymbolRelatedToPreviousError (method);
749 Report.SymbolRelatedToPreviousError (non_method);
750 Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and non-method `{1}'. Using method `{0}'",
751 TypeManager.CSharpSignature (method), TypeManager.GetFullNameSignature (non_method));
755 return new MethodGroupExpr (methods, queried_type, loc);
758 if (mi [0] is MethodBase)
759 return new MethodGroupExpr (mi, queried_type, loc);
761 return ExprClassFromMemberInfo (container_type, mi [0], loc);
764 public const MemberTypes AllMemberTypes =
765 MemberTypes.Constructor |
769 MemberTypes.NestedType |
770 MemberTypes.Property;
772 public const BindingFlags AllBindingFlags =
773 BindingFlags.Public |
774 BindingFlags.Static |
775 BindingFlags.Instance;
777 public static Expression MemberLookup (Type container_type, Type queried_type,
778 string name, Location loc)
780 return MemberLookup (container_type, null, queried_type, name,
781 AllMemberTypes, AllBindingFlags, loc);
784 public static Expression MemberLookup (Type container_type, Type qualifier_type,
785 Type queried_type, string name, Location loc)
787 return MemberLookup (container_type, qualifier_type, queried_type,
788 name, AllMemberTypes, AllBindingFlags, loc);
791 public static MethodGroupExpr MethodLookup (Type container_type, Type queried_type,
792 string name, Location loc)
794 return (MethodGroupExpr)MemberLookup (container_type, null, queried_type, name,
795 MemberTypes.Method, AllBindingFlags, loc);
799 /// This is a wrapper for MemberLookup that is not used to "probe", but
800 /// to find a final definition. If the final definition is not found, we
801 /// look for private members and display a useful debugging message if we
804 protected Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
805 Type queried_type, string name,
806 MemberTypes mt, BindingFlags bf,
811 int errors = Report.Errors;
812 e = MemberLookup (ec.ContainerType, qualifier_type, queried_type, name, mt, bf, loc);
814 if (e != null || errors != Report.Errors)
817 // No errors were reported by MemberLookup, but there was an error.
818 return Error_MemberLookupFailed (ec.ContainerType, qualifier_type, queried_type,
822 protected virtual Expression Error_MemberLookupFailed (Type container_type, Type qualifier_type,
823 Type queried_type, string name, string class_name,
824 MemberTypes mt, BindingFlags bf)
826 MemberInfo[] lookup = null;
827 if (queried_type == null) {
828 class_name = "global::";
830 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
831 mt, (bf & ~BindingFlags.Public) | BindingFlags.NonPublic,
834 if (lookup != null) {
835 Expression e = Error_MemberLookupFailed (queried_type, lookup);
838 // FIXME: This is still very wrong, it should be done inside
839 // OverloadResolve to do correct arguments matching.
840 // Requires MemberLookup accessiblity check removal
842 if (e == null || (mt & (MemberTypes.Method | MemberTypes.Constructor)) == 0) {
843 MemberInfo mi = lookup[0];
844 Report.SymbolRelatedToPreviousError (mi);
845 if (qualifier_type != null && container_type != null && qualifier_type != container_type &&
846 TypeManager.IsNestedFamilyAccessible (container_type, mi.DeclaringType)) {
847 // Although a derived class can access protected members of
848 // its base class it cannot do so through an instance of the
849 // base class (CS1540). If the qualifier_type is a base of the
850 // ec.ContainerType and the lookup succeeds with the latter one,
851 // then we are in this situation.
852 Error_CannotAccessProtected (loc, mi, qualifier_type, container_type);
854 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (mi));
861 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
862 AllMemberTypes, AllBindingFlags | BindingFlags.NonPublic,
866 if (lookup == null) {
867 if (class_name != null) {
868 Report.Error (103, loc, "The name `{0}' does not exist in the current context",
871 Error_TypeDoesNotContainDefinition (queried_type, name);
876 if (TypeManager.MemberLookup (queried_type, null, queried_type,
877 AllMemberTypes, AllBindingFlags |
878 BindingFlags.NonPublic, name, null) == null) {
879 if ((lookup.Length == 1) && (lookup [0] is Type)) {
880 Type t = (Type) lookup [0];
882 Report.Error (305, loc,
883 "Using the generic type `{0}' " +
884 "requires {1} type arguments",
885 TypeManager.CSharpName (t),
886 TypeManager.GetNumberOfTypeArguments (t).ToString ());
891 return Error_MemberLookupFailed (queried_type, lookup);
894 protected virtual Expression Error_MemberLookupFailed (Type type, MemberInfo[] members)
896 for (int i = 0; i < members.Length; ++i) {
897 if (!(members [i] is MethodBase))
901 // By default propagate the closest candidates upwards
902 return new MethodGroupExpr (members, type, loc, true);
905 protected virtual void Error_NegativeArrayIndex (Location loc)
907 throw new NotImplementedException ();
910 protected void Error_PointerInsideExpressionTree ()
912 Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
916 /// Returns an expression that can be used to invoke operator true
917 /// on the expression if it exists.
919 static public Expression GetOperatorTrue (EmitContext ec, Expression e, Location loc)
921 return GetOperatorTrueOrFalse (ec, e, true, loc);
925 /// Returns an expression that can be used to invoke operator false
926 /// on the expression if it exists.
928 static public Expression GetOperatorFalse (EmitContext ec, Expression e, Location loc)
930 return GetOperatorTrueOrFalse (ec, e, false, loc);
933 static Expression GetOperatorTrueOrFalse (EmitContext ec, Expression e, bool is_true, Location loc)
935 MethodGroupExpr operator_group;
936 string mname = Operator.GetMetadataName (is_true ? Operator.OpType.True : Operator.OpType.False);
937 operator_group = MethodLookup (ec.ContainerType, e.Type, mname, loc) as MethodGroupExpr;
938 if (operator_group == null)
941 ArrayList arguments = new ArrayList (1);
942 arguments.Add (new Argument (e, Argument.AType.Expression));
943 operator_group = operator_group.OverloadResolve (
944 ec, ref arguments, false, loc);
946 if (operator_group == null)
949 return new UserOperatorCall (operator_group, arguments, null, loc);
953 /// Resolves the expression `e' into a boolean expression: either through
954 /// an implicit conversion, or through an `operator true' invocation
956 public static Expression ResolveBoolean (EmitContext ec, Expression e, Location loc)
962 if (e.Type == TypeManager.bool_type)
965 Expression converted = Convert.ImplicitConversion (ec, e, TypeManager.bool_type, Location.Null);
967 if (converted != null)
971 // If no implicit conversion to bool exists, try using `operator true'
973 converted = Expression.GetOperatorTrue (ec, e, loc);
974 if (converted == null){
975 e.Error_ValueCannotBeConverted (ec, loc, TypeManager.bool_type, false);
981 public virtual string ExprClassName
985 case ExprClass.Invalid:
987 case ExprClass.Value:
989 case ExprClass.Variable:
991 case ExprClass.Namespace:
995 case ExprClass.MethodGroup:
996 return "method group";
997 case ExprClass.PropertyAccess:
998 return "property access";
999 case ExprClass.EventAccess:
1000 return "event access";
1001 case ExprClass.IndexerAccess:
1002 return "indexer access";
1003 case ExprClass.Nothing:
1005 case ExprClass.TypeParameter:
1006 return "type parameter";
1008 throw new Exception ("Should not happen");
1013 /// Reports that we were expecting `expr' to be of class `expected'
1015 public void Error_UnexpectedKind (DeclSpace ds, string expected, Location loc)
1017 Error_UnexpectedKind (ds, expected, ExprClassName, loc);
1020 public void Error_UnexpectedKind (DeclSpace ds, string expected, string was, Location loc)
1022 string name = GetSignatureForError ();
1024 name = ds.GetSignatureForError () + '.' + name;
1026 Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
1027 name, was, expected);
1030 public void Error_UnexpectedKind (ResolveFlags flags, Location loc)
1032 string [] valid = new string [4];
1035 if ((flags & ResolveFlags.VariableOrValue) != 0) {
1036 valid [count++] = "variable";
1037 valid [count++] = "value";
1040 if ((flags & ResolveFlags.Type) != 0)
1041 valid [count++] = "type";
1043 if ((flags & ResolveFlags.MethodGroup) != 0)
1044 valid [count++] = "method group";
1047 valid [count++] = "unknown";
1049 StringBuilder sb = new StringBuilder (valid [0]);
1050 for (int i = 1; i < count - 1; i++) {
1052 sb.Append (valid [i]);
1055 sb.Append ("' or `");
1056 sb.Append (valid [count - 1]);
1059 Report.Error (119, loc,
1060 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1063 public static void UnsafeError (Location loc)
1065 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1069 // Load the object from the pointer.
1071 public static void LoadFromPtr (ILGenerator ig, Type t)
1073 if (t == TypeManager.int32_type)
1074 ig.Emit (OpCodes.Ldind_I4);
1075 else if (t == TypeManager.uint32_type)
1076 ig.Emit (OpCodes.Ldind_U4);
1077 else if (t == TypeManager.short_type)
1078 ig.Emit (OpCodes.Ldind_I2);
1079 else if (t == TypeManager.ushort_type)
1080 ig.Emit (OpCodes.Ldind_U2);
1081 else if (t == TypeManager.char_type)
1082 ig.Emit (OpCodes.Ldind_U2);
1083 else if (t == TypeManager.byte_type)
1084 ig.Emit (OpCodes.Ldind_U1);
1085 else if (t == TypeManager.sbyte_type)
1086 ig.Emit (OpCodes.Ldind_I1);
1087 else if (t == TypeManager.uint64_type)
1088 ig.Emit (OpCodes.Ldind_I8);
1089 else if (t == TypeManager.int64_type)
1090 ig.Emit (OpCodes.Ldind_I8);
1091 else if (t == TypeManager.float_type)
1092 ig.Emit (OpCodes.Ldind_R4);
1093 else if (t == TypeManager.double_type)
1094 ig.Emit (OpCodes.Ldind_R8);
1095 else if (t == TypeManager.bool_type)
1096 ig.Emit (OpCodes.Ldind_I1);
1097 else if (t == TypeManager.intptr_type)
1098 ig.Emit (OpCodes.Ldind_I);
1099 else if (TypeManager.IsEnumType (t)) {
1100 if (t == TypeManager.enum_type)
1101 ig.Emit (OpCodes.Ldind_Ref);
1103 LoadFromPtr (ig, TypeManager.GetEnumUnderlyingType (t));
1104 } else if (TypeManager.IsStruct (t) || TypeManager.IsGenericParameter (t))
1105 ig.Emit (OpCodes.Ldobj, t);
1106 else if (t.IsPointer)
1107 ig.Emit (OpCodes.Ldind_I);
1109 ig.Emit (OpCodes.Ldind_Ref);
1113 // The stack contains the pointer and the value of type `type'
1115 public static void StoreFromPtr (ILGenerator ig, Type type)
1117 if (TypeManager.IsEnumType (type))
1118 type = TypeManager.GetEnumUnderlyingType (type);
1119 if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
1120 ig.Emit (OpCodes.Stind_I4);
1121 else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
1122 ig.Emit (OpCodes.Stind_I8);
1123 else if (type == TypeManager.char_type || type == TypeManager.short_type ||
1124 type == TypeManager.ushort_type)
1125 ig.Emit (OpCodes.Stind_I2);
1126 else if (type == TypeManager.float_type)
1127 ig.Emit (OpCodes.Stind_R4);
1128 else if (type == TypeManager.double_type)
1129 ig.Emit (OpCodes.Stind_R8);
1130 else if (type == TypeManager.byte_type || type == TypeManager.sbyte_type ||
1131 type == TypeManager.bool_type)
1132 ig.Emit (OpCodes.Stind_I1);
1133 else if (type == TypeManager.intptr_type)
1134 ig.Emit (OpCodes.Stind_I);
1135 else if (TypeManager.IsStruct (type) || TypeManager.IsGenericParameter (type))
1136 ig.Emit (OpCodes.Stobj, type);
1138 ig.Emit (OpCodes.Stind_Ref);
1142 // Returns the size of type `t' if known, otherwise, 0
1144 public static int GetTypeSize (Type t)
1146 t = TypeManager.TypeToCoreType (t);
1147 if (t == TypeManager.int32_type ||
1148 t == TypeManager.uint32_type ||
1149 t == TypeManager.float_type)
1151 else if (t == TypeManager.int64_type ||
1152 t == TypeManager.uint64_type ||
1153 t == TypeManager.double_type)
1155 else if (t == TypeManager.byte_type ||
1156 t == TypeManager.sbyte_type ||
1157 t == TypeManager.bool_type)
1159 else if (t == TypeManager.short_type ||
1160 t == TypeManager.char_type ||
1161 t == TypeManager.ushort_type)
1163 else if (t == TypeManager.decimal_type)
1169 protected void Error_CannotCallAbstractBase (string name)
1171 Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
1174 protected void Error_CannotModifyIntermediateExpressionValue (EmitContext ec)
1176 Report.SymbolRelatedToPreviousError (type);
1177 if (ec.CurrentInitializerVariable != null) {
1178 Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
1179 TypeManager.CSharpName (type), GetSignatureForError ());
1181 Report.Error (1612, loc, "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
1182 GetSignatureForError ());
1186 public void Error_ExpressionCannotBeGeneric (Location loc)
1188 Report.Error (307, loc, "The {0} `{1}' cannot be used with type arguments",
1189 ExprClassName, GetSignatureForError ());
1193 // Converts `source' to an int, uint, long or ulong.
1195 public Expression ConvertExpressionToArrayIndex (EmitContext ec, Expression source)
1197 Expression converted;
1199 using (ec.With (EmitContext.Flags.CheckState, true)) {
1200 converted = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, source.loc);
1201 if (converted == null)
1202 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, source.loc);
1203 if (converted == null)
1204 converted = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, source.loc);
1205 if (converted == null)
1206 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, source.loc);
1208 if (converted == null) {
1209 source.Error_ValueCannotBeConverted (ec, source.loc, TypeManager.int32_type, false);
1215 // Only positive constants are allowed at compile time
1217 Constant c = converted as Constant;
1220 Error_NegativeArrayIndex (source.loc);
1225 return new ArrayIndexCast (converted).Resolve (ec);
1229 // Derived classes implement this method by cloning the fields that
1230 // could become altered during the Resolve stage
1232 // Only expressions that are created for the parser need to implement
1235 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1237 throw new NotImplementedException (
1239 "CloneTo not implemented for expression {0}", this.GetType ()));
1243 // Clones an expression created by the parser.
1245 // We only support expressions created by the parser so far, not
1246 // expressions that have been resolved (many more classes would need
1247 // to implement CloneTo).
1249 // This infrastructure is here merely for Lambda expressions which
1250 // compile the same code using different type values for the same
1251 // arguments to find the correct overload
1253 public Expression Clone (CloneContext clonectx)
1255 Expression cloned = (Expression) MemberwiseClone ();
1256 CloneTo (clonectx, cloned);
1262 // Implementation of expression to expression tree conversion
1264 public abstract Expression CreateExpressionTree (EmitContext ec);
1266 protected Expression CreateExpressionFactoryCall (string name, ArrayList args)
1268 return CreateExpressionFactoryCall (name, null, args, loc);
1271 protected Expression CreateExpressionFactoryCall (string name, TypeArguments typeArguments, ArrayList args)
1273 return CreateExpressionFactoryCall (name, typeArguments, args, loc);
1276 public static Expression CreateExpressionFactoryCall (string name, TypeArguments typeArguments, ArrayList args, Location loc)
1278 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (loc), name, typeArguments, loc), args);
1281 protected static TypeExpr CreateExpressionTypeExpression (Location loc)
1283 TypeExpr texpr = TypeManager.expression_type_expr;
1284 if (texpr == null) {
1285 Type t = TypeManager.CoreLookupType ("System.Linq.Expressions", "Expression", Kind.Class, true);
1289 TypeManager.expression_type_expr = texpr = new TypeExpression (t, Location.Null);
1295 public virtual void MutateHoistedGenericType (AnonymousMethodStorey storey)
1297 // TODO: It should probably be type = storey.MutateType (type);
1302 /// This is just a base class for expressions that can
1303 /// appear on statements (invocations, object creation,
1304 /// assignments, post/pre increment and decrement). The idea
1305 /// being that they would support an extra Emition interface that
1306 /// does not leave a result on the stack.
1308 public abstract class ExpressionStatement : Expression {
1310 public virtual ExpressionStatement ResolveStatement (EmitContext ec)
1312 Expression e = Resolve (ec);
1316 ExpressionStatement es = e as ExpressionStatement;
1318 Error_InvalidExpressionStatement ();
1324 /// Requests the expression to be emitted in a `statement'
1325 /// context. This means that no new value is left on the
1326 /// stack after invoking this method (constrasted with
1327 /// Emit that will always leave a value on the stack).
1329 public abstract void EmitStatement (EmitContext ec);
1331 public override void EmitSideEffect (EmitContext ec)
1338 /// This kind of cast is used to encapsulate the child
1339 /// whose type is child.Type into an expression that is
1340 /// reported to return "return_type". This is used to encapsulate
1341 /// expressions which have compatible types, but need to be dealt
1342 /// at higher levels with.
1344 /// For example, a "byte" expression could be encapsulated in one
1345 /// of these as an "unsigned int". The type for the expression
1346 /// would be "unsigned int".
1349 public abstract class TypeCast : Expression
1351 protected readonly Expression child;
1353 protected TypeCast (Expression child, Type return_type)
1355 eclass = child.eclass;
1356 loc = child.Location;
1361 public override Expression CreateExpressionTree (EmitContext ec)
1363 ArrayList args = new ArrayList (2);
1364 args.Add (new Argument (child.CreateExpressionTree (ec)));
1365 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1367 if (type.IsPointer || child.Type.IsPointer)
1368 Error_PointerInsideExpressionTree ();
1370 return CreateExpressionFactoryCall (ec.CheckState ? "ConvertChecked" : "Convert", args);
1373 public override Expression DoResolve (EmitContext ec)
1375 // This should never be invoked, we are born in fully
1376 // initialized state.
1381 public override void Emit (EmitContext ec)
1386 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
1388 return child.GetAttributableValue (ec, value_type, out value);
1391 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1393 type = storey.MutateType (type);
1394 child.MutateHoistedGenericType (storey);
1397 protected override void CloneTo (CloneContext clonectx, Expression t)
1402 public override bool IsNull {
1403 get { return child.IsNull; }
1407 public class EmptyCast : TypeCast {
1408 EmptyCast (Expression child, Type target_type)
1409 : base (child, target_type)
1413 public static Expression Create (Expression child, Type type)
1415 Constant c = child as Constant;
1417 return new EmptyConstantCast (c, type);
1419 EmptyCast e = child as EmptyCast;
1421 return new EmptyCast (e.child, type);
1423 return new EmptyCast (child, type);
1426 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1428 child.EmitBranchable (ec, label, on_true);
1431 public override void EmitSideEffect (EmitContext ec)
1433 child.EmitSideEffect (ec);
1438 // Used for predefined class library user casts (no obsolete check, etc.)
1440 public class OperatorCast : TypeCast {
1441 MethodInfo conversion_operator;
1443 public OperatorCast (Expression child, Type target_type)
1444 : this (child, target_type, false)
1448 public OperatorCast (Expression child, Type target_type, bool find_explicit)
1449 : base (child, target_type)
1451 conversion_operator = GetConversionOperator (find_explicit);
1452 if (conversion_operator == null)
1453 throw new InternalErrorException ("Outer conversion routine is out of sync");
1456 // Returns the implicit operator that converts from
1457 // 'child.Type' to our target type (type)
1458 MethodInfo GetConversionOperator (bool find_explicit)
1460 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1464 mi = TypeManager.MemberLookup (child.Type, child.Type, child.Type, MemberTypes.Method,
1465 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1468 mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1469 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1472 foreach (MethodInfo oper in mi) {
1473 AParametersCollection pd = TypeManager.GetParameterData (oper);
1475 if (pd.Types [0] == child.Type && TypeManager.TypeToCoreType (oper.ReturnType) == type)
1482 public override void Emit (EmitContext ec)
1485 ec.ig.Emit (OpCodes.Call, conversion_operator);
1490 /// This is a numeric cast to a Decimal
1492 public class CastToDecimal : OperatorCast {
1493 public CastToDecimal (Expression child)
1494 : this (child, false)
1498 public CastToDecimal (Expression child, bool find_explicit)
1499 : base (child, TypeManager.decimal_type, find_explicit)
1505 /// This is an explicit numeric cast from a Decimal
1507 public class CastFromDecimal : TypeCast
1509 static IDictionary operators;
1511 public CastFromDecimal (Expression child, Type return_type)
1512 : base (child, return_type)
1514 if (child.Type != TypeManager.decimal_type)
1515 throw new InternalErrorException (
1516 "The expected type is Decimal, instead it is " + child.Type.FullName);
1519 // Returns the explicit operator that converts from an
1520 // express of type System.Decimal to 'type'.
1521 public Expression Resolve ()
1523 if (operators == null) {
1524 MemberInfo[] all_oper = TypeManager.MemberLookup (TypeManager.decimal_type,
1525 TypeManager.decimal_type, TypeManager.decimal_type, MemberTypes.Method,
1526 BindingFlags.Static | BindingFlags.Public, "op_Explicit", null);
1528 operators = new System.Collections.Specialized.HybridDictionary ();
1529 foreach (MethodInfo oper in all_oper) {
1530 AParametersCollection pd = TypeManager.GetParameterData (oper);
1531 if (pd.Types [0] == TypeManager.decimal_type)
1532 operators.Add (TypeManager.TypeToCoreType (oper.ReturnType), oper);
1536 return operators.Contains (type) ? this : null;
1539 public override void Emit (EmitContext ec)
1541 ILGenerator ig = ec.ig;
1544 ig.Emit (OpCodes.Call, (MethodInfo)operators [type]);
1550 // Constant specialization of EmptyCast.
1551 // We need to special case this since an empty cast of
1552 // a constant is still a constant.
1554 public class EmptyConstantCast : Constant
1556 public readonly Constant child;
1558 public EmptyConstantCast(Constant child, Type type)
1559 : base (child.Location)
1561 eclass = child.eclass;
1566 public override string AsString ()
1568 return child.AsString ();
1571 public override object GetValue ()
1573 return child.GetValue ();
1576 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
1578 // FIXME: check that 'type' can be converted to 'target_type' first
1579 return child.ConvertExplicitly (in_checked_context, target_type);
1582 public override Expression CreateExpressionTree (EmitContext ec)
1584 ArrayList args = new ArrayList (2);
1585 args.Add (new Argument (child.CreateExpressionTree (ec)));
1586 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1588 Error_PointerInsideExpressionTree ();
1590 return CreateExpressionFactoryCall ("Convert", args);
1593 public override Constant Increment ()
1595 return child.Increment ();
1598 public override bool IsDefaultValue {
1599 get { return child.IsDefaultValue; }
1602 public override bool IsNegative {
1603 get { return child.IsNegative; }
1606 public override bool IsNull {
1607 get { return child.IsNull; }
1610 public override bool IsZeroInteger {
1611 get { return child.IsZeroInteger; }
1614 public override void Emit (EmitContext ec)
1619 // Only to make verifier happy
1620 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1621 ec.ig.Emit (OpCodes.Unbox_Any, type);
1625 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1627 child.EmitBranchable (ec, label, on_true);
1630 // Only to make verifier happy
1631 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1632 ec.ig.Emit (OpCodes.Unbox_Any, type);
1636 public override void EmitSideEffect (EmitContext ec)
1638 child.EmitSideEffect (ec);
1641 public override Constant ConvertImplicitly (Type target_type)
1643 // FIXME: Do we need to check user conversions?
1644 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1646 return child.ConvertImplicitly (target_type);
1649 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1651 child.MutateHoistedGenericType (storey);
1657 /// This class is used to wrap literals which belong inside Enums
1659 public class EnumConstant : Constant {
1660 public Constant Child;
1662 public EnumConstant (Constant child, Type enum_type):
1663 base (child.Location)
1665 eclass = child.eclass;
1670 public override Expression DoResolve (EmitContext ec)
1672 // This should never be invoked, we are born in fully
1673 // initialized state.
1678 public override void Emit (EmitContext ec)
1683 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1685 Child.EmitBranchable (ec, label, on_true);
1688 public override void EmitSideEffect (EmitContext ec)
1690 Child.EmitSideEffect (ec);
1693 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
1695 value = GetTypedValue ();
1699 public override string GetSignatureForError()
1701 return TypeManager.CSharpName (Type);
1704 public override object GetValue ()
1706 return Child.GetValue ();
1709 public override object GetTypedValue ()
1711 // FIXME: runtime is not ready to work with just emited enums
1712 if (!RootContext.StdLib) {
1713 return Child.GetValue ();
1717 // Small workaround for big problem
1718 // System.Enum.ToObject cannot be called on dynamic types
1719 // EnumBuilder has to be used, but we cannot use EnumBuilder
1720 // because it does not properly support generics
1722 // This works only sometimes
1724 if (type.Module == CodeGen.Module.Builder)
1725 return Child.GetValue ();
1728 return System.Enum.ToObject (type, Child.GetValue ());
1731 public override string AsString ()
1733 return Child.AsString ();
1736 public override Constant Increment()
1738 return new EnumConstant (Child.Increment (), type);
1741 public override bool IsDefaultValue {
1743 return Child.IsDefaultValue;
1747 public override bool IsZeroInteger {
1748 get { return Child.IsZeroInteger; }
1751 public override bool IsNegative {
1753 return Child.IsNegative;
1757 public override Constant ConvertExplicitly(bool in_checked_context, Type target_type)
1759 if (Child.Type == target_type)
1762 return Child.ConvertExplicitly (in_checked_context, target_type);
1765 public override Constant ConvertImplicitly (Type type)
1767 Type this_type = TypeManager.DropGenericTypeArguments (Type);
1768 type = TypeManager.DropGenericTypeArguments (type);
1770 if (this_type == type) {
1771 // This is workaround of mono bug. It can be removed when the latest corlib spreads enough
1772 if (TypeManager.IsEnumType (type.UnderlyingSystemType))
1775 Type child_type = TypeManager.DropGenericTypeArguments (Child.Type);
1776 if (type.UnderlyingSystemType != child_type)
1777 Child = Child.ConvertImplicitly (type.UnderlyingSystemType);
1781 if (!Convert.ImplicitStandardConversionExists (this, type)){
1785 return Child.ConvertImplicitly(type);
1791 /// This kind of cast is used to encapsulate Value Types in objects.
1793 /// The effect of it is to box the value type emitted by the previous
1796 public class BoxedCast : TypeCast {
1798 public BoxedCast (Expression expr, Type target_type)
1799 : base (expr, target_type)
1801 eclass = ExprClass.Value;
1804 public override Expression DoResolve (EmitContext ec)
1806 // This should never be invoked, we are born in fully
1807 // initialized state.
1812 public override void Emit (EmitContext ec)
1816 ec.ig.Emit (OpCodes.Box, child.Type);
1819 public override void EmitSideEffect (EmitContext ec)
1821 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1822 // so, we need to emit the box+pop instructions in most cases
1823 if (TypeManager.IsStruct (child.Type) &&
1824 (type == TypeManager.object_type || type == TypeManager.value_type))
1825 child.EmitSideEffect (ec);
1827 base.EmitSideEffect (ec);
1831 public class UnboxCast : TypeCast {
1832 public UnboxCast (Expression expr, Type return_type)
1833 : base (expr, return_type)
1837 public override Expression DoResolve (EmitContext ec)
1839 // This should never be invoked, we are born in fully
1840 // initialized state.
1845 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1847 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
1848 Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
1849 return base.DoResolveLValue (ec, right_side);
1852 public override void Emit (EmitContext ec)
1854 ILGenerator ig = ec.ig;
1858 if (type.IsGenericParameter || type.IsGenericType && type.IsValueType)
1859 ig.Emit (OpCodes.Unbox_Any, type);
1863 ig.Emit (OpCodes.Unbox, type);
1865 LoadFromPtr (ig, type);
1869 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1871 type = storey.MutateType (type);
1872 base.MutateHoistedGenericType (storey);
1877 /// This is used to perform explicit numeric conversions.
1879 /// Explicit numeric conversions might trigger exceptions in a checked
1880 /// context, so they should generate the conv.ovf opcodes instead of
1883 public class ConvCast : TypeCast {
1884 public enum Mode : byte {
1885 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1887 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1888 U2_I1, U2_U1, U2_I2, U2_CH,
1889 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1890 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1891 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH,
1892 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH,
1893 CH_I1, CH_U1, CH_I2,
1894 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1895 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4
1900 public ConvCast (Expression child, Type return_type, Mode m)
1901 : base (child, return_type)
1906 public override Expression DoResolve (EmitContext ec)
1908 // This should never be invoked, we are born in fully
1909 // initialized state.
1914 public override string ToString ()
1916 return String.Format ("ConvCast ({0}, {1})", mode, child);
1919 public override void Emit (EmitContext ec)
1921 ILGenerator ig = ec.ig;
1927 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1928 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1929 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1930 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1931 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1933 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1934 case Mode.U1_CH: /* nothing */ break;
1936 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1937 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1938 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1939 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1940 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1941 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1943 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1944 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1945 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1946 case Mode.U2_CH: /* nothing */ break;
1948 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1949 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1950 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1951 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1952 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1953 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1954 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1956 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1957 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1958 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1959 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1960 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1961 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1963 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1964 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1965 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1966 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1967 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1968 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1969 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1970 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1972 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1973 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1974 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1975 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1976 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1977 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1978 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1979 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1981 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1982 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1983 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1985 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1986 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1987 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1988 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1989 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1990 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1991 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1992 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1993 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1995 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1996 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1997 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1998 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1999 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
2000 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
2001 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
2002 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
2003 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
2004 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
2008 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
2009 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
2010 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
2011 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
2012 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
2014 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
2015 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
2017 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
2018 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
2019 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
2020 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
2021 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
2022 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
2024 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
2025 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
2026 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
2027 case Mode.U2_CH: /* nothing */ break;
2029 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
2030 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
2031 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
2032 case Mode.I4_U4: /* nothing */ break;
2033 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
2034 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
2035 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
2037 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
2038 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
2039 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
2040 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
2041 case Mode.U4_I4: /* nothing */ break;
2042 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
2044 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
2045 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
2046 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
2047 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
2048 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
2049 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
2050 case Mode.I8_U8: /* nothing */ break;
2051 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
2053 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
2054 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
2055 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
2056 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
2057 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
2058 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
2059 case Mode.U8_I8: /* nothing */ break;
2060 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
2062 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
2063 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
2064 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
2066 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
2067 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
2068 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
2069 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
2070 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
2071 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
2072 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
2073 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
2074 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
2076 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
2077 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
2078 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
2079 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
2080 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
2081 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
2082 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
2083 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
2084 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
2085 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
2091 public class OpcodeCast : TypeCast {
2094 public OpcodeCast (Expression child, Type return_type, OpCode op)
2095 : base (child, return_type)
2100 public override Expression DoResolve (EmitContext ec)
2102 // This should never be invoked, we are born in fully
2103 // initialized state.
2108 public override void Emit (EmitContext ec)
2114 public Type UnderlyingType {
2115 get { return child.Type; }
2120 /// This kind of cast is used to encapsulate a child and cast it
2121 /// to the class requested
2123 public sealed class ClassCast : TypeCast {
2124 readonly bool forced;
2126 public ClassCast (Expression child, Type return_type)
2127 : base (child, return_type)
2131 public ClassCast (Expression child, Type return_type, bool forced)
2132 : base (child, return_type)
2134 this.forced = forced;
2137 public override void Emit (EmitContext ec)
2142 bool gen = TypeManager.IsGenericParameter (child.Type);
2144 ec.ig.Emit (OpCodes.Box, child.Type);
2146 if (type.IsGenericParameter) {
2147 ec.ig.Emit (OpCodes.Unbox_Any, type);
2155 ec.ig.Emit (OpCodes.Castclass, type);
2160 // Created during resolving pahse when an expression is wrapped or constantified
2161 // and original expression can be used later (e.g. for expression trees)
2163 public class ReducedExpression : Expression
2165 sealed class ReducedConstantExpression : EmptyConstantCast
2167 readonly Expression orig_expr;
2169 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2170 : base (expr, expr.Type)
2172 this.orig_expr = orig_expr;
2175 public override Constant ConvertImplicitly (Type target_type)
2177 Constant c = base.ConvertImplicitly (target_type);
2179 c = new ReducedConstantExpression (c, orig_expr);
2183 public override Expression CreateExpressionTree (EmitContext ec)
2185 return orig_expr.CreateExpressionTree (ec);
2188 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
2191 // Even if resolved result is a constant original expression was not
2192 // and attribute accepts constants only
2194 Attribute.Error_AttributeArgumentNotValid (orig_expr.Location);
2199 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
2201 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
2203 c = new ReducedConstantExpression (c, orig_expr);
2208 sealed class ReducedExpressionStatement : ExpressionStatement
2210 readonly Expression orig_expr;
2211 readonly ExpressionStatement stm;
2213 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
2215 this.orig_expr = orig;
2217 this.loc = orig.Location;
2220 public override Expression CreateExpressionTree (EmitContext ec)
2222 return orig_expr.CreateExpressionTree (ec);
2225 public override Expression DoResolve (EmitContext ec)
2227 eclass = stm.eclass;
2232 public override void Emit (EmitContext ec)
2237 public override void EmitStatement (EmitContext ec)
2239 stm.EmitStatement (ec);
2242 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2244 stm.MutateHoistedGenericType (storey);
2248 readonly Expression expr, orig_expr;
2250 private ReducedExpression (Expression expr, Expression orig_expr)
2253 this.orig_expr = orig_expr;
2254 this.loc = orig_expr.Location;
2257 public static Constant Create (Constant expr, Expression original_expr)
2259 return new ReducedConstantExpression (expr, original_expr);
2262 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
2264 return new ReducedExpressionStatement (s, orig);
2267 public static Expression Create (Expression expr, Expression original_expr)
2269 Constant c = expr as Constant;
2271 return Create (c, original_expr);
2273 ExpressionStatement s = expr as ExpressionStatement;
2275 return Create (s, original_expr);
2277 return new ReducedExpression (expr, original_expr);
2280 public override Expression CreateExpressionTree (EmitContext ec)
2282 return orig_expr.CreateExpressionTree (ec);
2285 public override Expression DoResolve (EmitContext ec)
2287 eclass = expr.eclass;
2292 public override void Emit (EmitContext ec)
2297 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2299 expr.EmitBranchable (ec, target, on_true);
2302 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2304 expr.MutateHoistedGenericType (storey);
2309 // Unresolved type name expressions
2311 public abstract class ATypeNameExpression : FullNamedExpression
2313 public readonly string Name;
2314 protected TypeArguments targs;
2316 protected ATypeNameExpression (string name, Location l)
2322 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2329 public bool HasTypeArguments {
2331 return targs != null;
2335 public override bool Equals (object obj)
2337 ATypeNameExpression atne = obj as ATypeNameExpression;
2338 return atne != null && atne.Name == Name &&
2339 (targs == null || targs.Equals (atne.targs));
2342 public override int GetHashCode ()
2344 return Name.GetHashCode ();
2347 public override string GetSignatureForError ()
2349 if (targs != null) {
2350 return TypeManager.RemoveGenericArity (Name) + "<" +
2351 targs.GetSignatureForError () + ">";
2359 /// SimpleName expressions are formed of a single word and only happen at the beginning
2360 /// of a dotted-name.
2362 public class SimpleName : ATypeNameExpression {
2365 public SimpleName (string name, Location l)
2370 public SimpleName (string name, TypeArguments args, Location l)
2371 : base (name, args, l)
2375 public SimpleName (string name, TypeParameter[] type_params, Location l)
2378 targs = new TypeArguments ();
2379 foreach (TypeParameter type_param in type_params)
2380 targs.Add (new TypeParameterExpr (type_param, l));
2383 public static string RemoveGenericArity (string name)
2386 StringBuilder sb = null;
2388 int pos = name.IndexOf ('`', start);
2393 sb.Append (name.Substring (start));
2398 sb = new StringBuilder ();
2399 sb.Append (name.Substring (start, pos-start));
2402 while ((pos < name.Length) && Char.IsNumber (name [pos]))
2406 } while (start < name.Length);
2408 return sb.ToString ();
2411 public SimpleName GetMethodGroup ()
2413 return new SimpleName (RemoveGenericArity (Name), targs, loc);
2416 public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
2418 if (ec.IsInFieldInitializer)
2419 Report.Error (236, l,
2420 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2423 Report.Error (120, l,
2424 "An object reference is required to access non-static member `{0}'",
2428 public bool IdenticalNameAndTypeName (EmitContext ec, Expression resolved_to, Location loc)
2430 return resolved_to != null && resolved_to.Type != null &&
2431 resolved_to.Type.Name == Name &&
2432 (ec.DeclContainer.LookupNamespaceOrType (Name, loc, /* ignore_cs0104 = */ true) != null);
2435 public override Expression DoResolve (EmitContext ec)
2437 return SimpleNameResolve (ec, null, false);
2440 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
2442 return SimpleNameResolve (ec, right_side, false);
2446 public Expression DoResolve (EmitContext ec, bool intermediate)
2448 return SimpleNameResolve (ec, null, intermediate);
2451 static bool IsNestedChild (Type t, Type parent)
2453 while (parent != null) {
2454 if (TypeManager.IsNestedChildOf (t, TypeManager.DropGenericTypeArguments (parent)))
2457 parent = parent.BaseType;
2463 FullNamedExpression ResolveNested (IResolveContext ec, Type t)
2465 if (!TypeManager.IsGenericTypeDefinition (t) && !TypeManager.IsGenericType (t))
2468 DeclSpace ds = ec.DeclContainer;
2469 while (ds != null && !IsNestedChild (t, ds.TypeBuilder))
2475 Type[] gen_params = TypeManager.GetTypeArguments (t);
2477 int arg_count = targs != null ? targs.Count : 0;
2479 for (; (ds != null) && ds.IsGeneric; ds = ds.Parent) {
2480 if (arg_count + ds.CountTypeParameters == gen_params.Length) {
2481 TypeArguments new_args = new TypeArguments ();
2482 foreach (TypeParameter param in ds.TypeParameters)
2483 new_args.Add (new TypeParameterExpr (param, loc));
2486 new_args.Add (targs);
2488 return new GenericTypeExpr (t, new_args, loc);
2495 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2497 FullNamedExpression fne = ec.GenericDeclContainer.LookupGeneric (Name, loc);
2499 return fne.ResolveAsTypeStep (ec, silent);
2501 int errors = Report.Errors;
2502 fne = ec.DeclContainer.LookupNamespaceOrType (Name, loc, /*ignore_cs0104=*/ false);
2505 if (fne.Type == null)
2508 FullNamedExpression nested = ResolveNested (ec, fne.Type);
2510 return nested.ResolveAsTypeStep (ec, false);
2512 if (targs != null) {
2513 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2514 return ct.ResolveAsTypeStep (ec, false);
2520 if (silent || errors != Report.Errors)
2523 Error_TypeOrNamespaceNotFound (ec);
2527 protected virtual void Error_TypeOrNamespaceNotFound (IResolveContext ec)
2529 MemberCore mc = ec.DeclContainer.GetDefinition (Name);
2531 Error_UnexpectedKind (ec.DeclContainer, "type", GetMemberType (mc), loc);
2535 string ns = ec.DeclContainer.NamespaceEntry.NS.Name;
2536 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2537 foreach (Assembly a in RootNamespace.Global.Assemblies) {
2538 Type type = a.GetType (fullname);
2540 Report.SymbolRelatedToPreviousError (type);
2541 Expression.ErrorIsInaccesible (loc, TypeManager.CSharpName (type));
2546 Type t = ec.DeclContainer.LookupAnyGeneric (Name);
2548 Namespace.Error_InvalidNumberOfTypeArguments (t, loc);
2552 if (targs != null) {
2553 FullNamedExpression retval = ec.DeclContainer.LookupNamespaceOrType (SimpleName.RemoveGenericArity (Name), loc, true);
2554 if (retval != null) {
2555 Namespace.Error_TypeArgumentsCannotBeUsed (retval, loc);
2560 NamespaceEntry.Error_NamespaceNotFound (loc, Name);
2563 // TODO: I am still not convinced about this. If someone else will need it
2564 // implement this as virtual property in MemberCore hierarchy
2565 public static string GetMemberType (MemberCore mc)
2571 if (mc is FieldBase)
2573 if (mc is MethodCore)
2575 if (mc is EnumMember)
2583 Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2589 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2595 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2602 /// 7.5.2: Simple Names.
2604 /// Local Variables and Parameters are handled at
2605 /// parse time, so they never occur as SimpleNames.
2607 /// The `intermediate' flag is used by MemberAccess only
2608 /// and it is used to inform us that it is ok for us to
2609 /// avoid the static check, because MemberAccess might end
2610 /// up resolving the Name as a Type name and the access as
2611 /// a static type access.
2613 /// ie: Type Type; .... { Type.GetType (""); }
2615 /// Type is both an instance variable and a Type; Type.GetType
2616 /// is the static method not an instance method of type.
2618 Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2620 Expression e = null;
2623 // Stage 1: Performed by the parser (binding to locals or parameters).
2625 Block current_block = ec.CurrentBlock;
2626 if (current_block != null){
2627 LocalInfo vi = current_block.GetLocalInfo (Name);
2629 LocalVariableReference var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2630 if (right_side != null) {
2631 return var.ResolveLValue (ec, right_side, loc);
2633 ResolveFlags rf = ResolveFlags.VariableOrValue;
2635 rf |= ResolveFlags.DisableFlowAnalysis;
2636 return var.Resolve (ec, rf);
2640 Expression expr = current_block.Toplevel.GetParameterReference (Name, loc);
2642 if (right_side != null)
2643 return expr.ResolveLValue (ec, right_side, loc);
2645 return expr.Resolve (ec);
2650 // Stage 2: Lookup members
2653 Type almost_matched_type = null;
2654 ArrayList almost_matched = null;
2655 for (DeclSpace lookup_ds = ec.DeclContainer; lookup_ds != null; lookup_ds = lookup_ds.Parent) {
2656 // either RootDeclSpace or GenericMethod
2657 if (lookup_ds.TypeBuilder == null)
2660 e = MemberLookup (ec.ContainerType, lookup_ds.TypeBuilder, Name, loc);
2662 PropertyExpr pe = e as PropertyExpr;
2664 AParametersCollection param = TypeManager.GetParameterData (pe.PropertyInfo);
2666 // since TypeManager.MemberLookup doesn't know if we're doing a lvalue access or not,
2667 // it doesn't know which accessor to check permissions against
2668 if (param.IsEmpty && pe.IsAccessibleFrom (ec.ContainerType, right_side != null))
2670 } else if (e is EventExpr) {
2671 if (((EventExpr) e).IsAccessibleFrom (ec.ContainerType))
2673 } else if (targs != null && e is TypeExpression) {
2674 e = new GenericTypeExpr (e.Type, targs, loc).ResolveAsTypeStep (ec, false);
2682 if (almost_matched == null && almost_matched_members.Count > 0) {
2683 almost_matched_type = lookup_ds.TypeBuilder;
2684 almost_matched = (ArrayList) almost_matched_members.Clone ();
2689 if (almost_matched == null && almost_matched_members.Count > 0) {
2690 almost_matched_type = ec.ContainerType;
2691 almost_matched = (ArrayList) almost_matched_members.Clone ();
2693 e = ResolveAsTypeStep (ec, true);
2697 if (current_block != null) {
2698 IKnownVariable ikv = current_block.Explicit.GetKnownVariable (Name);
2700 LocalInfo li = ikv as LocalInfo;
2701 // Supress CS0219 warning
2705 Error_VariableIsUsedBeforeItIsDeclared (Name);
2710 if (RootContext.EvalMode){
2711 FieldInfo fi = Evaluator.LookupField (Name);
2713 return new FieldExpr (fi, loc).Resolve (ec);
2716 if (almost_matched != null)
2717 almost_matched_members = almost_matched;
2718 if (almost_matched_type == null)
2719 almost_matched_type = ec.ContainerType;
2720 return Error_MemberLookupFailed (ec.ContainerType, null, almost_matched_type, Name,
2721 ec.DeclContainer.Name, AllMemberTypes, AllBindingFlags);
2724 if (e is MemberExpr) {
2725 MemberExpr me = (MemberExpr) e;
2728 if (me.IsInstance) {
2729 if (ec.IsStatic || ec.IsInFieldInitializer) {
2731 // Note that an MemberExpr can be both IsInstance and IsStatic.
2732 // An unresolved MethodGroupExpr can contain both kinds of methods
2733 // and each predicate is true if the MethodGroupExpr contains
2734 // at least one of that kind of method.
2738 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2739 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2744 // Pass the buck to MemberAccess and Invocation.
2746 left = EmptyExpression.Null;
2748 left = ec.GetThis (loc);
2751 left = new TypeExpression (ec.ContainerType, loc);
2754 me = me.ResolveMemberAccess (ec, left, loc, null);
2758 if (targs != null) {
2759 if (!targs.Resolve (ec))
2762 me.SetTypeArguments (targs);
2765 if (!me.IsStatic && (me.InstanceExpression != null) &&
2766 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2767 me.InstanceExpression.Type != me.DeclaringType &&
2768 !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2769 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2770 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2771 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2775 return (right_side != null)
2776 ? me.DoResolveLValue (ec, right_side)
2777 : me.DoResolve (ec);
2785 /// Represents a namespace or a type. The name of the class was inspired by
2786 /// section 10.8.1 (Fully Qualified Names).
2788 public abstract class FullNamedExpression : Expression
2790 protected override void CloneTo (CloneContext clonectx, Expression target)
2792 // Do nothing, most unresolved type expressions cannot be
2793 // resolved to different type
2796 public override Expression CreateExpressionTree (EmitContext ec)
2798 throw new NotSupportedException ("ET");
2801 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2803 throw new NotSupportedException ();
2806 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2811 public override void Emit (EmitContext ec)
2813 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2814 GetSignatureForError ());
2819 /// Expression that evaluates to a type
2821 public abstract class TypeExpr : FullNamedExpression {
2822 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2824 TypeExpr t = DoResolveAsTypeStep (ec);
2828 eclass = ExprClass.Type;
2832 override public Expression DoResolve (EmitContext ec)
2834 return ResolveAsTypeTerminal (ec, false);
2837 public virtual bool CheckAccessLevel (DeclSpace ds)
2839 return ds.CheckAccessLevel (Type);
2842 public virtual bool AsAccessible (DeclSpace ds)
2844 return ds.IsAccessibleAs (Type);
2847 public virtual bool IsClass {
2848 get { return Type.IsClass; }
2851 public virtual bool IsValueType {
2852 get { return TypeManager.IsStruct (Type); }
2855 public virtual bool IsInterface {
2856 get { return Type.IsInterface; }
2859 public virtual bool IsSealed {
2860 get { return Type.IsSealed; }
2863 public virtual bool CanInheritFrom ()
2865 if (Type == TypeManager.enum_type ||
2866 (Type == TypeManager.value_type && RootContext.StdLib) ||
2867 Type == TypeManager.multicast_delegate_type ||
2868 Type == TypeManager.delegate_type ||
2869 Type == TypeManager.array_type)
2875 protected abstract TypeExpr DoResolveAsTypeStep (IResolveContext ec);
2877 public override bool Equals (object obj)
2879 TypeExpr tobj = obj as TypeExpr;
2883 return Type == tobj.Type;
2886 public override int GetHashCode ()
2888 return Type.GetHashCode ();
2891 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2893 type = storey.MutateType (type);
2898 /// Fully resolved Expression that already evaluated to a type
2900 public class TypeExpression : TypeExpr {
2901 public TypeExpression (Type t, Location l)
2904 eclass = ExprClass.Type;
2908 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2913 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2920 // Used to create types from a fully qualified name. These are just used
2921 // by the parser to setup the core types.
2923 public sealed class TypeLookupExpression : TypeExpr {
2924 readonly string ns_name;
2925 readonly string name;
2927 public TypeLookupExpression (string ns, string name)
2931 eclass = ExprClass.Type;
2934 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2937 // It's null only during mscorlib bootstrap when DefineType
2938 // nees to resolve base type of same type
2940 // For instance struct Char : IComparable<char>
2942 // TODO: it could be removed when Resolve starts to use
2943 // DeclSpace instead of Type
2946 Namespace ns = RootNamespace.Global.GetNamespace (ns_name, false);
2947 FullNamedExpression fne = ns.Lookup (null, name, loc);
2955 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2960 public override string GetSignatureForError ()
2963 return TypeManager.CSharpName (ns_name + "." + name, null);
2965 return base.GetSignatureForError ();
2970 /// This class denotes an expression which evaluates to a member
2971 /// of a struct or a class.
2973 public abstract class MemberExpr : Expression
2975 protected bool is_base;
2978 /// The name of this member.
2980 public abstract string Name {
2985 // When base.member is used
2987 public bool IsBase {
2988 get { return is_base; }
2989 set { is_base = value; }
2993 /// Whether this is an instance member.
2995 public abstract bool IsInstance {
3000 /// Whether this is a static member.
3002 public abstract bool IsStatic {
3007 /// The type which declares this member.
3009 public abstract Type DeclaringType {
3014 /// The instance expression associated with this member, if it's a
3015 /// non-static member.
3017 public Expression InstanceExpression;
3019 public static void error176 (Location loc, string name)
3021 Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
3022 "with an instance reference, qualify it with a type name instead", name);
3025 public static void Error_BaseAccessInExpressionTree (Location loc)
3027 Report.Error (831, loc, "An expression tree may not contain a base access");
3030 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3032 if (InstanceExpression != null)
3033 InstanceExpression.MutateHoistedGenericType (storey);
3036 // TODO: possible optimalization
3037 // Cache resolved constant result in FieldBuilder <-> expression map
3038 public virtual MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3039 SimpleName original)
3043 // original == null || original.Resolve (...) ==> left
3046 if (left is TypeExpr) {
3047 left = left.ResolveAsBaseTerminal (ec, false);
3051 // TODO: Same problem as in class.cs, TypeTerminal does not
3052 // always do all necessary checks
3053 ObsoleteAttribute oa = AttributeTester.GetObsoleteAttribute (left.Type);
3054 if (oa != null && !ec.IsInObsoleteScope) {
3055 AttributeTester.Report_ObsoleteMessage (oa, left.GetSignatureForError (), loc);
3058 GenericTypeExpr ct = left as GenericTypeExpr;
3059 if (ct != null && !ct.CheckConstraints (ec))
3064 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3072 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3075 return ResolveExtensionMemberAccess (left);
3078 InstanceExpression = left;
3082 protected virtual MemberExpr ResolveExtensionMemberAccess (Expression left)
3084 error176 (loc, GetSignatureForError ());
3088 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3093 if (InstanceExpression == EmptyExpression.Null) {
3094 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3098 if (TypeManager.IsValueType (InstanceExpression.Type)) {
3099 if (InstanceExpression is IMemoryLocation) {
3100 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
3102 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
3103 InstanceExpression.Emit (ec);
3105 t.AddressOf (ec, AddressOp.Store);
3108 InstanceExpression.Emit (ec);
3110 if (prepare_for_load)
3111 ec.ig.Emit (OpCodes.Dup);
3114 public virtual void SetTypeArguments (TypeArguments ta)
3116 // TODO: need to get correct member type
3117 Report.Error (307, loc, "The property `{0}' cannot be used with type arguments",
3118 GetSignatureForError ());
3123 /// Represents group of extension methods
3125 public class ExtensionMethodGroupExpr : MethodGroupExpr
3127 readonly NamespaceEntry namespace_entry;
3128 public Expression ExtensionExpression;
3129 Argument extension_argument;
3131 public ExtensionMethodGroupExpr (ArrayList list, NamespaceEntry n, Type extensionType, Location l)
3132 : base (list, extensionType, l)
3134 this.namespace_entry = n;
3137 public override bool IsStatic {
3138 get { return true; }
3141 public bool IsTopLevel {
3142 get { return namespace_entry == null; }
3145 public override void EmitArguments (EmitContext ec, ArrayList arguments)
3147 if (arguments == null)
3148 arguments = new ArrayList (1);
3149 arguments.Insert (0, extension_argument);
3150 base.EmitArguments (ec, arguments);
3153 public override void EmitCall (EmitContext ec, ArrayList arguments)
3155 if (arguments == null)
3156 arguments = new ArrayList (1);
3157 arguments.Insert (0, extension_argument);
3158 base.EmitCall (ec, arguments);
3161 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3163 extension_argument.Expr.MutateHoistedGenericType (storey);
3164 base.MutateHoistedGenericType (storey);
3167 public override MethodGroupExpr OverloadResolve (EmitContext ec, ref ArrayList arguments, bool may_fail, Location loc)
3169 if (arguments == null)
3170 arguments = new ArrayList (1);
3172 arguments.Insert (0, new Argument (ExtensionExpression));
3173 MethodGroupExpr mg = ResolveOverloadExtensions (ec, arguments, namespace_entry, loc);
3175 // Store resolved argument and restore original arguments
3177 ((ExtensionMethodGroupExpr)mg).extension_argument = (Argument)arguments [0];
3178 arguments.RemoveAt (0);
3183 MethodGroupExpr ResolveOverloadExtensions (EmitContext ec, ArrayList arguments, NamespaceEntry ns, Location loc)
3185 // Use normal resolve rules
3186 MethodGroupExpr mg = base.OverloadResolve (ec, ref arguments, ns != null, loc);
3194 ExtensionMethodGroupExpr e = ns.LookupExtensionMethod (type, null, Name, loc);
3196 return base.OverloadResolve (ec, ref arguments, false, loc);
3198 e.ExtensionExpression = ExtensionExpression;
3199 e.SetTypeArguments (type_arguments);
3200 return e.ResolveOverloadExtensions (ec, arguments, e.namespace_entry, loc);
3205 /// MethodGroupExpr represents a group of method candidates which
3206 /// can be resolved to the best method overload
3208 public class MethodGroupExpr : MemberExpr
3210 public interface IErrorHandler
3212 bool AmbiguousCall (MethodBase ambiguous);
3213 bool NoExactMatch (EmitContext ec, MethodBase method);
3216 public IErrorHandler CustomErrorHandler;
3217 public MethodBase [] Methods;
3218 MethodBase best_candidate;
3219 // TODO: make private
3220 public TypeArguments type_arguments;
3221 bool identical_type_name;
3222 bool has_inaccessible_candidates_only;
3225 public MethodGroupExpr (MemberInfo [] mi, Type type, Location l)
3228 Methods = new MethodBase [mi.Length];
3229 mi.CopyTo (Methods, 0);
3232 public MethodGroupExpr (MemberInfo[] mi, Type type, Location l, bool inacessibleCandidatesOnly)
3233 : this (mi, type, l)
3235 has_inaccessible_candidates_only = inacessibleCandidatesOnly;
3238 public MethodGroupExpr (ArrayList list, Type type, Location l)
3242 Methods = (MethodBase[])list.ToArray (typeof (MethodBase));
3244 foreach (MemberInfo m in list){
3245 if (!(m is MethodBase)){
3246 Console.WriteLine ("Name " + m.Name);
3247 Console.WriteLine ("Found a: " + m.GetType ().FullName);
3256 protected MethodGroupExpr (Type type, Location loc)
3259 eclass = ExprClass.MethodGroup;
3263 public override Type DeclaringType {
3266 // We assume that the top-level type is in the end
3268 return Methods [Methods.Length - 1].DeclaringType;
3269 //return Methods [0].DeclaringType;
3273 public Type DelegateType {
3275 delegate_type = value;
3279 public bool IdenticalTypeName {
3281 return identical_type_name;
3285 public override string GetSignatureForError ()
3287 if (best_candidate != null)
3288 return TypeManager.CSharpSignature (best_candidate);
3290 return TypeManager.CSharpSignature (Methods [0]);
3293 public override string Name {
3295 return Methods [0].Name;
3299 public override bool IsInstance {
3301 if (best_candidate != null)
3302 return !best_candidate.IsStatic;
3304 foreach (MethodBase mb in Methods)
3312 public override bool IsStatic {
3314 if (best_candidate != null)
3315 return best_candidate.IsStatic;
3317 foreach (MethodBase mb in Methods)
3325 public static explicit operator ConstructorInfo (MethodGroupExpr mg)
3327 return (ConstructorInfo)mg.best_candidate;
3330 public static explicit operator MethodInfo (MethodGroupExpr mg)
3332 return (MethodInfo)mg.best_candidate;
3336 // 7.4.3.3 Better conversion from expression
3337 // Returns : 1 if a->p is better,
3338 // 2 if a->q is better,
3339 // 0 if neither is better
3341 static int BetterExpressionConversion (EmitContext ec, Argument a, Type p, Type q)
3343 Type argument_type = TypeManager.TypeToCoreType (a.Type);
3344 if (argument_type == TypeManager.anonymous_method_type && RootContext.Version > LanguageVersion.ISO_2) {
3346 // Uwrap delegate from Expression<T>
3348 if (TypeManager.DropGenericTypeArguments (p) == TypeManager.expression_type) {
3349 p = TypeManager.GetTypeArguments (p) [0];
3351 if (TypeManager.DropGenericTypeArguments (q) == TypeManager.expression_type) {
3352 q = TypeManager.GetTypeArguments (q) [0];
3355 p = Delegate.GetInvokeMethod (null, p).ReturnType;
3356 q = Delegate.GetInvokeMethod (null, q).ReturnType;
3357 if (p == TypeManager.void_type && q != TypeManager.void_type)
3359 if (q == TypeManager.void_type && p != TypeManager.void_type)
3362 if (argument_type == p)
3365 if (argument_type == q)
3369 return BetterTypeConversion (ec, p, q);
3373 // 7.4.3.4 Better conversion from type
3375 public static int BetterTypeConversion (EmitContext ec, Type p, Type q)
3377 if (p == null || q == null)
3378 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3380 if (p == TypeManager.int32_type) {
3381 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3383 } else if (p == TypeManager.int64_type) {
3384 if (q == TypeManager.uint64_type)
3386 } else if (p == TypeManager.sbyte_type) {
3387 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3388 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3390 } else if (p == TypeManager.short_type) {
3391 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3392 q == TypeManager.uint64_type)
3396 if (q == TypeManager.int32_type) {
3397 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3399 } if (q == TypeManager.int64_type) {
3400 if (p == TypeManager.uint64_type)
3402 } else if (q == TypeManager.sbyte_type) {
3403 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3404 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3406 } if (q == TypeManager.short_type) {
3407 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3408 p == TypeManager.uint64_type)
3412 // TODO: this is expensive
3413 Expression p_tmp = new EmptyExpression (p);
3414 Expression q_tmp = new EmptyExpression (q);
3416 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3417 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3419 if (p_to_q && !q_to_p)
3422 if (q_to_p && !p_to_q)
3429 /// Determines "Better function" between candidate
3430 /// and the current best match
3433 /// Returns a boolean indicating :
3434 /// false if candidate ain't better
3435 /// true if candidate is better than the current best match
3437 static bool BetterFunction (EmitContext ec, ArrayList args, int argument_count,
3438 MethodBase candidate, bool candidate_params,
3439 MethodBase best, bool best_params)
3441 AParametersCollection candidate_pd = TypeManager.GetParameterData (candidate);
3442 AParametersCollection best_pd = TypeManager.GetParameterData (best);
3444 bool better_at_least_one = false;
3446 for (int j = 0, c_idx = 0, b_idx = 0; j < argument_count; ++j, ++c_idx, ++b_idx)
3448 Argument a = (Argument) args [j];
3450 Type ct = candidate_pd.Types [c_idx];
3451 Type bt = best_pd.Types [b_idx];
3453 if (candidate_params && candidate_pd.FixedParameters [c_idx].ModFlags == Parameter.Modifier.PARAMS)
3455 ct = TypeManager.GetElementType (ct);
3459 if (best_params && best_pd.FixedParameters [b_idx].ModFlags == Parameter.Modifier.PARAMS)
3461 bt = TypeManager.GetElementType (bt);
3469 int result = BetterExpressionConversion (ec, a, ct, bt);
3471 // for each argument, the conversion to 'ct' should be no worse than
3472 // the conversion to 'bt'.
3476 // for at least one argument, the conversion to 'ct' should be better than
3477 // the conversion to 'bt'.
3479 better_at_least_one = true;
3482 if (better_at_least_one)
3486 // This handles the case
3488 // Add (float f1, float f2, float f3);
3489 // Add (params decimal [] foo);
3491 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3492 // first candidate would've chosen as better.
3498 // The two methods have equal parameter types. Now apply tie-breaking rules
3500 if (TypeManager.IsGenericMethod (best)) {
3501 if (!TypeManager.IsGenericMethod (candidate))
3503 } else if (TypeManager.IsGenericMethod (candidate)) {
3508 // This handles the following cases:
3510 // Trim () is better than Trim (params char[] chars)
3511 // Concat (string s1, string s2, string s3) is better than
3512 // Concat (string s1, params string [] srest)
3513 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3515 if (!candidate_params && best_params)
3517 if (candidate_params && !best_params)
3520 int candidate_param_count = candidate_pd.Count;
3521 int best_param_count = best_pd.Count;
3523 if (candidate_param_count != best_param_count)
3524 // can only happen if (candidate_params && best_params)
3525 return candidate_param_count > best_param_count;
3528 // now, both methods have the same number of parameters, and the parameters have the same types
3529 // Pick the "more specific" signature
3532 MethodBase orig_candidate = TypeManager.DropGenericMethodArguments (candidate);
3533 MethodBase orig_best = TypeManager.DropGenericMethodArguments (best);
3535 AParametersCollection orig_candidate_pd = TypeManager.GetParameterData (orig_candidate);
3536 AParametersCollection orig_best_pd = TypeManager.GetParameterData (orig_best);
3538 bool specific_at_least_once = false;
3539 for (int j = 0; j < candidate_param_count; ++j)
3541 Type ct = orig_candidate_pd.Types [j];
3542 Type bt = orig_best_pd.Types [j];
3545 Type specific = MoreSpecific (ct, bt);
3549 specific_at_least_once = true;
3552 if (specific_at_least_once)
3555 // FIXME: handle lifted operators
3561 protected override MemberExpr ResolveExtensionMemberAccess (Expression left)
3564 return base.ResolveExtensionMemberAccess (left);
3567 // When left side is an expression and at least one candidate method is
3568 // static, it can be extension method
3570 InstanceExpression = left;
3574 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3575 SimpleName original)
3577 if (!(left is TypeExpr) &&
3578 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3579 identical_type_name = true;
3581 return base.ResolveMemberAccess (ec, left, loc, original);
3584 public override Expression CreateExpressionTree (EmitContext ec)
3586 if (best_candidate == null) {
3587 Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3591 if (best_candidate.IsConstructor)
3592 return new TypeOfConstructorInfo (best_candidate, loc);
3594 IMethodData md = TypeManager.GetMethod (best_candidate);
3595 if (md != null && md.IsExcluded ())
3596 Report.Error (765, loc,
3597 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3599 return new TypeOfMethodInfo (best_candidate, loc);
3602 override public Expression DoResolve (EmitContext ec)
3604 if (InstanceExpression != null) {
3605 InstanceExpression = InstanceExpression.DoResolve (ec);
3606 if (InstanceExpression == null)
3613 public void ReportUsageError ()
3615 Report.Error (654, loc, "Method `" + DeclaringType + "." +
3616 Name + "()' is referenced without parentheses");
3619 override public void Emit (EmitContext ec)
3621 ReportUsageError ();
3624 public virtual void EmitArguments (EmitContext ec, ArrayList arguments)
3626 Invocation.EmitArguments (ec, arguments, false, null);
3629 public virtual void EmitCall (EmitContext ec, ArrayList arguments)
3631 Invocation.EmitCall (ec, IsBase, InstanceExpression, best_candidate, arguments, loc);
3634 void Error_AmbiguousCall (MethodBase ambiguous)
3636 if (CustomErrorHandler != null && CustomErrorHandler.AmbiguousCall (ambiguous))
3639 Report.SymbolRelatedToPreviousError (best_candidate);
3640 Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
3641 TypeManager.CSharpSignature (ambiguous), TypeManager.CSharpSignature (best_candidate));
3644 protected virtual void Error_InvalidArguments (EmitContext ec, Location loc, int idx, MethodBase method,
3645 Argument a, AParametersCollection expected_par, Type paramType)
3647 ExtensionMethodGroupExpr emg = this as ExtensionMethodGroupExpr;
3649 if (a is CollectionElementInitializer.ElementInitializerArgument) {
3650 Report.SymbolRelatedToPreviousError (method);
3651 if ((expected_par.FixedParameters [idx].ModFlags & Parameter.Modifier.ISBYREF) != 0) {
3652 Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
3653 TypeManager.CSharpSignature (method));
3656 Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
3657 TypeManager.CSharpSignature (method));
3658 } else if (TypeManager.IsDelegateType (method.DeclaringType)) {
3659 Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
3660 TypeManager.CSharpName (method.DeclaringType));
3662 Report.SymbolRelatedToPreviousError (method);
3664 Report.Error (1928, loc,
3665 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3666 emg.ExtensionExpression.GetSignatureForError (),
3667 emg.Name, TypeManager.CSharpSignature (method));
3669 Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
3670 TypeManager.CSharpSignature (method));
3674 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters [idx].ModFlags;
3676 string index = (idx + 1).ToString ();
3677 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
3678 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
3679 if ((mod & Parameter.Modifier.ISBYREF) == 0)
3680 Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
3681 index, Parameter.GetModifierSignature (a.Modifier));
3683 Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
3684 index, Parameter.GetModifierSignature (mod));
3686 string p1 = a.GetSignatureForError ();
3687 string p2 = TypeManager.CSharpName (paramType);
3690 Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
3691 Report.SymbolRelatedToPreviousError (a.Expr.Type);
3692 Report.SymbolRelatedToPreviousError (paramType);
3695 if (idx == 0 && emg != null) {
3696 Report.Error (1929, loc,
3697 "Extension method instance type `{0}' cannot be converted to `{1}'", p1, p2);
3699 Report.Error (1503, loc,
3700 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
3705 public override void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl)
3707 Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3708 Name, TypeManager.CSharpName (target));
3711 void Error_ArgumentCountWrong (int arg_count)
3713 Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
3714 Name, arg_count.ToString ());
3717 protected virtual int GetApplicableParametersCount (MethodBase method, AParametersCollection parameters)
3719 return parameters.Count;
3722 public static bool IsAncestralType (Type first_type, Type second_type)
3724 return first_type != second_type &&
3725 (TypeManager.IsSubclassOf (second_type, first_type) ||
3726 TypeManager.ImplementsInterface (second_type, first_type));
3730 /// Determines if the candidate method is applicable (section 14.4.2.1)
3731 /// to the given set of arguments
3732 /// A return value rates candidate method compatibility,
3733 /// 0 = the best, int.MaxValue = the worst
3735 public int IsApplicable (EmitContext ec,
3736 ArrayList arguments, int arg_count, ref MethodBase method, ref bool params_expanded_form)
3738 MethodBase candidate = method;
3740 AParametersCollection pd = TypeManager.GetParameterData (candidate);
3741 int param_count = GetApplicableParametersCount (candidate, pd);
3743 if (arg_count != param_count) {
3745 return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
3746 if (arg_count < param_count - 1)
3747 return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
3749 // Initialize expanded form of a method with 1 params parameter
3750 params_expanded_form = param_count == 1 && pd.HasParams;
3755 // 1. Handle generic method using type arguments when specified or type inference
3757 if (TypeManager.IsGenericMethod (candidate)) {
3758 if (type_arguments != null) {
3759 Type [] g_args = candidate.GetGenericArguments ();
3760 if (g_args.Length != type_arguments.Count)
3761 return int.MaxValue - 20000 + Math.Abs (type_arguments.Count - g_args.Length);
3763 // TODO: Don't create new method, create Parameters only
3764 method = ((MethodInfo) candidate).MakeGenericMethod (type_arguments.Arguments);
3766 pd = TypeManager.GetParameterData (candidate);
3768 int score = TypeManager.InferTypeArguments (ec, arguments, ref candidate);
3770 return score - 20000;
3772 if (TypeManager.IsGenericMethodDefinition (candidate))
3773 throw new InternalErrorException ("A generic method `{0}' definition took part in overload resolution",
3774 TypeManager.CSharpSignature (candidate));
3776 pd = TypeManager.GetParameterData (candidate);
3779 if (type_arguments != null)
3780 return int.MaxValue - 15000;
3785 // 2. Each argument has to be implicitly convertible to method parameter
3788 Parameter.Modifier p_mod = 0;
3790 for (int i = 0; i < arg_count; i++) {
3791 Argument a = (Argument) arguments [i];
3792 Parameter.Modifier a_mod = a.Modifier &
3793 ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3795 if (p_mod != Parameter.Modifier.PARAMS) {
3796 p_mod = pd.FixedParameters [i].ModFlags & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3798 if (p_mod == Parameter.Modifier.ARGLIST) {
3799 if (a.Type == TypeManager.runtime_argument_handle_type)
3807 params_expanded_form = true;
3811 if (!params_expanded_form)
3812 score = IsArgumentCompatible (ec, a_mod, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
3814 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && delegate_type == null) {
3815 // It can be applicable in expanded form
3816 score = IsArgumentCompatible (ec, a_mod, a, 0, TypeManager.GetElementType (pt));
3818 params_expanded_form = true;
3822 if (params_expanded_form)
3824 return (arg_count - i) * 2 + score;
3828 if (arg_count != param_count)
3829 params_expanded_form = true;
3834 int IsArgumentCompatible (EmitContext ec, Parameter.Modifier arg_mod, Argument argument, Parameter.Modifier param_mod, Type parameter)
3837 // Types have to be identical when ref or out modifer is used
3839 if (arg_mod != 0 || param_mod != 0) {
3840 if (TypeManager.HasElementType (parameter))
3841 parameter = TypeManager.GetElementType (parameter);
3843 Type a_type = argument.Type;
3844 if (TypeManager.HasElementType (a_type))
3845 a_type = TypeManager.GetElementType (a_type);
3847 if (a_type != parameter)
3850 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter))
3854 if (arg_mod != param_mod)
3860 public static bool IsOverride (MethodBase cand_method, MethodBase base_method)
3862 if (!IsAncestralType (base_method.DeclaringType, cand_method.DeclaringType))
3865 AParametersCollection cand_pd = TypeManager.GetParameterData (cand_method);
3866 AParametersCollection base_pd = TypeManager.GetParameterData (base_method);
3868 if (cand_pd.Count != base_pd.Count)
3871 for (int j = 0; j < cand_pd.Count; ++j)
3873 Parameter.Modifier cm = cand_pd.FixedParameters [j].ModFlags;
3874 Parameter.Modifier bm = base_pd.FixedParameters [j].ModFlags;
3875 Type ct = cand_pd.Types [j];
3876 Type bt = base_pd.Types [j];
3878 if (cm != bm || ct != bt)
3885 public static MethodGroupExpr MakeUnionSet (MethodGroupExpr mg1, MethodGroupExpr mg2, Location loc)
3896 ArrayList all = new ArrayList (mg1.Methods);
3897 foreach (MethodBase m in mg2.Methods){
3898 if (!TypeManager.ArrayContainsMethod (mg1.Methods, m, false))
3902 return new MethodGroupExpr (all, null, loc);
3905 static Type MoreSpecific (Type p, Type q)
3907 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
3909 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
3912 if (TypeManager.HasElementType (p))
3914 Type pe = TypeManager.GetElementType (p);
3915 Type qe = TypeManager.GetElementType (q);
3916 Type specific = MoreSpecific (pe, qe);
3922 else if (TypeManager.IsGenericType (p))
3924 Type[] pargs = TypeManager.GetTypeArguments (p);
3925 Type[] qargs = TypeManager.GetTypeArguments (q);
3927 bool p_specific_at_least_once = false;
3928 bool q_specific_at_least_once = false;
3930 for (int i = 0; i < pargs.Length; i++)
3932 Type specific = MoreSpecific (pargs [i], qargs [i]);
3933 if (specific == pargs [i])
3934 p_specific_at_least_once = true;
3935 if (specific == qargs [i])
3936 q_specific_at_least_once = true;
3939 if (p_specific_at_least_once && !q_specific_at_least_once)
3941 if (!p_specific_at_least_once && q_specific_at_least_once)
3948 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3950 base.MutateHoistedGenericType (storey);
3952 MethodInfo mi = best_candidate as MethodInfo;
3954 best_candidate = storey.MutateGenericMethod (mi);
3958 best_candidate = storey.MutateConstructor ((ConstructorInfo) this);
3962 /// Find the Applicable Function Members (7.4.2.1)
3964 /// me: Method Group expression with the members to select.
3965 /// it might contain constructors or methods (or anything
3966 /// that maps to a method).
3968 /// Arguments: ArrayList containing resolved Argument objects.
3970 /// loc: The location if we want an error to be reported, or a Null
3971 /// location for "probing" purposes.
3973 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3974 /// that is the best match of me on Arguments.
3977 public virtual MethodGroupExpr OverloadResolve (EmitContext ec, ref ArrayList Arguments,
3978 bool may_fail, Location loc)
3980 bool method_params = false;
3981 Type applicable_type = null;
3983 ArrayList candidates = new ArrayList (2);
3984 ArrayList candidate_overrides = null;
3987 // Used to keep a map between the candidate
3988 // and whether it is being considered in its
3989 // normal or expanded form
3991 // false is normal form, true is expanded form
3993 Hashtable candidate_to_form = null;
3995 if (Arguments != null)
3996 arg_count = Arguments.Count;
3998 if (RootContext.Version == LanguageVersion.ISO_1 && Name == "Invoke" && TypeManager.IsDelegateType (DeclaringType)) {
4000 Report.Error (1533, loc, "Invoke cannot be called directly on a delegate");
4004 int nmethods = Methods.Length;
4008 // Methods marked 'override' don't take part in 'applicable_type'
4009 // computation, nor in the actual overload resolution.
4010 // However, they still need to be emitted instead of a base virtual method.
4011 // So, we salt them away into the 'candidate_overrides' array.
4013 // In case of reflected methods, we replace each overriding method with
4014 // its corresponding base virtual method. This is to improve compatibility
4015 // with non-C# libraries which change the visibility of overrides (#75636)
4018 for (int i = 0; i < Methods.Length; ++i) {
4019 MethodBase m = Methods [i];
4020 if (TypeManager.IsOverride (m)) {
4021 if (candidate_overrides == null)
4022 candidate_overrides = new ArrayList ();
4023 candidate_overrides.Add (m);
4024 m = TypeManager.TryGetBaseDefinition (m);
4033 // Enable message recording, it's used mainly by lambda expressions
4035 Report.IMessageRecorder msg_recorder = new Report.MessageRecorder ();
4036 Report.IMessageRecorder prev_recorder = Report.SetMessageRecorder (msg_recorder);
4039 // First we construct the set of applicable methods
4041 bool is_sorted = true;
4042 int best_candidate_rate = int.MaxValue;
4043 for (int i = 0; i < nmethods; i++) {
4044 Type decl_type = Methods [i].DeclaringType;
4047 // If we have already found an applicable method
4048 // we eliminate all base types (Section 14.5.5.1)
4050 if (applicable_type != null && IsAncestralType (decl_type, applicable_type))
4054 // Check if candidate is applicable (section 14.4.2.1)
4056 bool params_expanded_form = false;
4057 int candidate_rate = IsApplicable (ec, Arguments, arg_count, ref Methods [i], ref params_expanded_form);
4059 if (candidate_rate < best_candidate_rate) {
4060 best_candidate_rate = candidate_rate;
4061 best_candidate = Methods [i];
4064 if (params_expanded_form) {
4065 if (candidate_to_form == null)
4066 candidate_to_form = new PtrHashtable ();
4067 MethodBase candidate = Methods [i];
4068 candidate_to_form [candidate] = candidate;
4071 if (candidate_rate != 0 || has_inaccessible_candidates_only) {
4072 if (msg_recorder != null)
4073 msg_recorder.EndSession ();
4077 msg_recorder = null;
4078 candidates.Add (Methods [i]);
4080 if (applicable_type == null)
4081 applicable_type = decl_type;
4082 else if (applicable_type != decl_type) {
4084 if (IsAncestralType (applicable_type, decl_type))
4085 applicable_type = decl_type;
4089 Report.SetMessageRecorder (prev_recorder);
4090 if (msg_recorder != null && !msg_recorder.IsEmpty) {
4092 msg_recorder.PrintMessages ();
4097 int candidate_top = candidates.Count;
4099 if (applicable_type == null) {
4101 // When we found a top level method which does not match and it's
4102 // not an extension method. We start extension methods lookup from here
4104 if (InstanceExpression != null) {
4105 ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (type, Name, loc);
4106 if (ex_method_lookup != null) {
4107 ex_method_lookup.ExtensionExpression = InstanceExpression;
4108 ex_method_lookup.SetTypeArguments (type_arguments);
4109 return ex_method_lookup.OverloadResolve (ec, ref Arguments, may_fail, loc);
4117 // Okay so we have failed to find exact match so we
4118 // return error info about the closest match
4120 if (best_candidate != null) {
4121 if (CustomErrorHandler != null && CustomErrorHandler.NoExactMatch (ec, best_candidate))
4124 AParametersCollection pd = TypeManager.GetParameterData (best_candidate);
4125 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4126 if (arg_count == pd.Count || pd.HasParams) {
4127 if (TypeManager.IsGenericMethodDefinition (best_candidate)) {
4128 if (type_arguments == null) {
4129 Report.Error (411, loc,
4130 "The type arguments for method `{0}' cannot be inferred from " +
4131 "the usage. Try specifying the type arguments explicitly",
4132 TypeManager.CSharpSignature (best_candidate));
4136 Type[] g_args = TypeManager.GetGenericArguments (best_candidate);
4137 if (type_arguments.Count != g_args.Length) {
4138 Report.SymbolRelatedToPreviousError (best_candidate);
4139 Report.Error (305, loc, "Using the generic method `{0}' requires `{1}' type argument(s)",
4140 TypeManager.CSharpSignature (best_candidate),
4141 g_args.Length.ToString ());
4145 if (type_arguments != null && !TypeManager.IsGenericMethod (best_candidate)) {
4146 Namespace.Error_TypeArgumentsCannotBeUsed (best_candidate, loc);
4151 if (has_inaccessible_candidates_only) {
4152 if (InstanceExpression != null && type != ec.ContainerType && TypeManager.IsNestedFamilyAccessible (ec.ContainerType, best_candidate.DeclaringType)) {
4153 // Although a derived class can access protected members of
4154 // its base class it cannot do so through an instance of the
4155 // base class (CS1540). If the qualifier_type is a base of the
4156 // ec.ContainerType and the lookup succeeds with the latter one,
4157 // then we are in this situation.
4158 Error_CannotAccessProtected (loc, best_candidate, type, ec.ContainerType);
4160 Report.SymbolRelatedToPreviousError (best_candidate);
4161 ErrorIsInaccesible (loc, GetSignatureForError ());
4165 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate, cand_params, may_fail, loc))
4168 if (has_inaccessible_candidates_only)
4171 throw new InternalErrorException ("VerifyArgumentsCompat didn't find any problem with rejected candidate " + best_candidate);
4176 // We failed to find any method with correct argument count
4178 if (Name == ConstructorInfo.ConstructorName) {
4179 Report.SymbolRelatedToPreviousError (type);
4180 Report.Error (1729, loc,
4181 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4182 TypeManager.CSharpName (type), arg_count);
4184 Error_ArgumentCountWrong (arg_count);
4192 // At this point, applicable_type is _one_ of the most derived types
4193 // in the set of types containing the methods in this MethodGroup.
4194 // Filter the candidates so that they only contain methods from the
4195 // most derived types.
4198 int finalized = 0; // Number of finalized candidates
4201 // Invariant: applicable_type is a most derived type
4203 // We'll try to complete Section 14.5.5.1 for 'applicable_type' by
4204 // eliminating all it's base types. At the same time, we'll also move
4205 // every unrelated type to the end of the array, and pick the next
4206 // 'applicable_type'.
4208 Type next_applicable_type = null;
4209 int j = finalized; // where to put the next finalized candidate
4210 int k = finalized; // where to put the next undiscarded candidate
4211 for (int i = finalized; i < candidate_top; ++i) {
4212 MethodBase candidate = (MethodBase) candidates [i];
4213 Type decl_type = candidate.DeclaringType;
4215 if (decl_type == applicable_type) {
4216 candidates [k++] = candidates [j];
4217 candidates [j++] = candidates [i];
4221 if (IsAncestralType (decl_type, applicable_type))
4224 if (next_applicable_type != null &&
4225 IsAncestralType (decl_type, next_applicable_type))
4228 candidates [k++] = candidates [i];
4230 if (next_applicable_type == null ||
4231 IsAncestralType (next_applicable_type, decl_type))
4232 next_applicable_type = decl_type;
4235 applicable_type = next_applicable_type;
4238 } while (applicable_type != null);
4242 // Now we actually find the best method
4245 best_candidate = (MethodBase) candidates [0];
4246 method_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4248 for (int ix = 1; ix < candidate_top; ix++) {
4249 MethodBase candidate = (MethodBase) candidates [ix];
4251 if (candidate == best_candidate)
4254 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4256 if (BetterFunction (ec, Arguments, arg_count,
4257 candidate, cand_params,
4258 best_candidate, method_params)) {
4259 best_candidate = candidate;
4260 method_params = cand_params;
4264 // Now check that there are no ambiguities i.e the selected method
4265 // should be better than all the others
4267 MethodBase ambiguous = null;
4268 for (int ix = 1; ix < candidate_top; ix++) {
4269 MethodBase candidate = (MethodBase) candidates [ix];
4271 if (candidate == best_candidate)
4274 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4275 if (!BetterFunction (ec, Arguments, arg_count,
4276 best_candidate, method_params,
4277 candidate, cand_params))
4280 Report.SymbolRelatedToPreviousError (candidate);
4281 ambiguous = candidate;
4285 if (ambiguous != null) {
4286 Error_AmbiguousCall (ambiguous);
4291 // If the method is a virtual function, pick an override closer to the LHS type.
4293 if (!IsBase && best_candidate.IsVirtual) {
4294 if (TypeManager.IsOverride (best_candidate))
4295 throw new InternalErrorException (
4296 "Should not happen. An 'override' method took part in overload resolution: " + best_candidate);
4298 if (candidate_overrides != null) {
4299 Type[] gen_args = null;
4300 bool gen_override = false;
4301 if (TypeManager.IsGenericMethod (best_candidate))
4302 gen_args = TypeManager.GetGenericArguments (best_candidate);
4304 foreach (MethodBase candidate in candidate_overrides) {
4305 if (TypeManager.IsGenericMethod (candidate)) {
4306 if (gen_args == null)
4309 if (gen_args.Length != TypeManager.GetGenericArguments (candidate).Length)
4312 if (gen_args != null)
4316 if (IsOverride (candidate, best_candidate)) {
4317 gen_override = true;
4318 best_candidate = candidate;
4322 if (gen_override && gen_args != null) {
4324 best_candidate = ((MethodInfo) best_candidate).MakeGenericMethod (gen_args);
4331 // And now check if the arguments are all
4332 // compatible, perform conversions if
4333 // necessary etc. and return if everything is
4336 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate,
4337 method_params, may_fail, loc))
4340 if (best_candidate == null)
4343 MethodBase the_method = TypeManager.DropGenericMethodArguments (best_candidate);
4345 if (the_method.IsGenericMethodDefinition &&
4346 !ConstraintChecker.CheckConstraints (ec, the_method, best_candidate, loc))
4351 // Check ObsoleteAttribute on the best method
4353 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (the_method);
4354 if (oa != null && !ec.IsInObsoleteScope)
4355 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc);
4357 IMethodData data = TypeManager.GetMethod (the_method);
4359 data.SetMemberIsUsed ();
4364 public override void SetTypeArguments (TypeArguments ta)
4366 type_arguments = ta;
4369 public bool VerifyArgumentsCompat (EmitContext ec, ref ArrayList arguments,
4370 int arg_count, MethodBase method,
4371 bool chose_params_expanded,
4372 bool may_fail, Location loc)
4374 AParametersCollection pd = TypeManager.GetParameterData (method);
4376 int errors = Report.Errors;
4377 Parameter.Modifier p_mod = 0;
4379 int a_idx = 0, a_pos = 0;
4381 ArrayList params_initializers = null;
4382 bool has_unsafe_arg = false;
4384 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4385 a = (Argument) arguments [a_idx];
4386 if (p_mod != Parameter.Modifier.PARAMS) {
4387 p_mod = pd.FixedParameters [a_idx].ModFlags;
4388 pt = pd.Types [a_idx];
4389 has_unsafe_arg |= pt.IsPointer;
4391 if (p_mod == Parameter.Modifier.ARGLIST) {
4392 if (a.Type != TypeManager.runtime_argument_handle_type)
4397 if (p_mod == Parameter.Modifier.PARAMS) {
4398 if (chose_params_expanded) {
4399 params_initializers = new ArrayList (arg_count - a_idx);
4400 pt = TypeManager.GetElementType (pt);
4406 // Types have to be identical when ref or out modifer is used
4408 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4409 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4412 if (!TypeManager.IsEqual (a.Expr.Type, pt))
4418 if (delegate_type != null && !Delegate.IsTypeCovariant (a.Expr, pt))
4421 Expression conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4426 // Convert params arguments to an array initializer
4428 if (params_initializers != null) {
4429 // we choose to use 'a.Expr' rather than 'conv' so that
4430 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
4431 params_initializers.Add (a.Expr);
4432 arguments.RemoveAt (a_idx--);
4437 // Update the argument with the implicit conversion
4441 if (a_idx != arg_count) {
4442 if (!may_fail && Report.Errors == errors) {
4443 if (CustomErrorHandler != null)
4444 CustomErrorHandler.NoExactMatch (ec, best_candidate);
4446 Error_InvalidArguments (ec, loc, a_pos, method, a, pd, pt);
4452 // Fill not provided arguments required by params modifier
4454 int param_count = GetApplicableParametersCount (method, pd);
4455 if (params_initializers == null && pd.HasParams && arg_count + 1 == param_count) {
4456 if (arguments == null)
4457 arguments = new ArrayList (1);
4459 pt = pd.Types [param_count - 1];
4460 pt = TypeManager.GetElementType (pt);
4461 has_unsafe_arg |= pt.IsPointer;
4462 params_initializers = new ArrayList (0);
4466 // Append an array argument with all params arguments
4468 if (params_initializers != null) {
4469 arguments.Add (new Argument (
4470 new ArrayCreation (new TypeExpression (pt, loc), "[]",
4471 params_initializers, loc).Resolve (ec)));
4475 if (arg_count < param_count) {
4477 Error_ArgumentCountWrong (arg_count);
4481 if (has_unsafe_arg && !ec.InUnsafe) {
4491 public class ConstantExpr : MemberExpr
4495 public ConstantExpr (FieldInfo constant, Location loc)
4497 this.constant = constant;
4501 public override string Name {
4502 get { throw new NotImplementedException (); }
4505 public override bool IsInstance {
4506 get { return !IsStatic; }
4509 public override bool IsStatic {
4510 get { return constant.IsStatic; }
4513 public override Type DeclaringType {
4514 get { return constant.DeclaringType; }
4517 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc, SimpleName original)
4519 constant = TypeManager.GetGenericFieldDefinition (constant);
4521 IConstant ic = TypeManager.GetConstant (constant);
4523 if (constant.IsLiteral) {
4524 ic = new ExternalConstant (constant);
4526 ic = ExternalConstant.CreateDecimal (constant);
4527 // HACK: decimal field was not resolved as constant
4529 return new FieldExpr (constant, loc).ResolveMemberAccess (ec, left, loc, original);
4531 TypeManager.RegisterConstant (constant, ic);
4534 return base.ResolveMemberAccess (ec, left, loc, original);
4537 public override Expression CreateExpressionTree (EmitContext ec)
4539 throw new NotSupportedException ("ET");
4542 public override Expression DoResolve (EmitContext ec)
4544 IConstant ic = TypeManager.GetConstant (constant);
4545 if (ic.ResolveValue ()) {
4546 if (!ec.IsInObsoleteScope)
4547 ic.CheckObsoleteness (loc);
4550 return ic.CreateConstantReference (loc);
4553 public override void Emit (EmitContext ec)
4555 throw new NotSupportedException ();
4558 public override string GetSignatureForError ()
4560 return TypeManager.GetFullNameSignature (constant);
4565 /// Fully resolved expression that evaluates to a Field
4567 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariableReference {
4568 public FieldInfo FieldInfo;
4569 readonly Type constructed_generic_type;
4570 VariableInfo variable_info;
4572 LocalTemporary temp;
4575 protected FieldExpr (Location l)
4580 public FieldExpr (FieldInfo fi, Location l)
4583 type = TypeManager.TypeToCoreType (fi.FieldType);
4587 public FieldExpr (FieldInfo fi, Type genericType, Location l)
4590 if (TypeManager.IsGenericTypeDefinition (genericType))
4592 this.constructed_generic_type = genericType;
4595 public override string Name {
4597 return FieldInfo.Name;
4601 public override bool IsInstance {
4603 return !FieldInfo.IsStatic;
4607 public override bool IsStatic {
4609 return FieldInfo.IsStatic;
4613 public override Type DeclaringType {
4615 return FieldInfo.DeclaringType;
4619 public override string GetSignatureForError ()
4621 return TypeManager.GetFullNameSignature (FieldInfo);
4624 public VariableInfo VariableInfo {
4626 return variable_info;
4630 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
4631 SimpleName original)
4633 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
4634 Type t = fi.FieldType;
4636 if (t.IsPointer && !ec.InUnsafe) {
4640 return base.ResolveMemberAccess (ec, left, loc, original);
4643 public void SetHasAddressTaken ()
4645 IVariableReference vr = InstanceExpression as IVariableReference;
4647 vr.SetHasAddressTaken ();
4650 public override Expression CreateExpressionTree (EmitContext ec)
4652 Expression instance;
4653 if (InstanceExpression == null) {
4654 instance = new NullLiteral (loc);
4656 instance = InstanceExpression.CreateExpressionTree (ec);
4659 ArrayList args = new ArrayList (2);
4660 args.Add (new Argument (instance));
4661 args.Add (new Argument (CreateTypeOfExpression ()));
4662 return CreateExpressionFactoryCall ("Field", args);
4665 public Expression CreateTypeOfExpression ()
4667 return new TypeOfField (GetConstructedFieldInfo (), loc);
4670 override public Expression DoResolve (EmitContext ec)
4672 return DoResolve (ec, false, false);
4675 Expression DoResolve (EmitContext ec, bool lvalue_instance, bool out_access)
4677 if (!FieldInfo.IsStatic){
4678 if (InstanceExpression == null){
4680 // This can happen when referencing an instance field using
4681 // a fully qualified type expression: TypeName.InstanceField = xxx
4683 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4687 // Resolve the field's instance expression while flow analysis is turned
4688 // off: when accessing a field "a.b", we must check whether the field
4689 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4691 if (lvalue_instance) {
4692 using (ec.With (EmitContext.Flags.DoFlowAnalysis, false)) {
4693 Expression right_side =
4694 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4695 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side, loc);
4698 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
4699 InstanceExpression = InstanceExpression.Resolve (ec, rf);
4702 if (InstanceExpression == null)
4705 using (ec.Set (EmitContext.Flags.OmitStructFlowAnalysis)) {
4706 InstanceExpression.CheckMarshalByRefAccess (ec);
4710 // TODO: the code above uses some non-standard multi-resolve rules
4711 if (eclass != ExprClass.Invalid)
4714 if (!ec.IsInObsoleteScope) {
4715 FieldBase f = TypeManager.GetField (FieldInfo);
4717 f.CheckObsoleteness (loc);
4719 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
4721 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
4725 IFixedBuffer fb = AttributeTester.GetFixedBuffer (FieldInfo);
4726 IVariableReference var = InstanceExpression as IVariableReference;
4729 IFixedExpression fe = InstanceExpression as IFixedExpression;
4730 if (!ec.InFixedInitializer && (fe == null || !fe.IsFixed)) {
4731 Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4734 if (InstanceExpression.eclass != ExprClass.Variable) {
4735 Report.SymbolRelatedToPreviousError (FieldInfo);
4736 Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4737 TypeManager.GetFullNameSignature (FieldInfo));
4738 } else if (var != null && var.IsHoisted) {
4739 AnonymousMethodExpression.Error_AddressOfCapturedVar (var, loc);
4742 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4745 eclass = ExprClass.Variable;
4747 // If the instance expression is a local variable or parameter.
4748 if (var == null || var.VariableInfo == null)
4751 VariableInfo vi = var.VariableInfo;
4752 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
4755 variable_info = vi.GetSubStruct (FieldInfo.Name);
4756 eclass = ExprClass.Variable;
4760 static readonly int [] codes = {
4761 191, // instance, write access
4762 192, // instance, out access
4763 198, // static, write access
4764 199, // static, out access
4765 1648, // member of value instance, write access
4766 1649, // member of value instance, out access
4767 1650, // member of value static, write access
4768 1651 // member of value static, out access
4771 static readonly string [] msgs = {
4772 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4773 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4774 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4775 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4776 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4777 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4778 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4779 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4782 // The return value is always null. Returning a value simplifies calling code.
4783 Expression Report_AssignToReadonly (Expression right_side)
4786 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4790 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4792 Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4797 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4799 IVariableReference var = InstanceExpression as IVariableReference;
4800 if (var != null && var.VariableInfo != null)
4801 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
4803 bool lvalue_instance = !FieldInfo.IsStatic && TypeManager.IsValueType (FieldInfo.DeclaringType);
4804 bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
4806 Expression e = DoResolve (ec, lvalue_instance, out_access);
4811 FieldBase fb = TypeManager.GetField (FieldInfo);
4815 if (FieldInfo.IsInitOnly) {
4816 // InitOnly fields can only be assigned in constructors or initializers
4817 if (!ec.IsInFieldInitializer && !ec.IsConstructor)
4818 return Report_AssignToReadonly (right_side);
4820 if (ec.IsConstructor) {
4821 Type ctype = ec.TypeContainer.CurrentType;
4823 ctype = ec.ContainerType;
4825 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4826 if (!TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
4827 return Report_AssignToReadonly (right_side);
4828 // static InitOnly fields cannot be assigned-to in an instance constructor
4829 if (IsStatic && !ec.IsStatic)
4830 return Report_AssignToReadonly (right_side);
4831 // instance constructors can't modify InitOnly fields of other instances of the same type
4832 if (!IsStatic && !(InstanceExpression is This))
4833 return Report_AssignToReadonly (right_side);
4837 if (right_side == EmptyExpression.OutAccess &&
4838 !IsStatic && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type)) {
4839 Report.SymbolRelatedToPreviousError (DeclaringType);
4840 Report.Warning (197, 1, loc,
4841 "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",
4842 GetSignatureForError ());
4845 eclass = ExprClass.Variable;
4849 bool is_marshal_by_ref ()
4851 return !IsStatic && TypeManager.IsStruct (Type) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type);
4854 public override void CheckMarshalByRefAccess (EmitContext ec)
4856 if (is_marshal_by_ref () && !(InstanceExpression is This)) {
4857 Report.SymbolRelatedToPreviousError (DeclaringType);
4858 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",
4859 GetSignatureForError ());
4863 public override int GetHashCode ()
4865 return FieldInfo.GetHashCode ();
4868 public bool IsFixed {
4871 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
4873 IVariableReference variable = InstanceExpression as IVariableReference;
4874 if (variable != null)
4875 return TypeManager.IsStruct (InstanceExpression.Type) && variable.IsFixed;
4877 IFixedExpression fe = InstanceExpression as IFixedExpression;
4878 return fe != null && fe.IsFixed;
4882 public bool IsHoisted {
4884 IVariableReference hv = InstanceExpression as IVariableReference;
4885 return hv != null && hv.IsHoisted;
4889 public override bool Equals (object obj)
4891 FieldExpr fe = obj as FieldExpr;
4895 if (FieldInfo != fe.FieldInfo)
4898 if (InstanceExpression == null || fe.InstanceExpression == null)
4901 return InstanceExpression.Equals (fe.InstanceExpression);
4904 public void Emit (EmitContext ec, bool leave_copy)
4906 ILGenerator ig = ec.ig;
4907 bool is_volatile = false;
4909 FieldBase f = TypeManager.GetField (FieldInfo);
4911 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4914 f.SetMemberIsUsed ();
4917 if (FieldInfo.IsStatic){
4919 ig.Emit (OpCodes.Volatile);
4921 ig.Emit (OpCodes.Ldsfld, GetConstructedFieldInfo ());
4924 EmitInstance (ec, false);
4926 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
4928 ig.Emit (OpCodes.Ldflda, GetConstructedFieldInfo ());
4929 ig.Emit (OpCodes.Ldflda, ff.Element);
4932 ig.Emit (OpCodes.Volatile);
4934 ig.Emit (OpCodes.Ldfld, GetConstructedFieldInfo ());
4939 ec.ig.Emit (OpCodes.Dup);
4940 if (!FieldInfo.IsStatic) {
4941 temp = new LocalTemporary (this.Type);
4947 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4949 FieldAttributes fa = FieldInfo.Attributes;
4950 bool is_static = (fa & FieldAttributes.Static) != 0;
4951 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
4952 ILGenerator ig = ec.ig;
4954 if (is_readonly && !ec.IsConstructor){
4955 Report_AssignToReadonly (source);
4959 prepared = prepare_for_load;
4960 EmitInstance (ec, prepared);
4964 ec.ig.Emit (OpCodes.Dup);
4965 if (!FieldInfo.IsStatic) {
4966 temp = new LocalTemporary (this.Type);
4971 FieldBase f = TypeManager.GetField (FieldInfo);
4973 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4974 ig.Emit (OpCodes.Volatile);
4980 ig.Emit (OpCodes.Stsfld, GetConstructedFieldInfo ());
4982 ig.Emit (OpCodes.Stfld, GetConstructedFieldInfo ());
4991 public override void Emit (EmitContext ec)
4996 public override void EmitSideEffect (EmitContext ec)
4998 FieldBase f = TypeManager.GetField (FieldInfo);
4999 bool is_volatile = f != null && (f.ModFlags & Modifiers.VOLATILE) != 0;
5001 if (is_volatile || is_marshal_by_ref ())
5002 base.EmitSideEffect (ec);
5005 public override void Error_VariableIsUsedBeforeItIsDeclared (string name)
5007 Report.Error (844, loc,
5008 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the field `{1}'",
5009 name, GetSignatureForError ());
5012 public void AddressOf (EmitContext ec, AddressOp mode)
5014 ILGenerator ig = ec.ig;
5016 FieldBase f = TypeManager.GetField (FieldInfo);
5018 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
5019 Report.Warning (420, 1, loc, "`{0}': A volatile field references will not be treated as volatile",
5020 f.GetSignatureForError ());
5023 if ((mode & AddressOp.Store) != 0)
5025 if ((mode & AddressOp.Load) != 0)
5026 f.SetMemberIsUsed ();
5030 // Handle initonly fields specially: make a copy and then
5031 // get the address of the copy.
5034 if (FieldInfo.IsInitOnly){
5036 if (ec.IsConstructor){
5037 if (FieldInfo.IsStatic){
5049 local = ig.DeclareLocal (type);
5050 ig.Emit (OpCodes.Stloc, local);
5051 ig.Emit (OpCodes.Ldloca, local);
5056 if (FieldInfo.IsStatic){
5057 ig.Emit (OpCodes.Ldsflda, GetConstructedFieldInfo ());
5060 EmitInstance (ec, false);
5061 ig.Emit (OpCodes.Ldflda, GetConstructedFieldInfo ());
5065 FieldInfo GetConstructedFieldInfo ()
5067 if (constructed_generic_type == null)
5070 return TypeBuilder.GetField (constructed_generic_type, FieldInfo);
5072 throw new NotSupportedException ();
5076 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5078 FieldInfo = storey.MutateField (FieldInfo);
5079 base.MutateHoistedGenericType (storey);
5085 /// Expression that evaluates to a Property. The Assign class
5086 /// might set the `Value' expression if we are in an assignment.
5088 /// This is not an LValue because we need to re-write the expression, we
5089 /// can not take data from the stack and store it.
5091 public class PropertyExpr : MemberExpr, IAssignMethod {
5092 public readonly PropertyInfo PropertyInfo;
5093 MethodInfo getter, setter;
5098 LocalTemporary temp;
5101 public PropertyExpr (Type container_type, PropertyInfo pi, Location l)
5104 eclass = ExprClass.PropertyAccess;
5108 type = TypeManager.TypeToCoreType (pi.PropertyType);
5110 ResolveAccessors (container_type);
5113 public override string Name {
5115 return PropertyInfo.Name;
5119 public override bool IsInstance {
5125 public override bool IsStatic {
5131 public override Expression CreateExpressionTree (EmitContext ec)
5134 if (IsSingleDimensionalArrayLength ()) {
5135 args = new ArrayList (1);
5136 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5137 return CreateExpressionFactoryCall ("ArrayLength", args);
5141 Error_BaseAccessInExpressionTree (loc);
5145 args = new ArrayList (2);
5146 if (InstanceExpression == null)
5147 args.Add (new Argument (new NullLiteral (loc)));
5149 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5150 args.Add (new Argument (new TypeOfMethodInfo (getter, loc)));
5151 return CreateExpressionFactoryCall ("Property", args);
5154 public Expression CreateSetterTypeOfExpression ()
5156 return new TypeOfMethodInfo (setter, loc);
5159 public override Type DeclaringType {
5161 return PropertyInfo.DeclaringType;
5165 public override string GetSignatureForError ()
5167 return TypeManager.GetFullNameSignature (PropertyInfo);
5170 void FindAccessors (Type invocation_type)
5172 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
5173 BindingFlags.Static | BindingFlags.Instance |
5174 BindingFlags.DeclaredOnly;
5176 Type current = PropertyInfo.DeclaringType;
5177 for (; current != null; current = current.BaseType) {
5178 MemberInfo[] group = TypeManager.MemberLookup (
5179 invocation_type, invocation_type, current,
5180 MemberTypes.Property, flags, PropertyInfo.Name, null);
5185 if (group.Length != 1)
5186 // Oooops, can this ever happen ?
5189 PropertyInfo pi = (PropertyInfo) group [0];
5192 getter = pi.GetGetMethod (true);
5195 setter = pi.GetSetMethod (true);
5197 MethodInfo accessor = getter != null ? getter : setter;
5199 if (!accessor.IsVirtual)
5205 // We also perform the permission checking here, as the PropertyInfo does not
5206 // hold the information for the accessibility of its setter/getter
5208 // TODO: Refactor to use some kind of cache together with GetPropertyFromAccessor
5209 void ResolveAccessors (Type container_type)
5211 FindAccessors (container_type);
5213 if (getter != null) {
5214 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
5215 IMethodData md = TypeManager.GetMethod (the_getter);
5217 md.SetMemberIsUsed ();
5219 is_static = getter.IsStatic;
5222 if (setter != null) {
5223 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
5224 IMethodData md = TypeManager.GetMethod (the_setter);
5226 md.SetMemberIsUsed ();
5228 is_static = setter.IsStatic;
5232 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5234 if (InstanceExpression != null)
5235 InstanceExpression.MutateHoistedGenericType (storey);
5237 type = storey.MutateType (type);
5239 getter = storey.MutateGenericMethod (getter);
5241 setter = storey.MutateGenericMethod (setter);
5244 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
5247 InstanceExpression = null;
5251 if (InstanceExpression == null) {
5252 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5256 InstanceExpression = InstanceExpression.DoResolve (ec);
5257 if (lvalue_instance && InstanceExpression != null)
5258 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
5260 if (InstanceExpression == null)
5263 InstanceExpression.CheckMarshalByRefAccess (ec);
5265 if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) &&
5266 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
5267 !TypeManager.IsNestedChildOf (ec.ContainerType, InstanceExpression.Type) &&
5268 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.ContainerType)) {
5269 Report.SymbolRelatedToPreviousError (PropertyInfo);
5270 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
5277 void Error_PropertyNotFound (MethodInfo mi, bool getter)
5279 // TODO: correctly we should compare arguments but it will lead to bigger changes
5280 if (mi is MethodBuilder) {
5281 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
5285 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
5287 AParametersCollection iparams = TypeManager.GetParameterData (mi);
5288 sig.Append (getter ? "get_" : "set_");
5290 sig.Append (iparams.GetSignatureForError ());
5292 Report.SymbolRelatedToPreviousError (mi);
5293 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
5294 Name, sig.ToString ());
5297 public bool IsAccessibleFrom (Type invocation_type, bool lvalue)
5300 MethodInfo accessor = lvalue ? setter : getter;
5301 if (accessor == null && lvalue)
5303 return accessor != null && IsAccessorAccessible (invocation_type, accessor, out dummy);
5306 bool IsSingleDimensionalArrayLength ()
5308 if (DeclaringType != TypeManager.array_type || getter == null || Name != "Length")
5311 string t_name = InstanceExpression.Type.Name;
5312 int t_name_len = t_name.Length;
5313 return t_name_len > 2 && t_name [t_name_len - 2] == '[';
5316 override public Expression DoResolve (EmitContext ec)
5321 if (getter != null){
5322 if (TypeManager.GetParameterData (getter).Count != 0){
5323 Error_PropertyNotFound (getter, true);
5328 if (getter == null){
5330 // The following condition happens if the PropertyExpr was
5331 // created, but is invalid (ie, the property is inaccessible),
5332 // and we did not want to embed the knowledge about this in
5333 // the caller routine. This only avoids double error reporting.
5338 if (InstanceExpression != EmptyExpression.Null) {
5339 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5340 TypeManager.GetFullNameSignature (PropertyInfo));
5345 bool must_do_cs1540_check = false;
5346 if (getter != null &&
5347 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
5348 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
5349 if (pm != null && pm.HasCustomAccessModifier) {
5350 Report.SymbolRelatedToPreviousError (pm);
5351 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5352 TypeManager.CSharpSignature (getter));
5355 Report.SymbolRelatedToPreviousError (getter);
5356 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
5361 if (!InstanceResolve (ec, false, must_do_cs1540_check))
5365 // Only base will allow this invocation to happen.
5367 if (IsBase && getter.IsAbstract) {
5368 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5371 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
5375 if (!ec.IsInObsoleteScope) {
5376 PropertyBase pb = TypeManager.GetProperty (PropertyInfo);
5378 pb.CheckObsoleteness (loc);
5380 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (PropertyInfo);
5382 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc);
5391 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
5393 if (right_side == EmptyExpression.OutAccess) {
5394 if (ec.CurrentBlock.Toplevel.GetParameterReference (PropertyInfo.Name, loc) is MemberAccess) {
5395 Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5398 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as `ref' or `out' parameter",
5399 GetSignatureForError ());
5404 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5405 Error_CannotModifyIntermediateExpressionValue (ec);
5408 if (setter == null){
5410 // The following condition happens if the PropertyExpr was
5411 // created, but is invalid (ie, the property is inaccessible),
5412 // and we did not want to embed the knowledge about this in
5413 // the caller routine. This only avoids double error reporting.
5418 if (ec.CurrentBlock.Toplevel.GetParameterReference (PropertyInfo.Name, loc) is MemberAccess) {
5419 Report.Error (1947, loc, "A range variable `{0}' cannot be assigned to. Consider using `let' clause to store the value",
5422 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
5423 GetSignatureForError ());
5428 if (TypeManager.GetParameterData (setter).Count != 1){
5429 Error_PropertyNotFound (setter, false);
5433 bool must_do_cs1540_check;
5434 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
5435 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
5436 if (pm != null && pm.HasCustomAccessModifier) {
5437 Report.SymbolRelatedToPreviousError (pm);
5438 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5439 TypeManager.CSharpSignature (setter));
5442 Report.SymbolRelatedToPreviousError (setter);
5443 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
5448 if (!InstanceResolve (ec, TypeManager.IsStruct (PropertyInfo.DeclaringType), must_do_cs1540_check))
5452 // Only base will allow this invocation to happen.
5454 if (IsBase && setter.IsAbstract){
5455 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5458 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe) {
5462 if (!ec.IsInObsoleteScope) {
5463 PropertyBase pb = TypeManager.GetProperty (PropertyInfo);
5465 pb.CheckObsoleteness (loc);
5467 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (PropertyInfo);
5469 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc);
5476 public override void Emit (EmitContext ec)
5481 public void Emit (EmitContext ec, bool leave_copy)
5484 // Special case: length of single dimension array property is turned into ldlen
5486 if (IsSingleDimensionalArrayLength ()) {
5488 EmitInstance (ec, false);
5489 ec.ig.Emit (OpCodes.Ldlen);
5490 ec.ig.Emit (OpCodes.Conv_I4);
5494 Invocation.EmitCall (ec, IsBase, InstanceExpression, getter, null, loc, prepared, false);
5497 ec.ig.Emit (OpCodes.Dup);
5499 temp = new LocalTemporary (this.Type);
5506 // Implements the IAssignMethod interface for assignments
5508 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5510 Expression my_source = source;
5512 if (prepare_for_load) {
5517 ec.ig.Emit (OpCodes.Dup);
5519 temp = new LocalTemporary (this.Type);
5523 } else if (leave_copy) {
5525 temp = new LocalTemporary (this.Type);
5530 ArrayList args = new ArrayList (1);
5531 args.Add (new Argument (my_source, Argument.AType.Expression));
5533 Invocation.EmitCall (ec, IsBase, InstanceExpression, setter, args, loc, false, prepared);
5543 /// Fully resolved expression that evaluates to an Event
5545 public class EventExpr : MemberExpr {
5546 public readonly EventInfo EventInfo;
5549 MethodInfo add_accessor, remove_accessor;
5551 public EventExpr (EventInfo ei, Location loc)
5555 eclass = ExprClass.EventAccess;
5557 add_accessor = TypeManager.GetAddMethod (ei);
5558 remove_accessor = TypeManager.GetRemoveMethod (ei);
5559 if (add_accessor.IsStatic || remove_accessor.IsStatic)
5562 if (EventInfo is MyEventBuilder){
5563 MyEventBuilder eb = (MyEventBuilder) EventInfo;
5564 type = eb.EventType;
5567 type = EventInfo.EventHandlerType;
5570 public override string Name {
5572 return EventInfo.Name;
5576 public override bool IsInstance {
5582 public override bool IsStatic {
5588 public override Type DeclaringType {
5590 return EventInfo.DeclaringType;
5594 void Error_AssignmentEventOnly ()
5596 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5597 GetSignatureForError ());
5600 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
5601 SimpleName original)
5604 // If the event is local to this class, we transform ourselves into a FieldExpr
5607 if (EventInfo.DeclaringType == ec.ContainerType ||
5608 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
5609 EventField mi = TypeManager.GetEventField (EventInfo);
5612 if (!ec.IsInObsoleteScope)
5613 mi.CheckObsoleteness (loc);
5615 if ((mi.ModFlags & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0 && !ec.IsInCompoundAssignment)
5616 Error_AssignmentEventOnly ();
5618 FieldExpr ml = new FieldExpr (mi.BackingField.FieldBuilder, loc);
5620 InstanceExpression = null;
5622 return ml.ResolveMemberAccess (ec, left, loc, original);
5626 if (left is This && !ec.IsInCompoundAssignment)
5627 Error_AssignmentEventOnly ();
5629 return base.ResolveMemberAccess (ec, left, loc, original);
5632 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
5635 InstanceExpression = null;
5639 if (InstanceExpression == null) {
5640 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5644 InstanceExpression = InstanceExpression.DoResolve (ec);
5645 if (InstanceExpression == null)
5648 if (IsBase && add_accessor.IsAbstract) {
5649 Error_CannotCallAbstractBase(TypeManager.CSharpSignature(add_accessor));
5654 // This is using the same mechanism as the CS1540 check in PropertyExpr.
5655 // However, in the Event case, we reported a CS0122 instead.
5657 // TODO: Exact copy from PropertyExpr
5659 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
5660 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
5661 !TypeManager.IsNestedChildOf (ec.ContainerType, InstanceExpression.Type) &&
5662 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.ContainerType)) {
5663 Report.SymbolRelatedToPreviousError (EventInfo);
5664 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5671 public bool IsAccessibleFrom (Type invocation_type)
5674 return IsAccessorAccessible (invocation_type, add_accessor, out dummy) &&
5675 IsAccessorAccessible (invocation_type, remove_accessor, out dummy);
5678 public override Expression CreateExpressionTree (EmitContext ec)
5680 throw new NotSupportedException ("ET");
5683 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5685 // contexts where an LValue is valid have already devolved to FieldExprs
5686 Error_CannotAssign ();
5690 public override Expression DoResolve (EmitContext ec)
5692 bool must_do_cs1540_check;
5693 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
5694 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
5695 Report.SymbolRelatedToPreviousError (EventInfo);
5696 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5700 if (!InstanceResolve (ec, must_do_cs1540_check))
5703 if (!ec.IsInCompoundAssignment) {
5704 Error_CannotAssign ();
5708 if (!ec.IsInObsoleteScope) {
5709 EventField ev = TypeManager.GetEventField (EventInfo);
5711 ev.CheckObsoleteness (loc);
5713 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (EventInfo);
5715 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc);
5722 public override void Emit (EmitContext ec)
5724 Error_CannotAssign ();
5727 public void Error_CannotAssign ()
5729 Report.Error (70, loc,
5730 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
5731 GetSignatureForError (), TypeManager.CSharpName (EventInfo.DeclaringType));
5734 public override string GetSignatureForError ()
5736 return TypeManager.CSharpSignature (EventInfo);
5739 public void EmitAddOrRemove (EmitContext ec, bool is_add, Expression source)
5741 ArrayList args = new ArrayList (1);
5742 args.Add (new Argument (source, Argument.AType.Expression));
5743 Invocation.EmitCall (ec, IsBase, InstanceExpression, is_add ? add_accessor : remove_accessor, args, loc);
5747 public class TemporaryVariable : VariableReference
5751 public TemporaryVariable (Type type, Location loc)
5755 eclass = ExprClass.Variable;
5758 public override Expression CreateExpressionTree (EmitContext ec)
5760 throw new NotSupportedException ("ET");
5763 public override Expression DoResolve (EmitContext ec)
5768 TypeExpr te = new TypeExpression (type, loc);
5769 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
5770 if (!li.Resolve (ec))
5774 // Don't capture temporary variables except when using
5775 // iterator redirection
5777 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.IsIterator && ec.IsVariableCapturingRequired) {
5778 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
5779 storey.CaptureLocalVariable (ec, li);
5785 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5787 return DoResolve (ec);
5790 public override void Emit (EmitContext ec)
5795 public void EmitAssign (EmitContext ec, Expression source)
5797 EmitAssign (ec, source, false, false);
5800 public override HoistedVariable GetHoistedVariable (EmitContext ec)
5802 return li.HoistedVariableReference;
5805 public override bool IsFixed {
5806 get { return true; }
5809 public override bool IsRef {
5810 get { return false; }
5813 public override string Name {
5814 get { throw new NotImplementedException (); }
5817 public override void SetHasAddressTaken ()
5819 throw new NotImplementedException ();
5822 protected override ILocalVariable Variable {
5826 public override VariableInfo VariableInfo {
5827 get { throw new NotImplementedException (); }
5832 /// Handles `var' contextual keyword; var becomes a keyword only
5833 /// if no type called var exists in a variable scope
5835 public class VarExpr : SimpleName
5837 // Used for error reporting only
5838 ArrayList initializer;
5840 public VarExpr (Location loc)
5845 public ArrayList VariableInitializer {
5847 this.initializer = value;
5851 public bool InferType (EmitContext ec, Expression right_side)
5854 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
5856 type = right_side.Type;
5857 if (right_side is NullLiteral || type == TypeManager.void_type || type == TypeManager.anonymous_method_type) {
5858 Report.Error (815, loc, "An implicitly typed local variable declaration cannot be initialized with `{0}'",
5859 right_side.GetSignatureForError ());
5863 eclass = ExprClass.Variable;
5867 protected override void Error_TypeOrNamespaceNotFound (IResolveContext ec)
5869 Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");
5872 public override TypeExpr ResolveAsContextualType (IResolveContext rc, bool silent)
5874 TypeExpr te = base.ResolveAsContextualType (rc, true);
5878 if (initializer == null)
5881 if (initializer.Count > 1) {
5882 Location loc = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [1]).Location;
5883 Report.Error (819, loc, "An implicitly typed local variable declaration cannot include multiple declarators");
5888 Expression variable_initializer = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [0]).expression_or_array_initializer;
5889 if (variable_initializer == null) {
5890 Report.Error (818, loc, "An implicitly typed local variable declarator must include an initializer");