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 {
107 bool IsFixedVariable { get; }
108 bool IsHoisted { get; }
110 VariableInfo VariableInfo { get; }
112 void SetHasAddressTaken ();
116 /// Base class for expressions
118 public abstract class Expression {
119 public ExprClass eclass;
121 protected Location loc;
125 set { type = value; }
128 public virtual Location Location {
133 /// Utility wrapper routine for Error, just to beautify the code
135 public void Error (int error, string s)
137 Report.Error (error, loc, s);
140 // Not nice but we have broken hierarchy.
141 public virtual void CheckMarshalByRefAccess (EmitContext ec)
145 public virtual bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
147 Attribute.Error_AttributeArgumentNotValid (loc);
152 public virtual string GetSignatureForError ()
154 return TypeManager.CSharpName (type);
157 public static bool IsAccessorAccessible (Type invocation_type, MethodInfo mi, out bool must_do_cs1540_check)
159 MethodAttributes ma = mi.Attributes & MethodAttributes.MemberAccessMask;
161 must_do_cs1540_check = false; // by default we do not check for this
163 if (ma == MethodAttributes.Public)
167 // If only accessible to the current class or children
169 if (ma == MethodAttributes.Private)
170 return TypeManager.IsPrivateAccessible (invocation_type, mi.DeclaringType) ||
171 TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType);
173 if (TypeManager.IsThisOrFriendAssembly (mi.DeclaringType.Assembly)) {
174 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamORAssem)
177 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamANDAssem)
181 // Family and FamANDAssem require that we derive.
182 // FamORAssem requires that we derive if in different assemblies.
183 if (!TypeManager.IsNestedFamilyAccessible (invocation_type, mi.DeclaringType))
186 if (!TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType))
187 must_do_cs1540_check = true;
192 public virtual bool IsNull {
199 /// Performs semantic analysis on the Expression
203 /// The Resolve method is invoked to perform the semantic analysis
206 /// The return value is an expression (it can be the
207 /// same expression in some cases) or a new
208 /// expression that better represents this node.
210 /// For example, optimizations of Unary (LiteralInt)
211 /// would return a new LiteralInt with a negated
214 /// If there is an error during semantic analysis,
215 /// then an error should be reported (using Report)
216 /// and a null value should be returned.
218 /// There are two side effects expected from calling
219 /// Resolve(): the the field variable "eclass" should
220 /// be set to any value of the enumeration
221 /// `ExprClass' and the type variable should be set
222 /// to a valid type (this is the type of the
225 public abstract Expression DoResolve (EmitContext ec);
227 public virtual Expression DoResolveLValue (EmitContext ec, Expression right_side)
233 // This is used if the expression should be resolved as a type or namespace name.
234 // the default implementation fails.
236 public virtual FullNamedExpression ResolveAsTypeStep (IResolveContext rc, bool silent)
240 EmitContext ec = rc as EmitContext;
244 e.Error_UnexpectedKind (ResolveFlags.Type, loc);
250 // C# 3.0 introduced contextual keywords (var) which behaves like a type if type with
251 // same name exists or as a keyword when no type was found
253 public virtual TypeExpr ResolveAsContextualType (IResolveContext rc, bool silent)
255 return ResolveAsTypeTerminal (rc, silent);
259 // This is used to resolve the expression as a type, a null
260 // value will be returned if the expression is not a type
263 public virtual TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
265 TypeExpr te = ResolveAsBaseTerminal (ec, silent);
269 if (!silent) { // && !(te is TypeParameterExpr)) {
270 ObsoleteAttribute obsolete_attr = AttributeTester.GetObsoleteAttribute (te.Type);
271 if (obsolete_attr != null && !ec.IsInObsoleteScope) {
272 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location);
276 ConstructedType ct = te as ConstructedType;
278 // Skip constrains check for overrides and explicit implementations
279 // TODO: they should use different overload
280 GenericMethod gm = ec.GenericDeclContainer as GenericMethod;
281 if (gm != null && ((gm.ModFlags & Modifiers.OVERRIDE) != 0 || gm.MemberName.Left != null)) {
286 // TODO: silent flag is ignored
287 ct.CheckConstraints (ec);
293 public TypeExpr ResolveAsBaseTerminal (IResolveContext ec, bool silent)
295 int errors = Report.Errors;
297 FullNamedExpression fne = ResolveAsTypeStep (ec, silent);
302 TypeExpr te = fne as TypeExpr;
304 if (!silent && errors == Report.Errors)
305 fne.Error_UnexpectedKind (null, "type", loc);
309 if (!te.CheckAccessLevel (ec.GenericDeclContainer)) {
310 Report.SymbolRelatedToPreviousError (te.Type);
311 ErrorIsInaccesible (loc, TypeManager.CSharpName (te.Type));
319 public static void ErrorIsInaccesible (Location loc, string name)
321 Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", name);
324 protected static void Error_CannotAccessProtected (Location loc, MemberInfo m, Type qualifier, Type container)
326 Report.Error (1540, loc, "Cannot access protected member `{0}' via a qualifier of type `{1}'."
327 + " The qualifier must be of type `{2}' or derived from it",
328 TypeManager.GetFullNameSignature (m),
329 TypeManager.CSharpName (qualifier),
330 TypeManager.CSharpName (container));
334 public static void Error_InvalidExpressionStatement (Location loc)
336 Report.Error (201, loc, "Only assignment, call, increment, decrement, and new object " +
337 "expressions can be used as a statement");
340 public void Error_InvalidExpressionStatement ()
342 Error_InvalidExpressionStatement (loc);
345 protected void Error_CannotAssign (string to, string roContext)
347 Report.Error (1656, loc, "Cannot assign to `{0}' because it is a `{1}'",
351 public static void Error_VoidInvalidInTheContext (Location loc)
353 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
356 public virtual void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl)
358 // The error was already reported as CS1660
359 if (type == TypeManager.anonymous_method_type)
362 if (TypeManager.IsGenericParameter (Type) && TypeManager.IsGenericParameter (target) && type.Name == target.Name) {
364 string sig1 = type.DeclaringMethod == null ?
365 TypeManager.CSharpName (type.DeclaringType) :
366 TypeManager.CSharpSignature (type.DeclaringMethod);
367 string sig2 = target.DeclaringMethod == null ?
368 TypeManager.CSharpName (target.DeclaringType) :
369 TypeManager.CSharpSignature (target.DeclaringMethod);
370 Report.ExtraInformation (loc,
372 "The generic parameter `{0}' of `{1}' cannot be converted to the generic parameter `{0}' of `{2}' (in the previous ",
373 Type.Name, sig1, sig2));
375 } else if (Type.FullName == target.FullName){
376 Report.ExtraInformation (loc,
378 "The type `{0}' has two conflicting definitions, one comes from `{1}' and the other from `{2}' (in the previous ",
379 Type.FullName, Type.Assembly.FullName, target.Assembly.FullName));
383 Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
384 TypeManager.CSharpName (type), TypeManager.CSharpName (target));
388 Report.DisableReporting ();
389 bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null;
390 Report.EnableReporting ();
393 Report.Error (266, loc, "Cannot implicitly convert type `{0}' to `{1}'. " +
394 "An explicit conversion exists (are you missing a cast?)",
395 TypeManager.CSharpName (Type), TypeManager.CSharpName (target));
399 Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
400 TypeManager.CSharpName (type),
401 TypeManager.CSharpName (target));
404 public virtual void Error_VariableIsUsedBeforeItIsDeclared (string name)
406 Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", name);
409 protected virtual void Error_TypeDoesNotContainDefinition (Type type, string name)
411 Error_TypeDoesNotContainDefinition (loc, type, name);
414 public static void Error_TypeDoesNotContainDefinition (Location loc, Type type, string name)
416 Report.SymbolRelatedToPreviousError (type);
417 Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
418 TypeManager.CSharpName (type), name);
421 protected static void Error_ValueAssignment (Location loc)
423 Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
426 ResolveFlags ExprClassToResolveFlags
431 case ExprClass.Namespace:
432 return ResolveFlags.Type;
434 case ExprClass.MethodGroup:
435 return ResolveFlags.MethodGroup;
437 case ExprClass.TypeParameter:
438 return ResolveFlags.TypeParameter;
440 case ExprClass.Value:
441 case ExprClass.Variable:
442 case ExprClass.PropertyAccess:
443 case ExprClass.EventAccess:
444 case ExprClass.IndexerAccess:
445 return ResolveFlags.VariableOrValue;
448 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
454 /// Resolves an expression and performs semantic analysis on it.
458 /// Currently Resolve wraps DoResolve to perform sanity
459 /// checking and assertion checking on what we expect from Resolve.
461 public Expression Resolve (EmitContext ec, ResolveFlags flags)
463 if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type)
464 return ResolveAsTypeStep (ec, false);
466 bool do_flow_analysis = ec.DoFlowAnalysis;
467 bool omit_struct_analysis = ec.OmitStructFlowAnalysis;
468 if ((flags & ResolveFlags.DisableFlowAnalysis) != 0)
469 do_flow_analysis = false;
470 if ((flags & ResolveFlags.DisableStructFlowAnalysis) != 0)
471 omit_struct_analysis = true;
474 using (ec.WithFlowAnalysis (do_flow_analysis, omit_struct_analysis)) {
475 if (this is SimpleName) {
476 bool intermediate = (flags & ResolveFlags.Intermediate) == ResolveFlags.Intermediate;
477 e = ((SimpleName) this).DoResolve (ec, intermediate);
486 if ((flags & e.ExprClassToResolveFlags) == 0) {
487 e.Error_UnexpectedKind (flags, loc);
491 if (e.type == null && !(e is Namespace)) {
492 throw new Exception (
493 "Expression " + e.GetType () +
494 " did not set its type after Resolve\n" +
495 "called from: " + this.GetType ());
502 /// Resolves an expression and performs semantic analysis on it.
504 public Expression Resolve (EmitContext ec)
506 Expression e = Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
508 if (e != null && e.eclass == ExprClass.MethodGroup && RootContext.Version == LanguageVersion.ISO_1) {
509 ((MethodGroupExpr) e).ReportUsageError ();
515 public Constant ResolveAsConstant (EmitContext ec, MemberCore mc)
517 Expression e = Resolve (ec);
521 Constant c = e as Constant;
525 Const.Error_ExpressionMustBeConstant (loc, mc.GetSignatureForError ());
530 /// Resolves an expression for LValue assignment
534 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
535 /// checking and assertion checking on what we expect from Resolve
537 public Expression ResolveLValue (EmitContext ec, Expression right_side, Location loc)
539 int errors = Report.Errors;
540 bool out_access = right_side == EmptyExpression.OutAccess;
542 Expression e = DoResolveLValue (ec, right_side);
544 if (e != null && out_access && !(e is IMemoryLocation)) {
545 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
546 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
548 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
549 // e.GetType () + " " + e.GetSignatureForError ());
554 if (errors == Report.Errors) {
556 Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
558 Error_ValueAssignment (loc);
563 if (e.eclass == ExprClass.Invalid)
564 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
566 if ((e.type == null) && !(e is ConstructedType))
567 throw new Exception ("Expression " + e + " did not set its type after Resolve");
573 /// Emits the code for the expression
577 /// The Emit method is invoked to generate the code
578 /// for the expression.
580 public abstract void Emit (EmitContext ec);
582 // Emit code to branch to @target if this expression is equivalent to @on_true.
583 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
584 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
585 // including the use of conditional branches. Note also that a branch MUST be emitted
586 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
589 ec.ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
592 // Emit this expression for its side effects, not for its value.
593 // The default implementation is to emit the value, and then throw it away.
594 // Subclasses can provide more efficient implementations, but those MUST be equivalent
595 public virtual void EmitSideEffect (EmitContext ec)
598 ec.ig.Emit (OpCodes.Pop);
602 /// Protected constructor. Only derivate types should
603 /// be able to be created
606 protected Expression ()
608 eclass = ExprClass.Invalid;
613 /// Returns a fully formed expression after a MemberLookup
616 public static Expression ExprClassFromMemberInfo (Type container_type, MemberInfo mi, Location loc)
619 return new EventExpr ((EventInfo) mi, loc);
620 else if (mi is FieldInfo) {
621 FieldInfo fi = (FieldInfo) mi;
622 if (fi.IsLiteral || (fi.IsInitOnly && fi.FieldType == TypeManager.decimal_type))
623 return new ConstantExpr (fi, loc);
624 return new FieldExpr (fi, loc);
625 } else if (mi is PropertyInfo)
626 return new PropertyExpr (container_type, (PropertyInfo) mi, loc);
627 else if (mi is Type) {
628 return new TypeExpression ((System.Type) mi, loc);
634 protected static ArrayList almost_matched_members = new ArrayList (4);
637 // FIXME: Probably implement a cache for (t,name,current_access_set)?
639 // This code could use some optimizations, but we need to do some
640 // measurements. For example, we could use a delegate to `flag' when
641 // something can not any longer be a method-group (because it is something
645 // If the return value is an Array, then it is an array of
648 // If the return value is an MemberInfo, it is anything, but a Method
652 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
653 // the arguments here and have MemberLookup return only the methods that
654 // match the argument count/type, unlike we are doing now (we delay this
657 // This is so we can catch correctly attempts to invoke instance methods
658 // from a static body (scan for error 120 in ResolveSimpleName).
661 // FIXME: Potential optimization, have a static ArrayList
664 public static Expression MemberLookup (Type container_type, Type queried_type, string name,
665 MemberTypes mt, BindingFlags bf, Location loc)
667 return MemberLookup (container_type, null, queried_type, name, mt, bf, loc);
671 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
672 // `qualifier_type' or null to lookup members in the current class.
675 public static Expression MemberLookup (Type container_type,
676 Type qualifier_type, Type queried_type,
677 string name, MemberTypes mt,
678 BindingFlags bf, Location loc)
680 almost_matched_members.Clear ();
682 MemberInfo [] mi = TypeManager.MemberLookup (container_type, qualifier_type,
683 queried_type, mt, bf, name, almost_matched_members);
689 bool is_interface = qualifier_type != null && qualifier_type.IsInterface;
690 ArrayList methods = new ArrayList (2);
691 ArrayList non_methods = null;
693 foreach (MemberInfo m in mi) {
694 if (m is MethodBase) {
699 if (non_methods == null) {
700 non_methods = new ArrayList (2);
705 foreach (MemberInfo n_m in non_methods) {
706 if (m.DeclaringType.IsInterface && TypeManager.ImplementsInterface (m.DeclaringType, n_m.DeclaringType))
709 Report.SymbolRelatedToPreviousError (m);
710 Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
711 TypeManager.GetFullNameSignature (m), TypeManager.GetFullNameSignature (n_m));
716 if (methods.Count == 0)
717 return ExprClassFromMemberInfo (container_type, (MemberInfo)non_methods [0], loc);
719 if (non_methods != null) {
720 MethodBase method = (MethodBase) methods [0];
721 MemberInfo non_method = (MemberInfo) non_methods [0];
722 if (method.DeclaringType == non_method.DeclaringType) {
723 // Cannot happen with C# code, but is valid in IL
724 Report.SymbolRelatedToPreviousError (method);
725 Report.SymbolRelatedToPreviousError (non_method);
726 Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
727 TypeManager.GetFullNameSignature (non_method),
728 TypeManager.CSharpSignature (method));
733 Report.SymbolRelatedToPreviousError (method);
734 Report.SymbolRelatedToPreviousError (non_method);
735 Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and non-method `{1}'. Using method `{0}'",
736 TypeManager.CSharpSignature (method), TypeManager.GetFullNameSignature (non_method));
740 return new MethodGroupExpr (methods, queried_type, loc);
743 if (mi [0] is MethodBase)
744 return new MethodGroupExpr (mi, queried_type, loc);
746 return ExprClassFromMemberInfo (container_type, mi [0], loc);
749 public const MemberTypes AllMemberTypes =
750 MemberTypes.Constructor |
754 MemberTypes.NestedType |
755 MemberTypes.Property;
757 public const BindingFlags AllBindingFlags =
758 BindingFlags.Public |
759 BindingFlags.Static |
760 BindingFlags.Instance;
762 public static Expression MemberLookup (Type container_type, Type queried_type,
763 string name, Location loc)
765 return MemberLookup (container_type, null, queried_type, name,
766 AllMemberTypes, AllBindingFlags, loc);
769 public static Expression MemberLookup (Type container_type, Type qualifier_type,
770 Type queried_type, string name, Location loc)
772 return MemberLookup (container_type, qualifier_type, queried_type,
773 name, AllMemberTypes, AllBindingFlags, loc);
776 public static MethodGroupExpr MethodLookup (Type container_type, Type queried_type,
777 string name, Location loc)
779 return (MethodGroupExpr)MemberLookup (container_type, null, queried_type, name,
780 MemberTypes.Method, AllBindingFlags, loc);
784 /// This is a wrapper for MemberLookup that is not used to "probe", but
785 /// to find a final definition. If the final definition is not found, we
786 /// look for private members and display a useful debugging message if we
789 protected Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
790 Type queried_type, string name,
791 MemberTypes mt, BindingFlags bf,
796 int errors = Report.Errors;
797 e = MemberLookup (ec.ContainerType, qualifier_type, queried_type, name, mt, bf, loc);
799 if (e != null || errors != Report.Errors)
802 // No errors were reported by MemberLookup, but there was an error.
803 return Error_MemberLookupFailed (ec.ContainerType, qualifier_type, queried_type,
807 protected virtual Expression Error_MemberLookupFailed (Type container_type, Type qualifier_type,
808 Type queried_type, string name, string class_name,
809 MemberTypes mt, BindingFlags bf)
811 if (almost_matched_members.Count != 0) {
812 for (int i = 0; i < almost_matched_members.Count; ++i) {
813 MemberInfo m = (MemberInfo) almost_matched_members [i];
814 for (int j = 0; j < i; ++j) {
815 if (m == almost_matched_members [j]) {
823 Type declaring_type = m.DeclaringType;
825 Report.SymbolRelatedToPreviousError (m);
826 if (qualifier_type == null) {
827 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
828 TypeManager.CSharpName (m.DeclaringType),
829 TypeManager.CSharpName (container_type));
831 } else if (qualifier_type != container_type &&
832 TypeManager.IsNestedFamilyAccessible (container_type, declaring_type)) {
833 // Although a derived class can access protected members of
834 // its base class it cannot do so through an instance of the
835 // base class (CS1540). If the qualifier_type is a base of the
836 // ec.ContainerType and the lookup succeeds with the latter one,
837 // then we are in this situation.
838 Error_CannotAccessProtected (loc, m, qualifier_type, container_type);
840 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (m));
843 almost_matched_members.Clear ();
847 MemberInfo[] lookup = null;
848 if (queried_type == null) {
849 class_name = "global::";
851 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
852 mt, (bf & ~BindingFlags.Public) | BindingFlags.NonPublic,
855 if (lookup != null) {
856 Report.SymbolRelatedToPreviousError (lookup [0]);
857 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (lookup [0]));
858 return Error_MemberLookupFailed (lookup);
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 (lookup);
894 protected virtual Expression Error_MemberLookupFailed (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);
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 (t.IsValueType || 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 (type.IsValueType || 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 ());
1187 // Converts `source' to an int, uint, long or ulong.
1189 public Expression ConvertExpressionToArrayIndex (EmitContext ec, Expression source)
1191 Expression converted;
1193 using (ec.With (EmitContext.Flags.CheckState, true)) {
1194 converted = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, source.loc);
1195 if (converted == null)
1196 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, source.loc);
1197 if (converted == null)
1198 converted = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, source.loc);
1199 if (converted == null)
1200 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, source.loc);
1202 if (converted == null) {
1203 source.Error_ValueCannotBeConverted (ec, source.loc, TypeManager.int32_type, false);
1209 // Only positive constants are allowed at compile time
1211 Constant c = converted as Constant;
1214 Error_NegativeArrayIndex (source.loc);
1219 return new ArrayIndexCast (converted).Resolve (ec);
1223 // Derived classes implement this method by cloning the fields that
1224 // could become altered during the Resolve stage
1226 // Only expressions that are created for the parser need to implement
1229 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1231 throw new NotImplementedException (
1233 "CloneTo not implemented for expression {0}", this.GetType ()));
1237 // Clones an expression created by the parser.
1239 // We only support expressions created by the parser so far, not
1240 // expressions that have been resolved (many more classes would need
1241 // to implement CloneTo).
1243 // This infrastructure is here merely for Lambda expressions which
1244 // compile the same code using different type values for the same
1245 // arguments to find the correct overload
1247 public Expression Clone (CloneContext clonectx)
1249 Expression cloned = (Expression) MemberwiseClone ();
1250 CloneTo (clonectx, cloned);
1256 // Implementation of expression to expression tree conversion
1258 public abstract Expression CreateExpressionTree (EmitContext ec);
1260 protected Expression CreateExpressionFactoryCall (string name, ArrayList args)
1262 return CreateExpressionFactoryCall (name, null, args, loc);
1265 protected Expression CreateExpressionFactoryCall (string name, TypeArguments typeArguments, ArrayList args)
1267 return CreateExpressionFactoryCall (name, typeArguments, args, loc);
1270 public static Expression CreateExpressionFactoryCall (string name, TypeArguments typeArguments, ArrayList args, Location loc)
1272 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (loc), name, typeArguments, loc), args);
1275 protected static TypeExpr CreateExpressionTypeExpression (Location loc)
1277 TypeExpr texpr = TypeManager.expression_type_expr;
1278 if (texpr == null) {
1279 Type t = TypeManager.CoreLookupType ("System.Linq.Expressions", "Expression", Kind.Class, true);
1283 TypeManager.expression_type_expr = texpr = new TypeExpression (t, Location.Null);
1289 public virtual void MutateHoistedGenericType (AnonymousMethodStorey storey)
1291 // TODO: It should probably be type = storey.MutateType (type);
1296 /// This is just a base class for expressions that can
1297 /// appear on statements (invocations, object creation,
1298 /// assignments, post/pre increment and decrement). The idea
1299 /// being that they would support an extra Emition interface that
1300 /// does not leave a result on the stack.
1302 public abstract class ExpressionStatement : Expression {
1304 public virtual ExpressionStatement ResolveStatement (EmitContext ec)
1306 Expression e = Resolve (ec);
1310 ExpressionStatement es = e as ExpressionStatement;
1312 Error_InvalidExpressionStatement ();
1318 /// Requests the expression to be emitted in a `statement'
1319 /// context. This means that no new value is left on the
1320 /// stack after invoking this method (constrasted with
1321 /// Emit that will always leave a value on the stack).
1323 public abstract void EmitStatement (EmitContext ec);
1325 public override void EmitSideEffect (EmitContext ec)
1332 /// This kind of cast is used to encapsulate the child
1333 /// whose type is child.Type into an expression that is
1334 /// reported to return "return_type". This is used to encapsulate
1335 /// expressions which have compatible types, but need to be dealt
1336 /// at higher levels with.
1338 /// For example, a "byte" expression could be encapsulated in one
1339 /// of these as an "unsigned int". The type for the expression
1340 /// would be "unsigned int".
1343 public abstract class TypeCast : Expression
1345 protected readonly Expression child;
1347 protected TypeCast (Expression child, Type return_type)
1349 eclass = child.eclass;
1350 loc = child.Location;
1355 public override Expression CreateExpressionTree (EmitContext ec)
1357 ArrayList args = new ArrayList (2);
1358 args.Add (new Argument (child.CreateExpressionTree (ec)));
1359 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1361 if (type.IsPointer || child.Type.IsPointer)
1362 Error_PointerInsideExpressionTree ();
1364 return CreateExpressionFactoryCall (ec.CheckState ? "ConvertChecked" : "Convert", args);
1367 public override Expression DoResolve (EmitContext ec)
1369 // This should never be invoked, we are born in fully
1370 // initialized state.
1375 public override void Emit (EmitContext ec)
1380 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
1382 return child.GetAttributableValue (ec, value_type, out value);
1385 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1387 child.MutateHoistedGenericType (storey);
1390 protected override void CloneTo (CloneContext clonectx, Expression t)
1395 public override bool IsNull {
1396 get { return child.IsNull; }
1400 public class EmptyCast : TypeCast {
1401 EmptyCast (Expression child, Type target_type)
1402 : base (child, target_type)
1406 public static Expression Create (Expression child, Type type)
1408 Constant c = child as Constant;
1410 return new EmptyConstantCast (c, type);
1412 EmptyCast e = child as EmptyCast;
1414 return new EmptyCast (e.child, type);
1416 return new EmptyCast (child, type);
1419 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1421 child.EmitBranchable (ec, label, on_true);
1424 public override void EmitSideEffect (EmitContext ec)
1426 child.EmitSideEffect (ec);
1431 /// Performs a cast using an operator (op_Explicit or op_Implicit)
1433 public class OperatorCast : TypeCast {
1434 MethodInfo conversion_operator;
1437 public OperatorCast (Expression child, Type target_type) : this (child, target_type, false) {}
1439 public OperatorCast (Expression child, Type target_type, bool find_explicit)
1440 : base (child, target_type)
1442 this.find_explicit = find_explicit;
1445 // Returns the implicit operator that converts from
1446 // 'child.Type' to our target type (type)
1447 MethodInfo GetConversionOperator (bool find_explicit)
1449 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1453 mi = TypeManager.MemberLookup (child.Type, child.Type, child.Type, MemberTypes.Method,
1454 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1457 mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1458 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1461 foreach (MethodInfo oper in mi) {
1462 AParametersCollection pd = TypeManager.GetParameterData (oper);
1464 if (pd.Types [0] == child.Type && TypeManager.TypeToCoreType (oper.ReturnType) == type)
1472 public override void Emit (EmitContext ec)
1474 ILGenerator ig = ec.ig;
1477 conversion_operator = GetConversionOperator (find_explicit);
1479 if (conversion_operator == null)
1480 throw new InternalErrorException ("Outer conversion routine is out of sync");
1482 ig.Emit (OpCodes.Call, conversion_operator);
1488 /// This is a numeric cast to a Decimal
1490 public class CastToDecimal : TypeCast {
1491 MethodInfo conversion_operator;
1493 public CastToDecimal (Expression child)
1494 : this (child, false)
1498 public CastToDecimal (Expression child, bool find_explicit)
1499 : base (child, TypeManager.decimal_type)
1501 conversion_operator = GetConversionOperator (find_explicit);
1503 if (conversion_operator == null)
1504 throw new InternalErrorException ("Outer conversion routine is out of sync");
1507 // Returns the implicit operator that converts from
1508 // 'child.Type' to System.Decimal.
1509 MethodInfo GetConversionOperator (bool find_explicit)
1511 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1513 MemberInfo [] mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1514 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1516 foreach (MethodInfo oper in mi) {
1517 AParametersCollection pd = TypeManager.GetParameterData (oper);
1519 if (pd.Types [0] == child.Type && TypeManager.TypeToCoreType (oper.ReturnType) == type)
1525 public override void Emit (EmitContext ec)
1527 ILGenerator ig = ec.ig;
1530 ig.Emit (OpCodes.Call, conversion_operator);
1535 /// This is an explicit numeric cast from a Decimal
1537 public class CastFromDecimal : TypeCast
1539 static IDictionary operators;
1541 public CastFromDecimal (Expression child, Type return_type)
1542 : base (child, return_type)
1544 if (child.Type != TypeManager.decimal_type)
1545 throw new InternalErrorException (
1546 "The expected type is Decimal, instead it is " + child.Type.FullName);
1549 // Returns the explicit operator that converts from an
1550 // express of type System.Decimal to 'type'.
1551 public Expression Resolve ()
1553 if (operators == null) {
1554 MemberInfo[] all_oper = TypeManager.MemberLookup (TypeManager.decimal_type,
1555 TypeManager.decimal_type, TypeManager.decimal_type, MemberTypes.Method,
1556 BindingFlags.Static | BindingFlags.Public, "op_Explicit", null);
1558 operators = new System.Collections.Specialized.HybridDictionary ();
1559 foreach (MethodInfo oper in all_oper) {
1560 AParametersCollection pd = TypeManager.GetParameterData (oper);
1561 if (pd.Types [0] == TypeManager.decimal_type)
1562 operators.Add (TypeManager.TypeToCoreType (oper.ReturnType), oper);
1566 return operators.Contains (type) ? this : null;
1569 public override void Emit (EmitContext ec)
1571 ILGenerator ig = ec.ig;
1574 ig.Emit (OpCodes.Call, (MethodInfo)operators [type]);
1580 // Constant specialization of EmptyCast.
1581 // We need to special case this since an empty cast of
1582 // a constant is still a constant.
1584 public class EmptyConstantCast : Constant
1586 public readonly Constant child;
1588 public EmptyConstantCast(Constant child, Type type)
1589 : base (child.Location)
1591 eclass = child.eclass;
1596 public override string AsString ()
1598 return child.AsString ();
1601 public override object GetValue ()
1603 return child.GetValue ();
1606 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
1608 // FIXME: check that 'type' can be converted to 'target_type' first
1609 return child.ConvertExplicitly (in_checked_context, target_type);
1612 public override Expression CreateExpressionTree (EmitContext ec)
1614 ArrayList args = new ArrayList (2);
1615 args.Add (new Argument (child.CreateExpressionTree (ec)));
1616 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1618 Error_PointerInsideExpressionTree ();
1620 return CreateExpressionFactoryCall ("Convert", args);
1623 public override Constant Increment ()
1625 return child.Increment ();
1628 public override bool IsDefaultValue {
1629 get { return child.IsDefaultValue; }
1632 public override bool IsNegative {
1633 get { return child.IsNegative; }
1636 public override bool IsNull {
1637 get { return child.IsNull; }
1640 public override bool IsZeroInteger {
1641 get { return child.IsZeroInteger; }
1644 public override void Emit (EmitContext ec)
1649 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1651 child.EmitBranchable (ec, label, on_true);
1654 public override void EmitSideEffect (EmitContext ec)
1656 child.EmitSideEffect (ec);
1659 public override Constant ConvertImplicitly (Type target_type)
1661 // FIXME: Do we need to check user conversions?
1662 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1664 return child.ConvertImplicitly (target_type);
1667 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1669 child.MutateHoistedGenericType (storey);
1675 /// This class is used to wrap literals which belong inside Enums
1677 public class EnumConstant : Constant {
1678 public Constant Child;
1680 public EnumConstant (Constant child, Type enum_type):
1681 base (child.Location)
1683 eclass = child.eclass;
1688 public override Expression DoResolve (EmitContext ec)
1690 // This should never be invoked, we are born in fully
1691 // initialized state.
1696 public override void Emit (EmitContext ec)
1701 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1703 Child.EmitBranchable (ec, label, on_true);
1706 public override void EmitSideEffect (EmitContext ec)
1708 Child.EmitSideEffect (ec);
1711 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
1713 value = GetTypedValue ();
1717 public override string GetSignatureForError()
1719 return TypeManager.CSharpName (Type);
1722 public override object GetValue ()
1724 return Child.GetValue ();
1727 public override object GetTypedValue ()
1729 // FIXME: runtime is not ready to work with just emited enums
1730 if (!RootContext.StdLib) {
1731 return Child.GetValue ();
1734 return System.Enum.ToObject (type, Child.GetValue ());
1737 public override string AsString ()
1739 return Child.AsString ();
1742 public override Constant Increment()
1744 return new EnumConstant (Child.Increment (), type);
1747 public override bool IsDefaultValue {
1749 return Child.IsDefaultValue;
1753 public override bool IsZeroInteger {
1754 get { return Child.IsZeroInteger; }
1757 public override bool IsNegative {
1759 return Child.IsNegative;
1763 public override Constant ConvertExplicitly(bool in_checked_context, Type target_type)
1765 if (Child.Type == target_type)
1768 return Child.ConvertExplicitly (in_checked_context, target_type);
1771 public override Constant ConvertImplicitly (Type type)
1773 Type this_type = TypeManager.DropGenericTypeArguments (Type);
1774 type = TypeManager.DropGenericTypeArguments (type);
1776 if (this_type == type) {
1777 // This is workaround of mono bug. It can be removed when the latest corlib spreads enough
1778 if (TypeManager.IsEnumType (type.UnderlyingSystemType))
1781 Type child_type = TypeManager.DropGenericTypeArguments (Child.Type);
1782 if (type.UnderlyingSystemType != child_type)
1783 Child = Child.ConvertImplicitly (type.UnderlyingSystemType);
1787 if (!Convert.ImplicitStandardConversionExists (this, type)){
1791 return Child.ConvertImplicitly(type);
1797 /// This kind of cast is used to encapsulate Value Types in objects.
1799 /// The effect of it is to box the value type emitted by the previous
1802 public class BoxedCast : TypeCast {
1804 public BoxedCast (Expression expr, Type target_type)
1805 : base (expr, target_type)
1807 eclass = ExprClass.Value;
1810 public override Expression DoResolve (EmitContext ec)
1812 // This should never be invoked, we are born in fully
1813 // initialized state.
1818 public override void Emit (EmitContext ec)
1822 ec.ig.Emit (OpCodes.Box, child.Type);
1825 public override void EmitSideEffect (EmitContext ec)
1827 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1828 // so, we need to emit the box+pop instructions in most cases
1829 if (child.Type.IsValueType &&
1830 (type == TypeManager.object_type || type == TypeManager.value_type))
1831 child.EmitSideEffect (ec);
1833 base.EmitSideEffect (ec);
1837 public class UnboxCast : TypeCast {
1838 public UnboxCast (Expression expr, Type return_type)
1839 : base (expr, return_type)
1843 public override Expression DoResolve (EmitContext ec)
1845 // This should never be invoked, we are born in fully
1846 // initialized state.
1851 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1853 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
1854 Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
1855 return base.DoResolveLValue (ec, right_side);
1858 public override void Emit (EmitContext ec)
1860 ILGenerator ig = ec.ig;
1864 if (type.IsGenericParameter || type.IsGenericType && type.IsValueType)
1865 ig.Emit (OpCodes.Unbox_Any, type);
1869 ig.Emit (OpCodes.Unbox, type);
1871 LoadFromPtr (ig, type);
1875 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1877 type = storey.MutateType (type);
1878 base.MutateHoistedGenericType (storey);
1883 /// This is used to perform explicit numeric conversions.
1885 /// Explicit numeric conversions might trigger exceptions in a checked
1886 /// context, so they should generate the conv.ovf opcodes instead of
1889 public class ConvCast : TypeCast {
1890 public enum Mode : byte {
1891 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1893 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1894 U2_I1, U2_U1, U2_I2, U2_CH,
1895 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1896 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1897 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH,
1898 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH,
1899 CH_I1, CH_U1, CH_I2,
1900 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1901 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4
1906 public ConvCast (Expression child, Type return_type, Mode m)
1907 : base (child, return_type)
1912 public override Expression DoResolve (EmitContext ec)
1914 // This should never be invoked, we are born in fully
1915 // initialized state.
1920 public override string ToString ()
1922 return String.Format ("ConvCast ({0}, {1})", mode, child);
1925 public override void Emit (EmitContext ec)
1927 ILGenerator ig = ec.ig;
1933 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1934 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1935 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1936 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1937 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1939 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1940 case Mode.U1_CH: /* nothing */ break;
1942 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1943 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1944 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1945 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1946 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1947 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1949 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1950 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1951 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1952 case Mode.U2_CH: /* nothing */ break;
1954 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1955 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1956 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1957 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1958 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1959 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1960 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1962 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1963 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1964 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1965 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1966 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1967 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1969 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1970 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1971 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1972 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1973 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1974 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1975 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1976 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1978 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1979 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1980 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1981 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1982 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1983 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1984 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1985 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1987 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1988 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1989 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1991 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1992 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1993 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1994 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1995 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1996 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1997 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1998 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1999 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
2001 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
2002 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
2003 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
2004 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
2005 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
2006 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
2007 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
2008 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
2009 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
2010 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
2014 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
2015 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
2016 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
2017 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
2018 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
2020 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
2021 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
2023 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
2024 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
2025 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
2026 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
2027 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
2028 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
2030 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
2031 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
2032 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
2033 case Mode.U2_CH: /* nothing */ break;
2035 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
2036 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
2037 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
2038 case Mode.I4_U4: /* nothing */ break;
2039 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
2040 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
2041 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
2043 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
2044 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
2045 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
2046 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
2047 case Mode.U4_I4: /* nothing */ break;
2048 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
2050 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
2051 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
2052 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
2053 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
2054 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
2055 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
2056 case Mode.I8_U8: /* nothing */ break;
2057 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
2059 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
2060 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
2061 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
2062 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
2063 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
2064 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
2065 case Mode.U8_I8: /* nothing */ break;
2066 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
2068 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
2069 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
2070 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
2072 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
2073 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
2074 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
2075 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
2076 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
2077 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
2078 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
2079 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
2080 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
2082 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
2083 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
2084 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
2085 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
2086 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
2087 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
2088 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
2089 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
2090 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
2091 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
2097 public class OpcodeCast : TypeCast {
2100 public OpcodeCast (Expression child, Type return_type, OpCode op)
2101 : base (child, return_type)
2106 public override Expression DoResolve (EmitContext ec)
2108 // This should never be invoked, we are born in fully
2109 // initialized state.
2114 public override void Emit (EmitContext ec)
2120 public Type UnderlyingType {
2121 get { return child.Type; }
2126 /// This kind of cast is used to encapsulate a child and cast it
2127 /// to the class requested
2129 public sealed class ClassCast : TypeCast {
2130 Type child_generic_parameter;
2132 public ClassCast (Expression child, Type return_type)
2133 : base (child, return_type)
2136 if (TypeManager.IsGenericParameter (child.Type))
2137 child_generic_parameter = child.Type;
2140 public override Expression DoResolve (EmitContext ec)
2142 // This should never be invoked, we are born in fully
2143 // initialized state.
2148 public override void Emit (EmitContext ec)
2152 if (child_generic_parameter != null)
2153 ec.ig.Emit (OpCodes.Box, child_generic_parameter);
2156 if (type.IsGenericParameter)
2157 ec.ig.Emit (OpCodes.Unbox_Any, type);
2160 ec.ig.Emit (OpCodes.Castclass, type);
2163 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2165 type = storey.MutateType (type);
2166 if (child_generic_parameter != null)
2167 child_generic_parameter = storey.MutateGenericArgument (child_generic_parameter);
2169 base.MutateHoistedGenericType (storey);
2174 // Created during resolving pahse when an expression is wrapped or constantified
2175 // and original expression can be used later (e.g. for expression trees)
2177 public class ReducedExpression : Expression
2179 sealed class ReducedConstantExpression : EmptyConstantCast
2181 readonly Expression orig_expr;
2183 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2184 : base (expr, expr.Type)
2186 this.orig_expr = orig_expr;
2189 public override Constant ConvertImplicitly (Type target_type)
2191 Constant c = base.ConvertImplicitly (target_type);
2193 c = new ReducedConstantExpression (c, orig_expr);
2197 public override Expression CreateExpressionTree (EmitContext ec)
2199 return orig_expr.CreateExpressionTree (ec);
2202 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
2205 // Even if resolved result is a constant original expression was not
2206 // and attribute accepts constants only
2208 Attribute.Error_AttributeArgumentNotValid (loc);
2213 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
2215 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
2217 c = new ReducedConstantExpression (c, orig_expr);
2222 readonly Expression expr, orig_expr;
2224 private ReducedExpression (Expression expr, Expression orig_expr)
2227 this.orig_expr = orig_expr;
2228 this.loc = orig_expr.Location;
2231 public static Constant Create (Constant expr, Expression original_expr)
2233 return new ReducedConstantExpression (expr, original_expr);
2236 public static Expression Create (Expression expr, Expression original_expr)
2238 Constant c = expr as Constant;
2240 return Create (c, original_expr);
2242 return new ReducedExpression (expr, original_expr);
2245 public override Expression CreateExpressionTree (EmitContext ec)
2247 return orig_expr.CreateExpressionTree (ec);
2250 public override Expression DoResolve (EmitContext ec)
2252 eclass = expr.eclass;
2257 public override void Emit (EmitContext ec)
2262 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2264 expr.EmitBranchable (ec, target, on_true);
2267 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2269 expr.MutateHoistedGenericType (storey);
2274 // Unresolved type name expressions
2276 public abstract class ATypeNameExpression : FullNamedExpression
2278 public readonly string Name;
2279 protected TypeArguments targs;
2281 protected ATypeNameExpression (string name, Location l)
2287 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2294 public bool HasTypeArguments {
2296 return targs != null;
2300 public override string GetSignatureForError ()
2302 if (targs != null) {
2303 return TypeManager.RemoveGenericArity (Name) + "<" +
2304 targs.GetSignatureForError () + ">";
2312 /// SimpleName expressions are formed of a single word and only happen at the beginning
2313 /// of a dotted-name.
2315 public class SimpleName : ATypeNameExpression {
2318 public SimpleName (string name, Location l)
2323 public SimpleName (string name, TypeArguments args, Location l)
2324 : base (name, args, l)
2328 public SimpleName (string name, TypeParameter[] type_params, Location l)
2331 targs = new TypeArguments (l);
2332 foreach (TypeParameter type_param in type_params)
2333 targs.Add (new TypeParameterExpr (type_param, l));
2336 public static string RemoveGenericArity (string name)
2339 StringBuilder sb = null;
2341 int pos = name.IndexOf ('`', start);
2346 sb.Append (name.Substring (start));
2351 sb = new StringBuilder ();
2352 sb.Append (name.Substring (start, pos-start));
2355 while ((pos < name.Length) && Char.IsNumber (name [pos]))
2359 } while (start < name.Length);
2361 return sb.ToString ();
2364 public SimpleName GetMethodGroup ()
2366 return new SimpleName (RemoveGenericArity (Name), targs, loc);
2369 public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
2371 if (ec.IsInFieldInitializer)
2372 Report.Error (236, l,
2373 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2377 120, l, "`{0}': An object reference is required for the nonstatic field, method or property",
2381 public bool IdenticalNameAndTypeName (EmitContext ec, Expression resolved_to, Location loc)
2383 return resolved_to != null && resolved_to.Type != null &&
2384 resolved_to.Type.Name == Name &&
2385 (ec.DeclContainer.LookupNamespaceOrType (Name, loc, /* ignore_cs0104 = */ true) != null);
2388 public override Expression DoResolve (EmitContext ec)
2390 return SimpleNameResolve (ec, null, false);
2393 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
2395 return SimpleNameResolve (ec, right_side, false);
2399 public Expression DoResolve (EmitContext ec, bool intermediate)
2401 return SimpleNameResolve (ec, null, intermediate);
2404 static bool IsNestedChild (Type t, Type parent)
2406 while (parent != null) {
2407 if (TypeManager.IsNestedChildOf (t, TypeManager.DropGenericTypeArguments (parent)))
2410 parent = parent.BaseType;
2416 FullNamedExpression ResolveNested (IResolveContext ec, Type t)
2418 if (!TypeManager.IsGenericTypeDefinition (t) && !TypeManager.IsGenericType (t))
2421 DeclSpace ds = ec.DeclContainer;
2422 while (ds != null && !IsNestedChild (t, ds.TypeBuilder))
2428 Type[] gen_params = TypeManager.GetTypeArguments (t);
2430 int arg_count = targs != null ? targs.Count : 0;
2432 for (; (ds != null) && ds.IsGeneric; ds = ds.Parent) {
2433 if (arg_count + ds.CountTypeParameters == gen_params.Length) {
2434 TypeArguments new_args = new TypeArguments (loc);
2435 foreach (TypeParameter param in ds.TypeParameters)
2436 new_args.Add (new TypeParameterExpr (param, loc));
2439 new_args.Add (targs);
2441 return new ConstructedType (t, new_args, loc);
2448 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2450 FullNamedExpression fne = ec.GenericDeclContainer.LookupGeneric (Name, loc);
2452 return fne.ResolveAsTypeStep (ec, silent);
2454 int errors = Report.Errors;
2455 fne = ec.DeclContainer.LookupNamespaceOrType (Name, loc, /*ignore_cs0104=*/ false);
2458 if (fne.Type == null)
2461 FullNamedExpression nested = ResolveNested (ec, fne.Type);
2463 return nested.ResolveAsTypeStep (ec, false);
2465 if (targs != null) {
2466 ConstructedType ct = new ConstructedType (fne, targs, loc);
2467 return ct.ResolveAsTypeStep (ec, false);
2473 if (silent || errors != Report.Errors)
2476 Error_TypeOrNamespaceNotFound (ec);
2480 protected virtual void Error_TypeOrNamespaceNotFound (IResolveContext ec)
2482 MemberCore mc = ec.DeclContainer.GetDefinition (Name);
2484 Error_UnexpectedKind (ec.DeclContainer, "type", GetMemberType (mc), loc);
2488 string ns = ec.DeclContainer.NamespaceEntry.NS.Name;
2489 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2490 foreach (Assembly a in RootNamespace.Global.Assemblies) {
2491 Type type = a.GetType (fullname);
2493 Report.SymbolRelatedToPreviousError (type);
2494 Expression.ErrorIsInaccesible (loc, TypeManager.CSharpName (type));
2499 Type t = ec.DeclContainer.LookupAnyGeneric (Name);
2501 Namespace.Error_InvalidNumberOfTypeArguments (t, loc);
2505 if (targs != null) {
2506 FullNamedExpression retval = ec.DeclContainer.LookupNamespaceOrType (SimpleName.RemoveGenericArity (Name), loc, true);
2507 if (retval != null) {
2508 Namespace.Error_TypeArgumentsCannotBeUsed (retval.Type, loc);
2513 NamespaceEntry.Error_NamespaceNotFound (loc, Name);
2516 // TODO: I am still not convinced about this. If someone else will need it
2517 // implement this as virtual property in MemberCore hierarchy
2518 public static string GetMemberType (MemberCore mc)
2524 if (mc is FieldBase)
2526 if (mc is MethodCore)
2528 if (mc is EnumMember)
2536 Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2542 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2548 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2555 /// 7.5.2: Simple Names.
2557 /// Local Variables and Parameters are handled at
2558 /// parse time, so they never occur as SimpleNames.
2560 /// The `intermediate' flag is used by MemberAccess only
2561 /// and it is used to inform us that it is ok for us to
2562 /// avoid the static check, because MemberAccess might end
2563 /// up resolving the Name as a Type name and the access as
2564 /// a static type access.
2566 /// ie: Type Type; .... { Type.GetType (""); }
2568 /// Type is both an instance variable and a Type; Type.GetType
2569 /// is the static method not an instance method of type.
2571 Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2573 Expression e = null;
2576 // Stage 1: Performed by the parser (binding to locals or parameters).
2578 Block current_block = ec.CurrentBlock;
2579 if (current_block != null){
2580 LocalInfo vi = current_block.GetLocalInfo (Name);
2582 if (targs != null) {
2583 Report.Error (307, loc,
2584 "The variable `{0}' cannot be used with type arguments",
2589 LocalVariableReference var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2590 if (right_side != null) {
2591 return var.ResolveLValue (ec, right_side, loc);
2593 ResolveFlags rf = ResolveFlags.VariableOrValue;
2595 rf |= ResolveFlags.DisableFlowAnalysis;
2596 return var.Resolve (ec, rf);
2600 ParameterReference pref = current_block.Toplevel.GetParameterReference (Name, loc);
2602 if (targs != null) {
2603 Report.Error (307, loc,
2604 "The variable `{0}' cannot be used with type arguments",
2609 if (right_side != null)
2610 return pref.ResolveLValue (ec, right_side, loc);
2612 return pref.Resolve (ec);
2615 Expression expr = current_block.Toplevel.GetTransparentIdentifier (Name);
2617 if (right_side != null)
2618 return expr.ResolveLValue (ec, right_side, loc);
2619 return expr.Resolve (ec);
2624 // Stage 2: Lookup members
2627 Type almost_matched_type = null;
2628 ArrayList almost_matched = null;
2629 for (DeclSpace lookup_ds = ec.DeclContainer; lookup_ds != null; lookup_ds = lookup_ds.Parent) {
2630 // either RootDeclSpace or GenericMethod
2631 if (lookup_ds.TypeBuilder == null)
2634 e = MemberLookup (ec.ContainerType, lookup_ds.TypeBuilder, Name, loc);
2636 PropertyExpr pe = e as PropertyExpr;
2638 AParametersCollection param = TypeManager.GetParameterData (pe.PropertyInfo);
2640 // since TypeManager.MemberLookup doesn't know if we're doing a lvalue access or not,
2641 // it doesn't know which accessor to check permissions against
2642 if (param.IsEmpty && pe.IsAccessibleFrom (ec.ContainerType, right_side != null))
2644 } else if (e is EventExpr) {
2645 if (((EventExpr) e).IsAccessibleFrom (ec.ContainerType))
2653 if (almost_matched == null && almost_matched_members.Count > 0) {
2654 almost_matched_type = lookup_ds.TypeBuilder;
2655 almost_matched = (ArrayList) almost_matched_members.Clone ();
2660 if (almost_matched == null && almost_matched_members.Count > 0) {
2661 almost_matched_type = ec.ContainerType;
2662 almost_matched = (ArrayList) almost_matched_members.Clone ();
2664 e = ResolveAsTypeStep (ec, true);
2668 if (current_block != null) {
2669 IKnownVariable ikv = current_block.Explicit.GetKnownVariable (Name);
2671 LocalInfo li = ikv as LocalInfo;
2672 // Supress CS0219 warning
2676 Error_VariableIsUsedBeforeItIsDeclared (Name);
2681 if (RootContext.EvalMode){
2682 FieldInfo fi = Evaluator.LookupField (Name);
2684 return new FieldExpr (fi, loc);
2687 if (almost_matched != null)
2688 almost_matched_members = almost_matched;
2689 if (almost_matched_type == null)
2690 almost_matched_type = ec.ContainerType;
2691 Error_MemberLookupFailed (ec.ContainerType, null, almost_matched_type, Name,
2692 ec.DeclContainer.Name, AllMemberTypes, AllBindingFlags);
2696 if (e is TypeExpr) {
2700 ConstructedType ct = new ConstructedType (
2701 e.Type, targs, loc);
2702 return ct.ResolveAsTypeStep (ec, false);
2705 if (e is MemberExpr) {
2706 MemberExpr me = (MemberExpr) e;
2709 if (me.IsInstance) {
2710 if (ec.IsStatic || ec.IsInFieldInitializer) {
2712 // Note that an MemberExpr can be both IsInstance and IsStatic.
2713 // An unresolved MethodGroupExpr can contain both kinds of methods
2714 // and each predicate is true if the MethodGroupExpr contains
2715 // at least one of that kind of method.
2719 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2720 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2725 // Pass the buck to MemberAccess and Invocation.
2727 left = EmptyExpression.Null;
2729 left = ec.GetThis (loc);
2732 left = new TypeExpression (ec.ContainerType, loc);
2735 me = me.ResolveMemberAccess (ec, left, loc, null);
2739 if (targs != null) {
2741 me.SetTypeArguments (targs);
2744 if (!me.IsStatic && (me.InstanceExpression != null) &&
2745 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2746 me.InstanceExpression.Type != me.DeclaringType &&
2747 !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2748 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2749 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2750 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2754 return (right_side != null)
2755 ? me.DoResolveLValue (ec, right_side)
2756 : me.DoResolve (ec);
2762 protected override void CloneTo (CloneContext clonectx, Expression target)
2764 // CloneTo: Nothing, we do not keep any state on this expression
2769 /// Represents a namespace or a type. The name of the class was inspired by
2770 /// section 10.8.1 (Fully Qualified Names).
2772 public abstract class FullNamedExpression : Expression {
2774 public override Expression CreateExpressionTree (EmitContext ec)
2776 throw new NotSupportedException ("ET");
2779 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2781 throw new NotSupportedException ();
2784 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2789 public override void Emit (EmitContext ec)
2791 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2792 GetSignatureForError ());
2797 /// Expression that evaluates to a type
2799 public abstract class TypeExpr : FullNamedExpression {
2800 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2802 TypeExpr t = DoResolveAsTypeStep (ec);
2806 eclass = ExprClass.Type;
2810 override public Expression DoResolve (EmitContext ec)
2812 return ResolveAsTypeTerminal (ec, false);
2815 public virtual bool CheckAccessLevel (DeclSpace ds)
2817 return ds.CheckAccessLevel (Type);
2820 public virtual bool AsAccessible (DeclSpace ds)
2822 return ds.IsAccessibleAs (Type);
2825 public virtual bool IsClass {
2826 get { return Type.IsClass; }
2829 public virtual bool IsValueType {
2830 get { return Type.IsValueType; }
2833 public virtual bool IsInterface {
2834 get { return Type.IsInterface; }
2837 public virtual bool IsSealed {
2838 get { return Type.IsSealed; }
2841 public virtual bool CanInheritFrom ()
2843 if (Type == TypeManager.enum_type ||
2844 (Type == TypeManager.value_type && RootContext.StdLib) ||
2845 Type == TypeManager.multicast_delegate_type ||
2846 Type == TypeManager.delegate_type ||
2847 Type == TypeManager.array_type)
2853 protected abstract TypeExpr DoResolveAsTypeStep (IResolveContext ec);
2855 public override bool Equals (object obj)
2857 TypeExpr tobj = obj as TypeExpr;
2861 return Type == tobj.Type;
2864 public override int GetHashCode ()
2866 return Type.GetHashCode ();
2869 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2871 type = storey.MutateType (type);
2876 /// Fully resolved Expression that already evaluated to a type
2878 public class TypeExpression : TypeExpr {
2879 public TypeExpression (Type t, Location l)
2882 eclass = ExprClass.Type;
2886 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2891 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2898 /// Used to create types from a fully qualified name. These are just used
2899 /// by the parser to setup the core types. A TypeLookupExpression is always
2900 /// classified as a type.
2902 public sealed class TypeLookupExpression : TypeExpr {
2903 readonly string name;
2905 public TypeLookupExpression (string name)
2908 eclass = ExprClass.Type;
2911 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2913 // It's null for corlib compilation only
2915 return DoResolveAsTypeStep (ec);
2920 private class UnexpectedType
2924 // This performes recursive type lookup, providing support for generic types.
2925 // For example, given the type:
2927 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]]
2929 // The types will be checked in the following order:
2932 // System.Collections |
2933 // System.Collections.Generic |
2935 // System | recursive call 1 |
2936 // System.Int32 _| | main method call
2938 // System | recursive call 2 |
2939 // System.String _| |
2941 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]] _|
2943 private Type TypeLookup (IResolveContext ec, string name)
2948 FullNamedExpression resolved = null;
2950 Type recursive_type = null;
2951 while (index < name.Length) {
2952 if (name[index] == '[') {
2957 if (name[index] == '[')
2959 else if (name[index] == ']')
2961 } while (braces > 0);
2962 recursive_type = TypeLookup (ec, name.Substring (open + 1, index - open - 1));
2963 if (recursive_type == null || (recursive_type == typeof(UnexpectedType)))
2964 return recursive_type;
2967 if (name[index] == ',')
2969 else if ((name[index] == '.' && !done) || (index == name.Length && name[0] != '[')) {
2970 string substring = name.Substring(dot, index - dot);
2972 if (resolved == null)
2973 resolved = RootNamespace.Global.Lookup (ec.DeclContainer, substring, Location.Null);
2974 else if (resolved is Namespace)
2975 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
2976 else if (type != null)
2977 type = TypeManager.GetNestedType (type, substring);
2981 if (resolved == null)
2983 else if (type == null && resolved is TypeExpr)
2984 type = resolved.Type;
2991 if (name[0] != '[') {
2992 string substring = name.Substring(dot, index - dot);
2995 return TypeManager.GetNestedType (type, substring);
2997 if (resolved != null) {
2998 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
2999 if (resolved is TypeExpr)
3000 return resolved.Type;
3002 if (resolved == null)
3005 resolved.Error_UnexpectedKind (ec.DeclContainer, "type", loc);
3006 return typeof (UnexpectedType);
3012 return recursive_type;
3015 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
3017 Type t = TypeLookup (ec, name);
3019 NamespaceEntry.Error_NamespaceNotFound (loc, name);
3022 if (t == typeof(UnexpectedType))
3028 protected override void CloneTo (CloneContext clonectx, Expression target)
3030 // CloneTo: Nothing, we do not keep any state on this expression
3033 public override string GetSignatureForError ()
3036 return TypeManager.CSharpName (name);
3038 return base.GetSignatureForError ();
3043 /// Represents an "unbound generic type", ie. typeof (Foo<>).
3046 public class UnboundTypeExpression : TypeExpr
3050 public UnboundTypeExpression (MemberName name, Location l)
3056 protected override void CloneTo (CloneContext clonectx, Expression target)
3061 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
3064 if (name.Left != null) {
3065 Expression lexpr = name.Left.GetTypeExpression ();
3066 expr = new MemberAccess (lexpr, name.Basename);
3068 expr = new SimpleName (name.Basename, loc);
3071 FullNamedExpression fne = expr.ResolveAsTypeStep (ec, false);
3076 return new TypeExpression (type, loc);
3081 /// This class denotes an expression which evaluates to a member
3082 /// of a struct or a class.
3084 public abstract class MemberExpr : Expression
3086 protected bool is_base;
3089 /// The name of this member.
3091 public abstract string Name {
3096 // When base.member is used
3098 public bool IsBase {
3099 get { return is_base; }
3100 set { is_base = value; }
3104 /// Whether this is an instance member.
3106 public abstract bool IsInstance {
3111 /// Whether this is a static member.
3113 public abstract bool IsStatic {
3118 /// The type which declares this member.
3120 public abstract Type DeclaringType {
3125 /// The instance expression associated with this member, if it's a
3126 /// non-static member.
3128 public Expression InstanceExpression;
3130 public static void error176 (Location loc, string name)
3132 Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
3133 "with an instance reference, qualify it with a type name instead", name);
3136 public static void Error_BaseAccessInExpressionTree (Location loc)
3138 Report.Error (831, loc, "An expression tree may not contain a base access");
3141 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3143 if (InstanceExpression != null)
3144 InstanceExpression.MutateHoistedGenericType (storey);
3147 // TODO: possible optimalization
3148 // Cache resolved constant result in FieldBuilder <-> expression map
3149 public virtual MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3150 SimpleName original)
3154 // original == null || original.Resolve (...) ==> left
3157 if (left is TypeExpr) {
3158 left = left.ResolveAsTypeTerminal (ec, true);
3163 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3171 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3174 return ResolveExtensionMemberAccess (left);
3177 InstanceExpression = left;
3181 protected virtual MemberExpr ResolveExtensionMemberAccess (Expression left)
3183 error176 (loc, GetSignatureForError ());
3187 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3192 if (InstanceExpression == EmptyExpression.Null) {
3193 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3197 if (InstanceExpression.Type.IsValueType) {
3198 if (InstanceExpression is IMemoryLocation) {
3199 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
3201 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
3202 InstanceExpression.Emit (ec);
3204 t.AddressOf (ec, AddressOp.Store);
3207 InstanceExpression.Emit (ec);
3209 if (prepare_for_load)
3210 ec.ig.Emit (OpCodes.Dup);
3213 public virtual void SetTypeArguments (TypeArguments ta)
3215 // TODO: need to get correct member type
3216 Report.Error (307, loc, "The property `{0}' cannot be used with type arguments",
3217 GetSignatureForError ());
3222 /// Represents group of extension methods
3224 public class ExtensionMethodGroupExpr : MethodGroupExpr
3226 readonly NamespaceEntry namespace_entry;
3227 public Expression ExtensionExpression;
3228 Argument extension_argument;
3230 public ExtensionMethodGroupExpr (ArrayList list, NamespaceEntry n, Type extensionType, Location l)
3231 : base (list, extensionType, l)
3233 this.namespace_entry = n;
3236 public override bool IsStatic {
3237 get { return true; }
3240 public bool IsTopLevel {
3241 get { return namespace_entry == null; }
3244 public override void EmitArguments (EmitContext ec, ArrayList arguments)
3246 if (arguments == null)
3247 arguments = new ArrayList (1);
3248 arguments.Insert (0, extension_argument);
3249 base.EmitArguments (ec, arguments);
3252 public override void EmitCall (EmitContext ec, ArrayList arguments)
3254 if (arguments == null)
3255 arguments = new ArrayList (1);
3256 arguments.Insert (0, extension_argument);
3257 base.EmitCall (ec, arguments);
3260 public override MethodGroupExpr OverloadResolve (EmitContext ec, ref ArrayList arguments, bool may_fail, Location loc)
3262 if (arguments == null)
3263 arguments = new ArrayList (1);
3265 arguments.Insert (0, new Argument (ExtensionExpression));
3266 MethodGroupExpr mg = ResolveOverloadExtensions (ec, arguments, namespace_entry, loc);
3268 // Store resolved argument and restore original arguments
3270 ((ExtensionMethodGroupExpr)mg).extension_argument = (Argument)arguments [0];
3271 arguments.RemoveAt (0);
3276 MethodGroupExpr ResolveOverloadExtensions (EmitContext ec, ArrayList arguments, NamespaceEntry ns, Location loc)
3278 // Use normal resolve rules
3279 MethodGroupExpr mg = base.OverloadResolve (ec, ref arguments, ns != null, loc);
3287 ExtensionMethodGroupExpr e = ns.LookupExtensionMethod (type, null, Name, loc);
3289 return base.OverloadResolve (ec, ref arguments, false, loc);
3291 e.ExtensionExpression = ExtensionExpression;
3292 e.SetTypeArguments (type_arguments);
3293 return e.ResolveOverloadExtensions (ec, arguments, e.namespace_entry, loc);
3298 /// MethodGroupExpr represents a group of method candidates which
3299 /// can be resolved to the best method overload
3301 public class MethodGroupExpr : MemberExpr
3303 public interface IErrorHandler
3305 bool NoExactMatch (EmitContext ec, MethodBase method);
3308 public IErrorHandler CustomErrorHandler;
3309 public MethodBase [] Methods;
3310 MethodBase best_candidate;
3311 // TODO: make private
3312 public TypeArguments type_arguments;
3313 bool identical_type_name;
3316 public MethodGroupExpr (MemberInfo [] mi, Type type, Location l)
3319 Methods = new MethodBase [mi.Length];
3320 mi.CopyTo (Methods, 0);
3323 public MethodGroupExpr (ArrayList list, Type type, Location l)
3327 Methods = (MethodBase[])list.ToArray (typeof (MethodBase));
3329 foreach (MemberInfo m in list){
3330 if (!(m is MethodBase)){
3331 Console.WriteLine ("Name " + m.Name);
3332 Console.WriteLine ("Found a: " + m.GetType ().FullName);
3341 protected MethodGroupExpr (Type type, Location loc)
3344 eclass = ExprClass.MethodGroup;
3348 public override Type DeclaringType {
3351 // We assume that the top-level type is in the end
3353 return Methods [Methods.Length - 1].DeclaringType;
3354 //return Methods [0].DeclaringType;
3358 public Type DelegateType {
3360 delegate_type = value;
3364 public bool IdenticalTypeName {
3366 return identical_type_name;
3370 identical_type_name = value;
3374 public override string GetSignatureForError ()
3376 if (best_candidate != null)
3377 return TypeManager.CSharpSignature (best_candidate);
3379 return TypeManager.CSharpSignature (Methods [0]);
3382 public override string Name {
3384 return Methods [0].Name;
3388 public override bool IsInstance {
3390 if (best_candidate != null)
3391 return !best_candidate.IsStatic;
3393 foreach (MethodBase mb in Methods)
3401 public override bool IsStatic {
3403 if (best_candidate != null)
3404 return best_candidate.IsStatic;
3406 foreach (MethodBase mb in Methods)
3414 public static explicit operator ConstructorInfo (MethodGroupExpr mg)
3416 return (ConstructorInfo)mg.best_candidate;
3419 public static explicit operator MethodInfo (MethodGroupExpr mg)
3421 return (MethodInfo)mg.best_candidate;
3425 // 7.4.3.3 Better conversion from expression
3426 // Returns : 1 if a->p is better,
3427 // 2 if a->q is better,
3428 // 0 if neither is better
3430 static int BetterExpressionConversion (EmitContext ec, Argument a, Type p, Type q)
3432 Type argument_type = TypeManager.TypeToCoreType (a.Type);
3433 if (argument_type == TypeManager.anonymous_method_type && RootContext.Version > LanguageVersion.ISO_2) {
3435 // Uwrap delegate from Expression<T>
3437 if (TypeManager.DropGenericTypeArguments (p) == TypeManager.expression_type) {
3438 p = TypeManager.GetTypeArguments (p) [0];
3440 if (TypeManager.DropGenericTypeArguments (q) == TypeManager.expression_type) {
3441 q = TypeManager.GetTypeArguments (q) [0];
3444 p = Delegate.GetInvokeMethod (null, p).ReturnType;
3445 q = Delegate.GetInvokeMethod (null, q).ReturnType;
3446 if (p == TypeManager.void_type && q != TypeManager.void_type)
3448 if (q == TypeManager.void_type && p != TypeManager.void_type)
3451 if (argument_type == p)
3454 if (argument_type == q)
3458 return BetterTypeConversion (ec, p, q);
3462 // 7.4.3.4 Better conversion from type
3464 public static int BetterTypeConversion (EmitContext ec, Type p, Type q)
3466 if (p == null || q == null)
3467 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3469 if (p == TypeManager.int32_type) {
3470 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3472 } else if (p == TypeManager.int64_type) {
3473 if (q == TypeManager.uint64_type)
3475 } else if (p == TypeManager.sbyte_type) {
3476 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3477 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3479 } else if (p == TypeManager.short_type) {
3480 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3481 q == TypeManager.uint64_type)
3485 if (q == TypeManager.int32_type) {
3486 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3488 } if (q == TypeManager.int64_type) {
3489 if (p == TypeManager.uint64_type)
3491 } else if (q == TypeManager.sbyte_type) {
3492 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3493 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3495 } if (q == TypeManager.short_type) {
3496 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3497 p == TypeManager.uint64_type)
3501 // TODO: this is expensive
3502 Expression p_tmp = new EmptyExpression (p);
3503 Expression q_tmp = new EmptyExpression (q);
3505 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3506 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3508 if (p_to_q && !q_to_p)
3511 if (q_to_p && !p_to_q)
3518 /// Determines "Better function" between candidate
3519 /// and the current best match
3522 /// Returns a boolean indicating :
3523 /// false if candidate ain't better
3524 /// true if candidate is better than the current best match
3526 static bool BetterFunction (EmitContext ec, ArrayList args, int argument_count,
3527 MethodBase candidate, bool candidate_params,
3528 MethodBase best, bool best_params)
3530 AParametersCollection candidate_pd = TypeManager.GetParameterData (candidate);
3531 AParametersCollection best_pd = TypeManager.GetParameterData (best);
3533 bool better_at_least_one = false;
3535 for (int j = 0, c_idx = 0, b_idx = 0; j < argument_count; ++j, ++c_idx, ++b_idx)
3537 Argument a = (Argument) args [j];
3539 Type ct = candidate_pd.Types [c_idx];
3540 Type bt = best_pd.Types [b_idx];
3542 if (candidate_params && candidate_pd.FixedParameters [c_idx].ModFlags == Parameter.Modifier.PARAMS)
3544 ct = TypeManager.GetElementType (ct);
3548 if (best_params && best_pd.FixedParameters [b_idx].ModFlags == Parameter.Modifier.PARAMS)
3550 bt = TypeManager.GetElementType (bt);
3558 int result = BetterExpressionConversion (ec, a, ct, bt);
3560 // for each argument, the conversion to 'ct' should be no worse than
3561 // the conversion to 'bt'.
3565 // for at least one argument, the conversion to 'ct' should be better than
3566 // the conversion to 'bt'.
3568 better_at_least_one = true;
3571 if (better_at_least_one)
3575 // This handles the case
3577 // Add (float f1, float f2, float f3);
3578 // Add (params decimal [] foo);
3580 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3581 // first candidate would've chosen as better.
3587 // The two methods have equal parameter types. Now apply tie-breaking rules
3589 if (TypeManager.IsGenericMethod (best) && !TypeManager.IsGenericMethod (candidate))
3591 if (!TypeManager.IsGenericMethod (best) && TypeManager.IsGenericMethod (candidate))
3595 // This handles the following cases:
3597 // Trim () is better than Trim (params char[] chars)
3598 // Concat (string s1, string s2, string s3) is better than
3599 // Concat (string s1, params string [] srest)
3600 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3602 if (!candidate_params && best_params)
3604 if (candidate_params && !best_params)
3607 int candidate_param_count = candidate_pd.Count;
3608 int best_param_count = best_pd.Count;
3610 if (candidate_param_count != best_param_count)
3611 // can only happen if (candidate_params && best_params)
3612 return candidate_param_count > best_param_count;
3615 // now, both methods have the same number of parameters, and the parameters have the same types
3616 // Pick the "more specific" signature
3619 MethodBase orig_candidate = TypeManager.DropGenericMethodArguments (candidate);
3620 MethodBase orig_best = TypeManager.DropGenericMethodArguments (best);
3622 AParametersCollection orig_candidate_pd = TypeManager.GetParameterData (orig_candidate);
3623 AParametersCollection orig_best_pd = TypeManager.GetParameterData (orig_best);
3625 bool specific_at_least_once = false;
3626 for (int j = 0; j < candidate_param_count; ++j)
3628 Type ct = orig_candidate_pd.Types [j];
3629 Type bt = orig_best_pd.Types [j];
3632 Type specific = MoreSpecific (ct, bt);
3636 specific_at_least_once = true;
3639 if (specific_at_least_once)
3642 // FIXME: handle lifted operators
3648 protected override MemberExpr ResolveExtensionMemberAccess (Expression left)
3651 return base.ResolveExtensionMemberAccess (left);
3654 // When left side is an expression and at least one candidate method is
3655 // static, it can be extension method
3657 InstanceExpression = left;
3661 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3662 SimpleName original)
3664 if (!(left is TypeExpr) &&
3665 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3666 IdenticalTypeName = true;
3668 return base.ResolveMemberAccess (ec, left, loc, original);
3671 public override Expression CreateExpressionTree (EmitContext ec)
3673 if (best_candidate == null) {
3674 Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3678 if (best_candidate.IsConstructor)
3679 return new TypeOfConstructorInfo (best_candidate, loc);
3681 IMethodData md = TypeManager.GetMethod (best_candidate);
3682 if (md != null && md.IsExcluded ())
3683 Report.Error (765, loc,
3684 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3686 return new TypeOfMethodInfo (best_candidate, loc);
3689 override public Expression DoResolve (EmitContext ec)
3691 if (InstanceExpression != null) {
3692 InstanceExpression = InstanceExpression.DoResolve (ec);
3693 if (InstanceExpression == null)
3700 public void ReportUsageError ()
3702 Report.Error (654, loc, "Method `" + DeclaringType + "." +
3703 Name + "()' is referenced without parentheses");
3706 override public void Emit (EmitContext ec)
3708 ReportUsageError ();
3711 public virtual void EmitArguments (EmitContext ec, ArrayList arguments)
3713 Invocation.EmitArguments (ec, arguments, false, null);
3716 public virtual void EmitCall (EmitContext ec, ArrayList arguments)
3718 Invocation.EmitCall (ec, IsBase, InstanceExpression, best_candidate, arguments, loc);
3721 protected virtual void Error_InvalidArguments (EmitContext ec, Location loc, int idx, MethodBase method,
3722 Argument a, AParametersCollection expected_par, Type paramType)
3724 ExtensionMethodGroupExpr emg = this as ExtensionMethodGroupExpr;
3726 if (a is CollectionElementInitializer.ElementInitializerArgument) {
3727 Report.SymbolRelatedToPreviousError (method);
3728 if ((expected_par.FixedParameters [idx].ModFlags & Parameter.Modifier.ISBYREF) != 0) {
3729 Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
3730 TypeManager.CSharpSignature (method));
3733 Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
3734 TypeManager.CSharpSignature (method));
3735 } else if (delegate_type == null) {
3736 Report.SymbolRelatedToPreviousError (method);
3738 Report.Error (1928, loc,
3739 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3740 emg.ExtensionExpression.GetSignatureForError (),
3741 emg.Name, TypeManager.CSharpSignature (method));
3743 Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
3744 TypeManager.CSharpSignature (method));
3747 Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
3748 TypeManager.CSharpName (delegate_type));
3750 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters [idx].ModFlags;
3752 string index = (idx + 1).ToString ();
3753 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
3754 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
3755 if ((mod & Parameter.Modifier.ISBYREF) == 0)
3756 Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
3757 index, Parameter.GetModifierSignature (a.Modifier));
3759 Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
3760 index, Parameter.GetModifierSignature (mod));
3762 string p1 = a.GetSignatureForError ();
3763 string p2 = TypeManager.CSharpName (paramType);
3766 Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
3767 Report.SymbolRelatedToPreviousError (a.Expr.Type);
3768 Report.SymbolRelatedToPreviousError (paramType);
3771 if (idx == 0 && emg != null) {
3772 Report.Error (1929, loc,
3773 "Extension method instance type `{0}' cannot be converted to `{1}'", p1, p2);
3775 Report.Error (1503, loc,
3776 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
3781 public override void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl)
3783 Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3784 Name, TypeManager.CSharpName (target));
3787 protected virtual int GetApplicableParametersCount (MethodBase method, AParametersCollection parameters)
3789 return parameters.Count;
3792 public static bool IsAncestralType (Type first_type, Type second_type)
3794 return first_type != second_type &&
3795 (TypeManager.IsSubclassOf (second_type, first_type) ||
3796 TypeManager.ImplementsInterface (second_type, first_type));
3800 /// Determines if the candidate method is applicable (section 14.4.2.1)
3801 /// to the given set of arguments
3802 /// A return value rates candidate method compatibility,
3803 /// 0 = the best, int.MaxValue = the worst
3805 public int IsApplicable (EmitContext ec,
3806 ArrayList arguments, int arg_count, ref MethodBase method, ref bool params_expanded_form)
3808 MethodBase candidate = method;
3810 AParametersCollection pd = TypeManager.GetParameterData (candidate);
3811 int param_count = GetApplicableParametersCount (candidate, pd);
3813 if (arg_count != param_count) {
3815 return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
3816 if (arg_count < param_count - 1)
3817 return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
3822 // 1. Handle generic method using type arguments when specified or type inference
3824 if (TypeManager.IsGenericMethod (candidate)) {
3825 if (type_arguments != null) {
3826 Type [] g_args = candidate.GetGenericArguments ();
3827 if (g_args.Length != type_arguments.Count)
3828 return int.MaxValue - 20000 + Math.Abs (type_arguments.Count - g_args.Length);
3830 // TODO: Don't create new method, create Parameters only
3831 method = ((MethodInfo) candidate).MakeGenericMethod (type_arguments.Arguments);
3833 pd = TypeManager.GetParameterData (candidate);
3835 int score = TypeManager.InferTypeArguments (ec, arguments, ref candidate);
3837 return score - 20000;
3839 if (TypeManager.IsGenericMethodDefinition (candidate))
3840 throw new InternalErrorException ("A generic method `{0}' definition took part in overload resolution",
3841 TypeManager.CSharpSignature (candidate));
3843 pd = TypeManager.GetParameterData (candidate);
3846 if (type_arguments != null)
3847 return int.MaxValue - 15000;
3852 // 2. Each argument has to be implicitly convertible to method parameter
3855 Parameter.Modifier p_mod = 0;
3857 for (int i = 0; i < arg_count; i++) {
3858 Argument a = (Argument) arguments [i];
3859 Parameter.Modifier a_mod = a.Modifier &
3860 ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3862 if (p_mod != Parameter.Modifier.PARAMS) {
3863 p_mod = pd.FixedParameters [i].ModFlags & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3865 if (p_mod == Parameter.Modifier.ARGLIST) {
3866 if (a.Type == TypeManager.runtime_argument_handle_type)
3874 params_expanded_form = true;
3878 if (!params_expanded_form)
3879 score = IsArgumentCompatible (ec, a_mod, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
3881 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0) {
3882 // It can be applicable in expanded form
3883 score = IsArgumentCompatible (ec, a_mod, a, 0, pt.GetElementType ());
3885 params_expanded_form = true;
3889 if (params_expanded_form)
3891 return (arg_count - i) * 2 + score;
3895 if (arg_count != param_count)
3896 params_expanded_form = true;
3901 int IsArgumentCompatible (EmitContext ec, Parameter.Modifier arg_mod, Argument argument, Parameter.Modifier param_mod, Type parameter)
3904 // Types have to be identical when ref or out modifer is used
3906 if (arg_mod != 0 || param_mod != 0) {
3907 if (TypeManager.HasElementType (parameter))
3908 parameter = parameter.GetElementType ();
3910 Type a_type = argument.Type;
3911 if (TypeManager.HasElementType (a_type))
3912 a_type = a_type.GetElementType ();
3914 if (a_type != parameter)
3917 if (delegate_type != null ?
3918 !Delegate.IsTypeCovariant (argument.Expr, parameter) :
3919 !Convert.ImplicitConversionExists (ec, argument.Expr, parameter))
3923 if (arg_mod != param_mod)
3929 public static bool IsOverride (MethodBase cand_method, MethodBase base_method)
3931 if (!IsAncestralType (base_method.DeclaringType, cand_method.DeclaringType))
3934 AParametersCollection cand_pd = TypeManager.GetParameterData (cand_method);
3935 AParametersCollection base_pd = TypeManager.GetParameterData (base_method);
3937 if (cand_pd.Count != base_pd.Count)
3940 for (int j = 0; j < cand_pd.Count; ++j)
3942 Parameter.Modifier cm = cand_pd.FixedParameters [j].ModFlags;
3943 Parameter.Modifier bm = base_pd.FixedParameters [j].ModFlags;
3944 Type ct = cand_pd.Types [j];
3945 Type bt = base_pd.Types [j];
3947 if (cm != bm || ct != bt)
3954 public static MethodGroupExpr MakeUnionSet (MethodGroupExpr mg1, MethodGroupExpr mg2, Location loc)
3965 ArrayList all = new ArrayList (mg1.Methods);
3966 foreach (MethodBase m in mg2.Methods){
3967 if (!TypeManager.ArrayContainsMethod (mg1.Methods, m, false))
3971 return new MethodGroupExpr (all, null, loc);
3974 static Type MoreSpecific (Type p, Type q)
3976 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
3978 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
3981 if (TypeManager.HasElementType (p))
3983 Type pe = TypeManager.GetElementType (p);
3984 Type qe = TypeManager.GetElementType (q);
3985 Type specific = MoreSpecific (pe, qe);
3991 else if (TypeManager.IsGenericType (p))
3993 Type[] pargs = TypeManager.GetTypeArguments (p);
3994 Type[] qargs = TypeManager.GetTypeArguments (q);
3996 bool p_specific_at_least_once = false;
3997 bool q_specific_at_least_once = false;
3999 for (int i = 0; i < pargs.Length; i++)
4001 Type specific = MoreSpecific (pargs [i], qargs [i]);
4002 if (specific == pargs [i])
4003 p_specific_at_least_once = true;
4004 if (specific == qargs [i])
4005 q_specific_at_least_once = true;
4008 if (p_specific_at_least_once && !q_specific_at_least_once)
4010 if (!p_specific_at_least_once && q_specific_at_least_once)
4017 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4019 base.MutateHoistedGenericType (storey);
4021 MethodInfo mi = best_candidate as MethodInfo;
4023 best_candidate = storey.MutateGenericMethod (mi);
4027 best_candidate = storey.MutateConstructor ((ConstructorInfo) this);
4031 /// Find the Applicable Function Members (7.4.2.1)
4033 /// me: Method Group expression with the members to select.
4034 /// it might contain constructors or methods (or anything
4035 /// that maps to a method).
4037 /// Arguments: ArrayList containing resolved Argument objects.
4039 /// loc: The location if we want an error to be reported, or a Null
4040 /// location for "probing" purposes.
4042 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4043 /// that is the best match of me on Arguments.
4046 public virtual MethodGroupExpr OverloadResolve (EmitContext ec, ref ArrayList Arguments,
4047 bool may_fail, Location loc)
4049 bool method_params = false;
4050 Type applicable_type = null;
4052 ArrayList candidates = new ArrayList (2);
4053 ArrayList candidate_overrides = null;
4056 // Used to keep a map between the candidate
4057 // and whether it is being considered in its
4058 // normal or expanded form
4060 // false is normal form, true is expanded form
4062 Hashtable candidate_to_form = null;
4064 if (Arguments != null)
4065 arg_count = Arguments.Count;
4067 if (RootContext.Version == LanguageVersion.ISO_1 && Name == "Invoke" && TypeManager.IsDelegateType (DeclaringType)) {
4069 Report.Error (1533, loc, "Invoke cannot be called directly on a delegate");
4073 int nmethods = Methods.Length;
4077 // Methods marked 'override' don't take part in 'applicable_type'
4078 // computation, nor in the actual overload resolution.
4079 // However, they still need to be emitted instead of a base virtual method.
4080 // So, we salt them away into the 'candidate_overrides' array.
4082 // In case of reflected methods, we replace each overriding method with
4083 // its corresponding base virtual method. This is to improve compatibility
4084 // with non-C# libraries which change the visibility of overrides (#75636)
4087 for (int i = 0; i < Methods.Length; ++i) {
4088 MethodBase m = Methods [i];
4089 if (TypeManager.IsOverride (m)) {
4090 if (candidate_overrides == null)
4091 candidate_overrides = new ArrayList ();
4092 candidate_overrides.Add (m);
4093 m = TypeManager.TryGetBaseDefinition (m);
4102 // Enable message recording, it's used mainly by lambda expressions
4104 Report.IMessageRecorder msg_recorder = new Report.MessageRecorder ();
4105 Report.IMessageRecorder prev_recorder = Report.SetMessageRecorder (msg_recorder);
4108 // First we construct the set of applicable methods
4110 bool is_sorted = true;
4111 int best_candidate_rate = int.MaxValue;
4112 for (int i = 0; i < nmethods; i++) {
4113 Type decl_type = Methods [i].DeclaringType;
4116 // If we have already found an applicable method
4117 // we eliminate all base types (Section 14.5.5.1)
4119 if (applicable_type != null && IsAncestralType (decl_type, applicable_type))
4123 // Check if candidate is applicable (section 14.4.2.1)
4125 bool params_expanded_form = false;
4126 int candidate_rate = IsApplicable (ec, Arguments, arg_count, ref Methods [i], ref params_expanded_form);
4128 if (candidate_rate < best_candidate_rate) {
4129 best_candidate_rate = candidate_rate;
4130 best_candidate = Methods [i];
4133 if (params_expanded_form) {
4134 if (candidate_to_form == null)
4135 candidate_to_form = new PtrHashtable ();
4136 MethodBase candidate = Methods [i];
4137 candidate_to_form [candidate] = candidate;
4140 if (candidate_rate != 0) {
4141 if (msg_recorder != null)
4142 msg_recorder.EndSession ();
4146 msg_recorder = null;
4147 candidates.Add (Methods [i]);
4149 if (applicable_type == null)
4150 applicable_type = decl_type;
4151 else if (applicable_type != decl_type) {
4153 if (IsAncestralType (applicable_type, decl_type))
4154 applicable_type = decl_type;
4158 Report.SetMessageRecorder (prev_recorder);
4159 if (msg_recorder != null && !msg_recorder.IsEmpty) {
4161 msg_recorder.PrintMessages ();
4166 int candidate_top = candidates.Count;
4168 if (applicable_type == null) {
4170 // When we found a top level method which does not match and it's
4171 // not an extension method. We start extension methods lookup from here
4173 if (InstanceExpression != null) {
4174 ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (type, Name, loc);
4175 if (ex_method_lookup != null) {
4176 ex_method_lookup.ExtensionExpression = InstanceExpression;
4177 ex_method_lookup.SetTypeArguments (type_arguments);
4178 return ex_method_lookup.OverloadResolve (ec, ref Arguments, may_fail, loc);
4186 // Okay so we have failed to find exact match so we
4187 // return error info about the closest match
4189 if (best_candidate != null) {
4190 if (CustomErrorHandler != null) {
4191 if (CustomErrorHandler.NoExactMatch (ec, best_candidate))
4195 AParametersCollection pd = TypeManager.GetParameterData (best_candidate);
4196 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4197 if (arg_count == pd.Count || pd.HasParams) {
4198 if (TypeManager.IsGenericMethodDefinition (best_candidate)) {
4199 if (type_arguments == null) {
4200 Report.Error (411, loc,
4201 "The type arguments for method `{0}' cannot be inferred from " +
4202 "the usage. Try specifying the type arguments explicitly",
4203 TypeManager.CSharpSignature (best_candidate));
4207 Type [] g_args = TypeManager.GetGenericArguments (best_candidate);
4208 if (type_arguments.Count != g_args.Length) {
4209 Report.SymbolRelatedToPreviousError (best_candidate);
4210 Report.Error (305, loc, "Using the generic method `{0}' requires `{1}' type argument(s)",
4211 TypeManager.CSharpSignature (best_candidate),
4212 g_args.Length.ToString ());
4216 if (type_arguments != null && !TypeManager.IsGenericMethod (best_candidate)) {
4217 Namespace.Error_TypeArgumentsCannotBeUsed (best_candidate, loc);
4222 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate, cand_params, may_fail, loc))
4227 if (almost_matched_members.Count != 0) {
4228 Error_MemberLookupFailed (ec.ContainerType, type, type, ".ctor",
4229 null, MemberTypes.Constructor, AllBindingFlags);
4234 // We failed to find any method with correct argument count
4236 if (Name == ConstructorInfo.ConstructorName) {
4237 Report.SymbolRelatedToPreviousError (type);
4238 Report.Error (1729, loc,
4239 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4240 TypeManager.CSharpName (type), arg_count);
4242 Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4243 Name, arg_count.ToString ());
4251 // At this point, applicable_type is _one_ of the most derived types
4252 // in the set of types containing the methods in this MethodGroup.
4253 // Filter the candidates so that they only contain methods from the
4254 // most derived types.
4257 int finalized = 0; // Number of finalized candidates
4260 // Invariant: applicable_type is a most derived type
4262 // We'll try to complete Section 14.5.5.1 for 'applicable_type' by
4263 // eliminating all it's base types. At the same time, we'll also move
4264 // every unrelated type to the end of the array, and pick the next
4265 // 'applicable_type'.
4267 Type next_applicable_type = null;
4268 int j = finalized; // where to put the next finalized candidate
4269 int k = finalized; // where to put the next undiscarded candidate
4270 for (int i = finalized; i < candidate_top; ++i) {
4271 MethodBase candidate = (MethodBase) candidates [i];
4272 Type decl_type = candidate.DeclaringType;
4274 if (decl_type == applicable_type) {
4275 candidates [k++] = candidates [j];
4276 candidates [j++] = candidates [i];
4280 if (IsAncestralType (decl_type, applicable_type))
4283 if (next_applicable_type != null &&
4284 IsAncestralType (decl_type, next_applicable_type))
4287 candidates [k++] = candidates [i];
4289 if (next_applicable_type == null ||
4290 IsAncestralType (next_applicable_type, decl_type))
4291 next_applicable_type = decl_type;
4294 applicable_type = next_applicable_type;
4297 } while (applicable_type != null);
4301 // Now we actually find the best method
4304 best_candidate = (MethodBase) candidates [0];
4305 if (delegate_type == null)
4306 method_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4308 for (int ix = 1; ix < candidate_top; ix++) {
4309 MethodBase candidate = (MethodBase) candidates [ix];
4311 if (candidate == best_candidate)
4314 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4316 if (BetterFunction (ec, Arguments, arg_count,
4317 candidate, cand_params,
4318 best_candidate, method_params)) {
4319 best_candidate = candidate;
4320 method_params = cand_params;
4324 // Now check that there are no ambiguities i.e the selected method
4325 // should be better than all the others
4327 MethodBase ambiguous = null;
4328 for (int ix = 1; ix < candidate_top; ix++) {
4329 MethodBase candidate = (MethodBase) candidates [ix];
4331 if (candidate == best_candidate)
4334 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4335 if (!BetterFunction (ec, Arguments, arg_count,
4336 best_candidate, method_params,
4337 candidate, cand_params))
4340 Report.SymbolRelatedToPreviousError (candidate);
4341 ambiguous = candidate;
4345 if (ambiguous != null) {
4346 Report.SymbolRelatedToPreviousError (best_candidate);
4347 Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4348 TypeManager.CSharpSignature (ambiguous), TypeManager.CSharpSignature (best_candidate));
4353 // If the method is a virtual function, pick an override closer to the LHS type.
4355 if (!IsBase && best_candidate.IsVirtual) {
4356 if (TypeManager.IsOverride (best_candidate))
4357 throw new InternalErrorException (
4358 "Should not happen. An 'override' method took part in overload resolution: " + best_candidate);
4360 if (candidate_overrides != null) {
4361 Type[] gen_args = null;
4362 bool gen_override = false;
4363 if (TypeManager.IsGenericMethod (best_candidate))
4364 gen_args = TypeManager.GetGenericArguments (best_candidate);
4366 foreach (MethodBase candidate in candidate_overrides) {
4367 if (TypeManager.IsGenericMethod (candidate)) {
4368 if (gen_args == null)
4371 if (gen_args.Length != TypeManager.GetGenericArguments (candidate).Length)
4374 if (gen_args != null)
4378 if (IsOverride (candidate, best_candidate)) {
4379 gen_override = true;
4380 best_candidate = candidate;
4384 if (gen_override && gen_args != null) {
4386 best_candidate = ((MethodInfo) best_candidate).MakeGenericMethod (gen_args);
4393 // And now check if the arguments are all
4394 // compatible, perform conversions if
4395 // necessary etc. and return if everything is
4398 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate,
4399 method_params, may_fail, loc))
4402 if (best_candidate == null)
4405 MethodBase the_method = TypeManager.DropGenericMethodArguments (best_candidate);
4407 if (the_method.IsGenericMethodDefinition &&
4408 !ConstraintChecker.CheckConstraints (ec, the_method, best_candidate, loc))
4412 IMethodData data = TypeManager.GetMethod (the_method);
4414 data.SetMemberIsUsed ();
4419 public override void SetTypeArguments (TypeArguments ta)
4421 type_arguments = ta;
4424 public bool VerifyArgumentsCompat (EmitContext ec, ref ArrayList arguments,
4425 int arg_count, MethodBase method,
4426 bool chose_params_expanded,
4427 bool may_fail, Location loc)
4429 AParametersCollection pd = TypeManager.GetParameterData (method);
4431 int errors = Report.Errors;
4432 Parameter.Modifier p_mod = 0;
4434 int a_idx = 0, a_pos = 0;
4436 ArrayList params_initializers = null;
4437 bool has_unsafe_arg = false;
4439 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4440 a = (Argument) arguments [a_idx];
4441 if (p_mod != Parameter.Modifier.PARAMS) {
4442 p_mod = pd.FixedParameters [a_idx].ModFlags;
4443 pt = pd.Types [a_idx];
4444 has_unsafe_arg |= pt.IsPointer;
4446 if (p_mod == Parameter.Modifier.ARGLIST) {
4447 if (a.Type != TypeManager.runtime_argument_handle_type)
4452 if (p_mod == Parameter.Modifier.PARAMS) {
4453 if (chose_params_expanded) {
4454 params_initializers = new ArrayList (arg_count - a_idx);
4455 pt = TypeManager.GetElementType (pt);
4461 // Types have to be identical when ref or out modifer is used
4463 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4464 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4467 if (!TypeManager.IsEqual (a.Expr.Type, pt))
4473 Expression conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4478 // Convert params arguments to an array initializer
4480 if (params_initializers != null) {
4481 // we choose to use 'a.Expr' rather than 'conv' so that
4482 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
4483 params_initializers.Add (a.Expr);
4484 arguments.RemoveAt (a_idx--);
4489 // Update the argument with the implicit conversion
4494 // Fill not provided arguments required by params modifier
4496 if (params_initializers == null && pd.HasParams && arg_count < pd.Count && a_idx + 1 == pd.Count) {
4497 if (arguments == null)
4498 arguments = new ArrayList (1);
4500 pt = pd.Types [GetApplicableParametersCount (method, pd) - 1];
4501 pt = TypeManager.GetElementType (pt);
4502 has_unsafe_arg |= pt.IsPointer;
4503 params_initializers = new ArrayList (0);
4506 if (a_idx == arg_count) {
4508 // Append an array argument with all params arguments
4510 if (params_initializers != null) {
4511 arguments.Add (new Argument (
4512 new ArrayCreation (new TypeExpression (pt, loc), "[]",
4513 params_initializers, loc).Resolve (ec)));
4516 if (has_unsafe_arg && !ec.InUnsafe) {
4525 if (!may_fail && Report.Errors == errors) {
4526 if (CustomErrorHandler != null)
4527 CustomErrorHandler.NoExactMatch (ec, best_candidate);
4529 Error_InvalidArguments (ec, loc, a_pos, method, a, pd, pt);
4535 public class ConstantExpr : MemberExpr
4539 public ConstantExpr (FieldInfo constant, Location loc)
4541 this.constant = constant;
4545 public override string Name {
4546 get { throw new NotImplementedException (); }
4549 public override bool IsInstance {
4550 get { return !IsStatic; }
4553 public override bool IsStatic {
4554 get { return constant.IsStatic; }
4557 public override Type DeclaringType {
4558 get { return constant.DeclaringType; }
4561 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc, SimpleName original)
4563 constant = TypeManager.GetGenericFieldDefinition (constant);
4565 IConstant ic = TypeManager.GetConstant (constant);
4567 if (constant.IsLiteral) {
4568 ic = new ExternalConstant (constant);
4570 ic = ExternalConstant.CreateDecimal (constant);
4571 // HACK: decimal field was not resolved as constant
4573 return new FieldExpr (constant, loc).ResolveMemberAccess (ec, left, loc, original);
4575 TypeManager.RegisterConstant (constant, ic);
4578 return base.ResolveMemberAccess (ec, left, loc, original);
4581 public override Expression CreateExpressionTree (EmitContext ec)
4583 throw new NotSupportedException ("ET");
4586 public override Expression DoResolve (EmitContext ec)
4588 IConstant ic = TypeManager.GetConstant (constant);
4589 if (ic.ResolveValue ()) {
4590 if (!ec.IsInObsoleteScope)
4591 ic.CheckObsoleteness (loc);
4594 return ic.CreateConstantReference (loc);
4597 public override void Emit (EmitContext ec)
4599 throw new NotSupportedException ();
4602 public override string GetSignatureForError ()
4604 return TypeManager.GetFullNameSignature (constant);
4609 /// Fully resolved expression that evaluates to a Field
4611 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariableReference {
4612 public FieldInfo FieldInfo;
4613 readonly Type constructed_generic_type;
4614 VariableInfo variable_info;
4616 LocalTemporary temp;
4618 bool in_initializer;
4620 public FieldExpr (FieldInfo fi, Location l, bool in_initializer):
4623 this.in_initializer = in_initializer;
4626 public FieldExpr (FieldInfo fi, Location l)
4629 eclass = ExprClass.Variable;
4630 type = TypeManager.TypeToCoreType (fi.FieldType);
4634 public FieldExpr (FieldInfo fi, Type genericType, Location l)
4637 this.constructed_generic_type = genericType;
4640 public override string Name {
4642 return FieldInfo.Name;
4646 public override bool IsInstance {
4648 return !FieldInfo.IsStatic;
4652 public override bool IsStatic {
4654 return FieldInfo.IsStatic;
4658 public override Type DeclaringType {
4660 return FieldInfo.DeclaringType;
4664 public override string GetSignatureForError ()
4666 return TypeManager.GetFullNameSignature (FieldInfo);
4669 public VariableInfo VariableInfo {
4671 return variable_info;
4675 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
4676 SimpleName original)
4678 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
4679 Type t = fi.FieldType;
4681 if (t.IsPointer && !ec.InUnsafe) {
4685 return base.ResolveMemberAccess (ec, left, loc, original);
4688 public void SetHasAddressTaken ()
4690 IVariableReference vr = InstanceExpression as IVariableReference;
4692 vr.SetHasAddressTaken ();
4695 public override Expression CreateExpressionTree (EmitContext ec)
4697 Expression instance;
4698 if (InstanceExpression == null) {
4699 instance = new NullLiteral (loc);
4701 instance = InstanceExpression.CreateExpressionTree (ec);
4704 ArrayList args = new ArrayList (2);
4705 args.Add (new Argument (instance));
4706 args.Add (new Argument (CreateTypeOfExpression ()));
4707 return CreateExpressionFactoryCall ("Field", args);
4710 public Expression CreateTypeOfExpression ()
4712 return new TypeOfField (FieldInfo, loc);
4715 override public Expression DoResolve (EmitContext ec)
4717 return DoResolve (ec, false, false);
4720 Expression DoResolve (EmitContext ec, bool lvalue_instance, bool out_access)
4722 if (!FieldInfo.IsStatic){
4723 if (InstanceExpression == null){
4725 // This can happen when referencing an instance field using
4726 // a fully qualified type expression: TypeName.InstanceField = xxx
4728 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4732 // Resolve the field's instance expression while flow analysis is turned
4733 // off: when accessing a field "a.b", we must check whether the field
4734 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4736 if (lvalue_instance) {
4737 using (ec.With (EmitContext.Flags.DoFlowAnalysis, false)) {
4738 Expression right_side =
4739 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4740 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side, loc);
4743 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
4744 InstanceExpression = InstanceExpression.Resolve (ec, rf);
4747 if (InstanceExpression == null)
4750 using (ec.Set (EmitContext.Flags.OmitStructFlowAnalysis)) {
4751 InstanceExpression.CheckMarshalByRefAccess (ec);
4755 if (!in_initializer && !ec.IsInFieldInitializer) {
4756 ObsoleteAttribute oa;
4757 FieldBase f = TypeManager.GetField (FieldInfo);
4759 if (!ec.IsInObsoleteScope)
4760 f.CheckObsoleteness (loc);
4762 // To be sure that type is external because we do not register generated fields
4763 } else if (!(FieldInfo.DeclaringType is TypeBuilder)) {
4764 oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
4766 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
4770 IFixedBuffer fb = AttributeTester.GetFixedBuffer (FieldInfo);
4771 IVariableReference var = InstanceExpression as IVariableReference;
4774 if (!ec.InFixedInitializer && ec.ContainerType.IsValueType) {
4775 Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4778 if (InstanceExpression.eclass != ExprClass.Variable) {
4779 Report.SymbolRelatedToPreviousError (FieldInfo);
4780 Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4781 TypeManager.GetFullNameSignature (FieldInfo));
4782 } else if (var != null && var.IsHoisted) {
4783 AnonymousMethodExpression.Error_AddressOfCapturedVar (var, loc);
4786 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4789 // If the instance expression is a local variable or parameter.
4790 if (var == null || var.VariableInfo == null)
4793 VariableInfo vi = var.VariableInfo;
4794 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
4797 variable_info = vi.GetSubStruct (FieldInfo.Name);
4801 static readonly int [] codes = {
4802 191, // instance, write access
4803 192, // instance, out access
4804 198, // static, write access
4805 199, // static, out access
4806 1648, // member of value instance, write access
4807 1649, // member of value instance, out access
4808 1650, // member of value static, write access
4809 1651 // member of value static, out access
4812 static readonly string [] msgs = {
4813 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4814 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4815 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4816 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4817 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4818 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4819 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4820 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4823 // The return value is always null. Returning a value simplifies calling code.
4824 Expression Report_AssignToReadonly (Expression right_side)
4827 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4831 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4833 Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4838 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4840 IVariableReference var = InstanceExpression as IVariableReference;
4841 if (var != null && var.VariableInfo != null)
4842 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
4844 bool lvalue_instance = !FieldInfo.IsStatic && FieldInfo.DeclaringType.IsValueType;
4845 bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
4847 Expression e = DoResolve (ec, lvalue_instance, out_access);
4852 FieldBase fb = TypeManager.GetField (FieldInfo);
4856 if (FieldInfo.IsInitOnly) {
4857 // InitOnly fields can only be assigned in constructors or initializers
4858 if (!ec.IsInFieldInitializer && !ec.IsConstructor)
4859 return Report_AssignToReadonly (right_side);
4861 if (ec.IsConstructor) {
4862 Type ctype = ec.TypeContainer.CurrentType;
4864 ctype = ec.ContainerType;
4866 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4867 if (!TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
4868 return Report_AssignToReadonly (right_side);
4869 // static InitOnly fields cannot be assigned-to in an instance constructor
4870 if (IsStatic && !ec.IsStatic)
4871 return Report_AssignToReadonly (right_side);
4872 // instance constructors can't modify InitOnly fields of other instances of the same type
4873 if (!IsStatic && !(InstanceExpression is This))
4874 return Report_AssignToReadonly (right_side);
4878 if (right_side == EmptyExpression.OutAccess &&
4879 !IsStatic && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type)) {
4880 Report.SymbolRelatedToPreviousError (DeclaringType);
4881 Report.Warning (197, 1, loc,
4882 "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",
4883 GetSignatureForError ());
4889 bool is_marshal_by_ref ()
4891 return !IsStatic && Type.IsValueType && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type);
4894 public override void CheckMarshalByRefAccess (EmitContext ec)
4896 if (is_marshal_by_ref () && !(InstanceExpression is This)) {
4897 Report.SymbolRelatedToPreviousError (DeclaringType);
4898 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",
4899 GetSignatureForError ());
4903 public override int GetHashCode ()
4905 return FieldInfo.GetHashCode ();
4908 public bool IsFixedVariable {
4911 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
4913 IVariableReference variable = InstanceExpression as IVariableReference;
4914 return variable != null && InstanceExpression.Type.IsValueType && variable.IsFixedVariable;
4918 public bool IsHoisted {
4920 IVariableReference hv = InstanceExpression as IVariableReference;
4921 return hv != null && hv.IsHoisted;
4925 public override bool Equals (object obj)
4927 FieldExpr fe = obj as FieldExpr;
4931 if (FieldInfo != fe.FieldInfo)
4934 if (InstanceExpression == null || fe.InstanceExpression == null)
4937 return InstanceExpression.Equals (fe.InstanceExpression);
4940 public void Emit (EmitContext ec, bool leave_copy)
4942 ILGenerator ig = ec.ig;
4943 bool is_volatile = false;
4945 FieldBase f = TypeManager.GetField (FieldInfo);
4947 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4950 f.SetMemberIsUsed ();
4953 if (FieldInfo.IsStatic){
4955 ig.Emit (OpCodes.Volatile);
4957 ig.Emit (OpCodes.Ldsfld, GetConstructedFieldInfo ());
4960 EmitInstance (ec, false);
4962 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
4964 ig.Emit (OpCodes.Ldflda, GetConstructedFieldInfo ());
4965 ig.Emit (OpCodes.Ldflda, ff.Element);
4968 ig.Emit (OpCodes.Volatile);
4970 ig.Emit (OpCodes.Ldfld, GetConstructedFieldInfo ());
4975 ec.ig.Emit (OpCodes.Dup);
4976 if (!FieldInfo.IsStatic) {
4977 temp = new LocalTemporary (this.Type);
4983 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4985 FieldAttributes fa = FieldInfo.Attributes;
4986 bool is_static = (fa & FieldAttributes.Static) != 0;
4987 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
4988 ILGenerator ig = ec.ig;
4990 if (is_readonly && !ec.IsConstructor){
4991 Report_AssignToReadonly (source);
4995 prepared = prepare_for_load;
4996 EmitInstance (ec, prepared);
5000 ec.ig.Emit (OpCodes.Dup);
5001 if (!FieldInfo.IsStatic) {
5002 temp = new LocalTemporary (this.Type);
5007 FieldBase f = TypeManager.GetField (FieldInfo);
5009 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
5010 ig.Emit (OpCodes.Volatile);
5016 ig.Emit (OpCodes.Stsfld, GetConstructedFieldInfo ());
5018 ig.Emit (OpCodes.Stfld, GetConstructedFieldInfo ());
5027 public override void Emit (EmitContext ec)
5032 public override void EmitSideEffect (EmitContext ec)
5034 FieldBase f = TypeManager.GetField (FieldInfo);
5035 bool is_volatile = f != null && (f.ModFlags & Modifiers.VOLATILE) != 0;
5037 if (is_volatile || is_marshal_by_ref ())
5038 base.EmitSideEffect (ec);
5041 public override void Error_VariableIsUsedBeforeItIsDeclared (string name)
5043 Report.Error (844, loc,
5044 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the field `{1}'",
5045 name, GetSignatureForError ());
5048 public void AddressOf (EmitContext ec, AddressOp mode)
5050 ILGenerator ig = ec.ig;
5052 FieldBase f = TypeManager.GetField (FieldInfo);
5054 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
5055 Report.Warning (420, 1, loc, "`{0}': A volatile field references will not be treated as volatile",
5056 f.GetSignatureForError ());
5059 if ((mode & AddressOp.Store) != 0)
5061 if ((mode & AddressOp.Load) != 0)
5062 f.SetMemberIsUsed ();
5066 // Handle initonly fields specially: make a copy and then
5067 // get the address of the copy.
5070 if (FieldInfo.IsInitOnly){
5072 if (ec.IsConstructor){
5073 if (FieldInfo.IsStatic){
5085 local = ig.DeclareLocal (type);
5086 ig.Emit (OpCodes.Stloc, local);
5087 ig.Emit (OpCodes.Ldloca, local);
5092 if (FieldInfo.IsStatic){
5093 ig.Emit (OpCodes.Ldsflda, GetConstructedFieldInfo ());
5096 EmitInstance (ec, false);
5097 ig.Emit (OpCodes.Ldflda, GetConstructedFieldInfo ());
5101 FieldInfo GetConstructedFieldInfo ()
5103 if (constructed_generic_type == null)
5106 return TypeBuilder.GetField (constructed_generic_type, FieldInfo);
5108 throw new NotSupportedException ();
5112 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5114 FieldInfo = storey.MutateField (FieldInfo);
5115 base.MutateHoistedGenericType (storey);
5121 /// Expression that evaluates to a Property. The Assign class
5122 /// might set the `Value' expression if we are in an assignment.
5124 /// This is not an LValue because we need to re-write the expression, we
5125 /// can not take data from the stack and store it.
5127 public class PropertyExpr : MemberExpr, IAssignMethod {
5128 public readonly PropertyInfo PropertyInfo;
5129 MethodInfo getter, setter;
5134 LocalTemporary temp;
5137 public PropertyExpr (Type container_type, PropertyInfo pi, Location l)
5140 eclass = ExprClass.PropertyAccess;
5144 type = TypeManager.TypeToCoreType (pi.PropertyType);
5146 ResolveAccessors (container_type);
5149 public override string Name {
5151 return PropertyInfo.Name;
5155 public override bool IsInstance {
5161 public override bool IsStatic {
5167 public override Expression CreateExpressionTree (EmitContext ec)
5170 if (IsSingleDimensionalArrayLength ()) {
5171 args = new ArrayList (1);
5172 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5173 return CreateExpressionFactoryCall ("ArrayLength", args);
5177 Error_BaseAccessInExpressionTree (loc);
5181 args = new ArrayList (2);
5182 if (InstanceExpression == null)
5183 args.Add (new Argument (new NullLiteral (loc)));
5185 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5186 args.Add (new Argument (new TypeOfMethodInfo (getter, loc)));
5187 return CreateExpressionFactoryCall ("Property", args);
5190 public Expression CreateSetterTypeOfExpression ()
5192 return new TypeOfMethodInfo (setter, loc);
5195 public override Type DeclaringType {
5197 return PropertyInfo.DeclaringType;
5201 public override string GetSignatureForError ()
5203 return TypeManager.GetFullNameSignature (PropertyInfo);
5206 void FindAccessors (Type invocation_type)
5208 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
5209 BindingFlags.Static | BindingFlags.Instance |
5210 BindingFlags.DeclaredOnly;
5212 Type current = PropertyInfo.DeclaringType;
5213 for (; current != null; current = current.BaseType) {
5214 MemberInfo[] group = TypeManager.MemberLookup (
5215 invocation_type, invocation_type, current,
5216 MemberTypes.Property, flags, PropertyInfo.Name, null);
5221 if (group.Length != 1)
5222 // Oooops, can this ever happen ?
5225 PropertyInfo pi = (PropertyInfo) group [0];
5228 getter = pi.GetGetMethod (true);
5231 setter = pi.GetSetMethod (true);
5233 MethodInfo accessor = getter != null ? getter : setter;
5235 if (!accessor.IsVirtual)
5241 // We also perform the permission checking here, as the PropertyInfo does not
5242 // hold the information for the accessibility of its setter/getter
5244 // TODO: Refactor to use some kind of cache together with GetPropertyFromAccessor
5245 void ResolveAccessors (Type container_type)
5247 FindAccessors (container_type);
5249 if (getter != null) {
5250 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
5251 IMethodData md = TypeManager.GetMethod (the_getter);
5253 md.SetMemberIsUsed ();
5255 is_static = getter.IsStatic;
5258 if (setter != null) {
5259 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
5260 IMethodData md = TypeManager.GetMethod (the_setter);
5262 md.SetMemberIsUsed ();
5264 is_static = setter.IsStatic;
5268 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5270 if (InstanceExpression != null)
5271 InstanceExpression.MutateHoistedGenericType (storey);
5273 type = storey.MutateType (type);
5274 getter = storey.MutateGenericMethod (getter);
5277 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
5280 InstanceExpression = null;
5284 if (InstanceExpression == null) {
5285 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5289 InstanceExpression = InstanceExpression.DoResolve (ec);
5290 if (lvalue_instance && InstanceExpression != null)
5291 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
5293 if (InstanceExpression == null)
5296 InstanceExpression.CheckMarshalByRefAccess (ec);
5298 if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) &&
5299 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
5300 !TypeManager.IsNestedChildOf (ec.ContainerType, InstanceExpression.Type) &&
5301 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.ContainerType)) {
5302 Report.SymbolRelatedToPreviousError (PropertyInfo);
5303 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
5310 void Error_PropertyNotFound (MethodInfo mi, bool getter)
5312 // TODO: correctly we should compare arguments but it will lead to bigger changes
5313 if (mi is MethodBuilder) {
5314 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
5318 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
5320 AParametersCollection iparams = TypeManager.GetParameterData (mi);
5321 sig.Append (getter ? "get_" : "set_");
5323 sig.Append (iparams.GetSignatureForError ());
5325 Report.SymbolRelatedToPreviousError (mi);
5326 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
5327 Name, sig.ToString ());
5330 public bool IsAccessibleFrom (Type invocation_type, bool lvalue)
5333 MethodInfo accessor = lvalue ? setter : getter;
5334 if (accessor == null && lvalue)
5336 return accessor != null && IsAccessorAccessible (invocation_type, accessor, out dummy);
5339 bool IsSingleDimensionalArrayLength ()
5341 if (DeclaringType != TypeManager.array_type || getter == null || Name != "Length")
5344 string t_name = InstanceExpression.Type.Name;
5345 int t_name_len = t_name.Length;
5346 return t_name_len > 2 && t_name [t_name_len - 2] == '[';
5349 override public Expression DoResolve (EmitContext ec)
5354 if (getter != null){
5355 if (TypeManager.GetParameterData (getter).Count != 0){
5356 Error_PropertyNotFound (getter, true);
5361 if (getter == null){
5363 // The following condition happens if the PropertyExpr was
5364 // created, but is invalid (ie, the property is inaccessible),
5365 // and we did not want to embed the knowledge about this in
5366 // the caller routine. This only avoids double error reporting.
5371 if (InstanceExpression != EmptyExpression.Null) {
5372 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5373 TypeManager.GetFullNameSignature (PropertyInfo));
5378 bool must_do_cs1540_check = false;
5379 if (getter != null &&
5380 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
5381 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
5382 if (pm != null && pm.HasCustomAccessModifier) {
5383 Report.SymbolRelatedToPreviousError (pm);
5384 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5385 TypeManager.CSharpSignature (getter));
5388 Report.SymbolRelatedToPreviousError (getter);
5389 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
5394 if (!InstanceResolve (ec, false, must_do_cs1540_check))
5398 // Only base will allow this invocation to happen.
5400 if (IsBase && getter.IsAbstract) {
5401 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5405 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
5415 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
5417 if (right_side == EmptyExpression.OutAccess) {
5418 if (ec.CurrentBlock.Toplevel.GetTransparentIdentifier (PropertyInfo.Name) != null) {
5419 Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5422 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as `ref' or `out' parameter",
5423 GetSignatureForError ());
5428 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5429 Error_CannotModifyIntermediateExpressionValue (ec);
5432 if (setter == null){
5434 // The following condition happens if the PropertyExpr was
5435 // created, but is invalid (ie, the property is inaccessible),
5436 // and we did not want to embed the knowledge about this in
5437 // the caller routine. This only avoids double error reporting.
5442 if (ec.CurrentBlock.Toplevel.GetTransparentIdentifier (PropertyInfo.Name) != null) {
5443 Report.Error (1947, loc, "A range variable `{0}' cannot be assigned to. Consider using `let' clause to store the value",
5446 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
5447 GetSignatureForError ());
5452 if (TypeManager.GetParameterData (setter).Count != 1){
5453 Error_PropertyNotFound (setter, false);
5457 bool must_do_cs1540_check;
5458 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
5459 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
5460 if (pm != null && pm.HasCustomAccessModifier) {
5461 Report.SymbolRelatedToPreviousError (pm);
5462 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5463 TypeManager.CSharpSignature (setter));
5466 Report.SymbolRelatedToPreviousError (setter);
5467 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
5472 if (!InstanceResolve (ec, PropertyInfo.DeclaringType.IsValueType, must_do_cs1540_check))
5476 // Only base will allow this invocation to happen.
5478 if (IsBase && setter.IsAbstract){
5479 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5483 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe) {
5490 public override void Emit (EmitContext ec)
5495 public void Emit (EmitContext ec, bool leave_copy)
5498 // Special case: length of single dimension array property is turned into ldlen
5500 if (IsSingleDimensionalArrayLength ()) {
5502 EmitInstance (ec, false);
5503 ec.ig.Emit (OpCodes.Ldlen);
5504 ec.ig.Emit (OpCodes.Conv_I4);
5508 Invocation.EmitCall (ec, IsBase, InstanceExpression, getter, null, loc, prepared, false);
5511 ec.ig.Emit (OpCodes.Dup);
5513 temp = new LocalTemporary (this.Type);
5520 // Implements the IAssignMethod interface for assignments
5522 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5524 Expression my_source = source;
5526 if (prepare_for_load) {
5531 ec.ig.Emit (OpCodes.Dup);
5533 temp = new LocalTemporary (this.Type);
5537 } else if (leave_copy) {
5539 temp = new LocalTemporary (this.Type);
5544 ArrayList args = new ArrayList (1);
5545 args.Add (new Argument (my_source, Argument.AType.Expression));
5547 Invocation.EmitCall (ec, IsBase, InstanceExpression, setter, args, loc, false, prepared);
5557 /// Fully resolved expression that evaluates to an Event
5559 public class EventExpr : MemberExpr {
5560 public readonly EventInfo EventInfo;
5563 MethodInfo add_accessor, remove_accessor;
5565 public EventExpr (EventInfo ei, Location loc)
5569 eclass = ExprClass.EventAccess;
5571 add_accessor = TypeManager.GetAddMethod (ei);
5572 remove_accessor = TypeManager.GetRemoveMethod (ei);
5573 if (add_accessor.IsStatic || remove_accessor.IsStatic)
5576 if (EventInfo is MyEventBuilder){
5577 MyEventBuilder eb = (MyEventBuilder) EventInfo;
5578 type = eb.EventType;
5581 type = EventInfo.EventHandlerType;
5584 public override string Name {
5586 return EventInfo.Name;
5590 public override bool IsInstance {
5596 public override bool IsStatic {
5602 public override Type DeclaringType {
5604 return EventInfo.DeclaringType;
5608 void Error_AssignmentEventOnly ()
5610 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5611 GetSignatureForError ());
5614 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
5615 SimpleName original)
5618 // If the event is local to this class, we transform ourselves into a FieldExpr
5621 if (EventInfo.DeclaringType == ec.ContainerType ||
5622 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
5623 EventField mi = TypeManager.GetEventField (EventInfo);
5626 if (!ec.IsInObsoleteScope)
5627 mi.CheckObsoleteness (loc);
5629 if ((mi.ModFlags & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0 && !ec.IsInCompoundAssignment)
5630 Error_AssignmentEventOnly ();
5632 FieldExpr ml = new FieldExpr (mi.FieldBuilder, loc);
5634 InstanceExpression = null;
5636 return ml.ResolveMemberAccess (ec, left, loc, original);
5640 if (left is This && !ec.IsInCompoundAssignment)
5641 Error_AssignmentEventOnly ();
5643 return base.ResolveMemberAccess (ec, left, loc, original);
5646 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
5649 InstanceExpression = null;
5653 if (InstanceExpression == null) {
5654 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5658 InstanceExpression = InstanceExpression.DoResolve (ec);
5659 if (InstanceExpression == null)
5662 if (IsBase && add_accessor.IsAbstract) {
5663 Error_CannotCallAbstractBase(TypeManager.CSharpSignature(add_accessor));
5668 // This is using the same mechanism as the CS1540 check in PropertyExpr.
5669 // However, in the Event case, we reported a CS0122 instead.
5671 // TODO: Exact copy from PropertyExpr
5673 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
5674 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
5675 !TypeManager.IsNestedChildOf (ec.ContainerType, InstanceExpression.Type) &&
5676 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.ContainerType)) {
5677 Report.SymbolRelatedToPreviousError (EventInfo);
5678 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5685 public bool IsAccessibleFrom (Type invocation_type)
5688 return IsAccessorAccessible (invocation_type, add_accessor, out dummy) &&
5689 IsAccessorAccessible (invocation_type, remove_accessor, out dummy);
5692 public override Expression CreateExpressionTree (EmitContext ec)
5694 throw new NotSupportedException ("ET");
5697 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5699 // contexts where an LValue is valid have already devolved to FieldExprs
5700 Error_CannotAssign ();
5704 public override Expression DoResolve (EmitContext ec)
5706 bool must_do_cs1540_check;
5707 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
5708 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
5709 Report.SymbolRelatedToPreviousError (EventInfo);
5710 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5714 if (!InstanceResolve (ec, must_do_cs1540_check))
5717 if (!ec.IsInCompoundAssignment) {
5718 Error_CannotAssign ();
5725 public override void Emit (EmitContext ec)
5727 Error_CannotAssign ();
5730 public void Error_CannotAssign ()
5732 Report.Error (70, loc,
5733 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
5734 GetSignatureForError (), TypeManager.CSharpName (EventInfo.DeclaringType));
5737 public override string GetSignatureForError ()
5739 return TypeManager.CSharpSignature (EventInfo);
5742 public void EmitAddOrRemove (EmitContext ec, bool is_add, Expression source)
5744 ArrayList args = new ArrayList (1);
5745 args.Add (new Argument (source, Argument.AType.Expression));
5746 Invocation.EmitCall (ec, IsBase, InstanceExpression, is_add ? add_accessor : remove_accessor, args, loc);
5750 public class TemporaryVariable : VariableReference
5754 public TemporaryVariable (Type type, Location loc)
5758 eclass = ExprClass.Variable;
5761 public override Expression CreateExpressionTree (EmitContext ec)
5763 throw new NotSupportedException ("ET");
5766 public override Expression DoResolve (EmitContext ec)
5771 TypeExpr te = new TypeExpression (type, loc);
5772 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
5773 if (!li.Resolve (ec))
5777 // Don't capture temporary variables except when using
5778 // iterator redirection
5780 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.IsIterator && ec.IsVariableCapturingRequired) {
5781 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
5782 storey.CaptureLocalVariable (ec, li);
5788 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5790 return DoResolve (ec);
5793 public override void Emit (EmitContext ec)
5798 public void EmitAssign (EmitContext ec, Expression source)
5800 EmitAssign (ec, source, false, false);
5803 public override HoistedVariable HoistedVariable {
5804 get { return li.HoistedVariableReference; }
5807 public override bool IsFixedVariable {
5808 get { return true; }
5811 public override bool IsRef {
5812 get { return false; }
5815 public override string Name {
5816 get { throw new NotImplementedException (); }
5819 public override void SetHasAddressTaken ()
5821 throw new NotImplementedException ();
5824 protected override ILocalVariable Variable {
5828 public override VariableInfo VariableInfo {
5829 get { throw new NotImplementedException (); }
5834 /// Handles `var' contextual keyword; var becomes a keyword only
5835 /// if no type called var exists in a variable scope
5837 public class VarExpr : SimpleName
5839 // Used for error reporting only
5840 ArrayList initializer;
5842 public VarExpr (Location loc)
5847 public ArrayList VariableInitializer {
5849 this.initializer = value;
5853 public bool InferType (EmitContext ec, Expression right_side)
5856 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
5858 type = right_side.Type;
5859 if (type == TypeManager.null_type || type == TypeManager.void_type || type == TypeManager.anonymous_method_type) {
5860 Report.Error (815, loc, "An implicitly typed local variable declaration cannot be initialized with `{0}'",
5861 right_side.GetSignatureForError ());
5865 eclass = ExprClass.Variable;
5869 protected override void Error_TypeOrNamespaceNotFound (IResolveContext ec)
5871 Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");
5874 public override TypeExpr ResolveAsContextualType (IResolveContext rc, bool silent)
5876 TypeExpr te = base.ResolveAsContextualType (rc, true);
5880 if (initializer == null)
5883 if (initializer.Count > 1) {
5884 Location loc = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [1]).Location;
5885 Report.Error (819, loc, "An implicitly typed local variable declaration cannot include multiple declarators");
5890 Expression variable_initializer = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [0]).expression_or_array_initializer;
5891 if (variable_initializer == null) {
5892 Report.Error (818, loc, "An implicitly typed local variable declarator must include an initializer");