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 // (C) 2001, 2002, 2003 Ximian, Inc.
12 namespace Mono.CSharp {
14 using System.Collections;
15 using System.Diagnostics;
16 using System.Reflection;
17 using System.Reflection.Emit;
21 /// The ExprClass class contains the is used to pass the
22 /// classification of an expression (value, variable, namespace,
23 /// type, method group, property access, event access, indexer access,
26 public enum ExprClass : byte {
41 /// This is used to tell Resolve in which types of expressions we're
45 public enum ResolveFlags {
46 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
49 // Returns a type expression.
52 // Returns a method group.
55 // Mask of all the expression class flags.
58 // Disable control flow analysis while resolving the expression.
59 // This is used when resolving the instance expression of a field expression.
60 DisableFlowAnalysis = 8,
62 // Set if this is resolving the first part of a MemberAccess.
65 // Disable control flow analysis _of struct_ while resolving the expression.
66 // This is used when resolving the instance expression of a field expression.
67 DisableStructFlowAnalysis = 32,
72 // This is just as a hint to AddressOf of what will be done with the
75 public enum AddressOp {
82 /// This interface is implemented by variables
84 public interface IMemoryLocation {
86 /// The AddressOf method should generate code that loads
87 /// the address of the object and leaves it on the stack.
89 /// The `mode' argument is used to notify the expression
90 /// of whether this will be used to read from the address or
91 /// write to the address.
93 /// This is just a hint that can be used to provide good error
94 /// reporting, and should have no other side effects.
96 void AddressOf (EmitContext ec, AddressOp mode);
100 /// This interface is implemented by variables
102 public interface IVariable {
103 VariableInfo VariableInfo {
111 /// Base class for expressions
113 public abstract class Expression {
114 public ExprClass eclass;
116 protected Location loc;
120 set { type = value; }
123 public virtual Location Location {
128 /// Utility wrapper routine for Error, just to beautify the code
130 public void Error (int error, string s)
132 Report.Error (error, loc, s);
135 // Not nice but we have broken hierarchy.
136 public virtual void CheckMarshalByRefAccess (EmitContext ec)
140 public virtual bool GetAttributableValue (Type value_type, out object value)
142 Attribute.Error_AttributeArgumentNotValid (loc);
147 public virtual string GetSignatureForError ()
149 return TypeManager.CSharpName (type);
152 public static bool IsAccessorAccessible (Type invocation_type, MethodInfo mi, out bool must_do_cs1540_check)
154 MethodAttributes ma = mi.Attributes & MethodAttributes.MemberAccessMask;
156 must_do_cs1540_check = false; // by default we do not check for this
158 if (ma == MethodAttributes.Public)
162 // If only accessible to the current class or children
164 if (ma == MethodAttributes.Private)
165 return TypeManager.IsPrivateAccessible (invocation_type, mi.DeclaringType) ||
166 TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType);
168 if (TypeManager.IsThisOrFriendAssembly (mi.DeclaringType.Assembly)) {
169 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamORAssem)
172 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamANDAssem)
176 // Family and FamANDAssem require that we derive.
177 // FamORAssem requires that we derive if in different assemblies.
178 if (!TypeManager.IsNestedFamilyAccessible (invocation_type, mi.DeclaringType))
181 if (!TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType))
182 must_do_cs1540_check = true;
187 public virtual bool IsNull {
194 /// Performs semantic analysis on the Expression
198 /// The Resolve method is invoked to perform the semantic analysis
201 /// The return value is an expression (it can be the
202 /// same expression in some cases) or a new
203 /// expression that better represents this node.
205 /// For example, optimizations of Unary (LiteralInt)
206 /// would return a new LiteralInt with a negated
209 /// If there is an error during semantic analysis,
210 /// then an error should be reported (using Report)
211 /// and a null value should be returned.
213 /// There are two side effects expected from calling
214 /// Resolve(): the the field variable "eclass" should
215 /// be set to any value of the enumeration
216 /// `ExprClass' and the type variable should be set
217 /// to a valid type (this is the type of the
220 public abstract Expression DoResolve (EmitContext ec);
222 public virtual Expression DoResolveLValue (EmitContext ec, Expression right_side)
228 // This is used if the expression should be resolved as a type or namespace name.
229 // the default implementation fails.
231 public virtual FullNamedExpression ResolveAsTypeStep (IResolveContext rc, bool silent)
235 EmitContext ec = rc as EmitContext;
239 e.Error_UnexpectedKind (ResolveFlags.Type, loc);
245 // C# 3.0 introduced contextual keywords (var) which behaves like a type if type with
246 // same name exists or as a keyword when no type was found
248 public virtual TypeExpr ResolveAsContextualType (IResolveContext rc, bool silent)
250 return ResolveAsTypeTerminal (rc, silent);
254 // This is used to resolve the expression as a type, a null
255 // value will be returned if the expression is not a type
258 public virtual TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
260 TypeExpr te = ResolveAsBaseTerminal (ec, silent);
264 if (!silent) { // && !(te is TypeParameterExpr)) {
265 ObsoleteAttribute obsolete_attr = AttributeTester.GetObsoleteAttribute (te.Type);
266 if (obsolete_attr != null && !ec.IsInObsoleteScope) {
267 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location);
271 // Constrains don't need to be checked for overrides
272 GenericMethod gm = ec.GenericDeclContainer as GenericMethod;
273 if (gm != null && (gm.ModFlags & Modifiers.OVERRIDE) != 0) {
278 ConstructedType ct = te as ConstructedType;
279 if ((ct != null) && !ct.CheckConstraints (ec))
285 public TypeExpr ResolveAsBaseTerminal (IResolveContext ec, bool silent)
287 int errors = Report.Errors;
289 FullNamedExpression fne = ResolveAsTypeStep (ec, silent);
294 if (fne.eclass != ExprClass.Type) {
295 if (!silent && errors == Report.Errors)
296 fne.Error_UnexpectedKind (null, "type", loc);
300 TypeExpr te = fne as TypeExpr;
302 if (!te.CheckAccessLevel (ec.DeclContainer)) {
303 Report.SymbolRelatedToPreviousError (te.Type);
304 ErrorIsInaccesible (loc, TypeManager.CSharpName (te.Type));
312 public static void ErrorIsInaccesible (Location loc, string name)
314 Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", name);
317 protected static void Error_CannotAccessProtected (Location loc, MemberInfo m, Type qualifier, Type container)
319 Report.Error (1540, loc, "Cannot access protected member `{0}' via a qualifier of type `{1}'."
320 + " The qualifier must be of type `{2}' or derived from it",
321 TypeManager.GetFullNameSignature (m),
322 TypeManager.CSharpName (qualifier),
323 TypeManager.CSharpName (container));
327 public static void Error_InvalidExpressionStatement (Location loc)
329 Report.Error (201, loc, "Only assignment, call, increment, decrement, and new object " +
330 "expressions can be used as a statement");
333 public void Error_InvalidExpressionStatement ()
335 Error_InvalidExpressionStatement (loc);
338 protected void Error_CannotAssign (string to, string roContext)
340 Report.Error (1656, loc, "Cannot assign to `{0}' because it is a `{1}'",
344 public static void Error_VoidInvalidInTheContext (Location loc)
346 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
349 public virtual void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl)
351 // The error was already reported as CS1660
352 if (type == TypeManager.anonymous_method_type)
355 if (TypeManager.IsGenericParameter (Type) && TypeManager.IsGenericParameter (target) && type.Name == target.Name) {
357 string sig1 = type.DeclaringMethod == null ?
358 TypeManager.CSharpName (type.DeclaringType) :
359 TypeManager.CSharpSignature (type.DeclaringMethod);
360 string sig2 = target.DeclaringMethod == null ?
361 TypeManager.CSharpName (target.DeclaringType) :
362 TypeManager.CSharpSignature (target.DeclaringMethod);
363 Report.ExtraInformation (loc,
365 "The generic parameter `{0}' of `{1}' cannot be converted to the generic parameter `{0}' of `{2}' (in the previous ",
366 Type.Name, sig1, sig2));
368 } else if (Type.FullName == target.FullName){
369 Report.ExtraInformation (loc,
371 "The type `{0}' has two conflicting definitions, one comes from `{1}' and the other from `{2}' (in the previous ",
372 Type.FullName, Type.Assembly.FullName, target.Assembly.FullName));
376 Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
377 TypeManager.CSharpName (type), TypeManager.CSharpName (target));
381 Expression e = (this is EnumConstant) ? ((EnumConstant)this).Child : this;
382 bool b = Convert.ExplicitNumericConversion (e, target) != null;
385 Convert.ExplicitReferenceConversionExists (Type, target) ||
386 Convert.ExplicitUnsafe (e, target) != null ||
387 (ec != null && Convert.ExplicitUserConversion (ec, this, target, Location.Null) != null))
389 Report.Error (266, loc, "Cannot implicitly convert type `{0}' to `{1}'. " +
390 "An explicit conversion exists (are you missing a cast?)",
391 TypeManager.CSharpName (Type), TypeManager.CSharpName (target));
395 if (Type != TypeManager.string_type && this is Constant && !(this is EmptyConstantCast)) {
396 Report.Error (31, loc, "Constant value `{0}' cannot be converted to a `{1}'",
397 ((Constant)(this)).GetValue ().ToString (), TypeManager.CSharpName (target));
401 Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
402 TypeManager.CSharpName (type),
403 TypeManager.CSharpName (target));
406 protected void Error_VariableIsUsedBeforeItIsDeclared (string name)
408 Report.Error (841, loc, "The variable `{0}' cannot be used before it is declared",
412 protected virtual void Error_TypeDoesNotContainDefinition (Type type, string name)
414 Error_TypeDoesNotContainDefinition (loc, type, name);
417 public static void Error_TypeDoesNotContainDefinition (Location loc, Type type, string name)
419 Report.SymbolRelatedToPreviousError (type);
420 Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
421 TypeManager.CSharpName (type), name);
424 protected static void Error_ValueAssignment (Location loc)
426 Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
429 ResolveFlags ExprClassToResolveFlags
434 case ExprClass.Namespace:
435 return ResolveFlags.Type;
437 case ExprClass.MethodGroup:
438 return ResolveFlags.MethodGroup;
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.eclass == ExprClass.MethodGroup) {
567 ((MethodGroupExpr) e).ReportUsageError ();
571 if ((e.type == null) && !(e is ConstructedType))
572 throw new Exception ("Expression " + e + " did not set its type after Resolve");
578 /// Emits the code for the expression
582 /// The Emit method is invoked to generate the code
583 /// for the expression.
585 public abstract void Emit (EmitContext ec);
587 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
590 ec.ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
594 /// Protected constructor. Only derivate types should
595 /// be able to be created
598 protected Expression ()
600 eclass = ExprClass.Invalid;
605 /// Returns a fully formed expression after a MemberLookup
608 public static Expression ExprClassFromMemberInfo (Type container_type, MemberInfo mi, Location loc)
611 return new EventExpr ((EventInfo) mi, loc);
612 else if (mi is FieldInfo) {
613 FieldInfo fi = (FieldInfo) mi;
614 if (fi.IsLiteral || (fi.IsInitOnly && fi.FieldType == TypeManager.decimal_type))
615 return new ConstantExpr (fi, loc);
616 return new FieldExpr (fi, loc);
617 } else if (mi is PropertyInfo)
618 return new PropertyExpr (container_type, (PropertyInfo) mi, loc);
619 else if (mi is Type) {
620 return new TypeExpression ((System.Type) mi, loc);
626 protected static ArrayList almost_matched_members = new ArrayList (4);
629 // FIXME: Probably implement a cache for (t,name,current_access_set)?
631 // This code could use some optimizations, but we need to do some
632 // measurements. For example, we could use a delegate to `flag' when
633 // something can not any longer be a method-group (because it is something
637 // If the return value is an Array, then it is an array of
640 // If the return value is an MemberInfo, it is anything, but a Method
644 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
645 // the arguments here and have MemberLookup return only the methods that
646 // match the argument count/type, unlike we are doing now (we delay this
649 // This is so we can catch correctly attempts to invoke instance methods
650 // from a static body (scan for error 120 in ResolveSimpleName).
653 // FIXME: Potential optimization, have a static ArrayList
656 public static Expression MemberLookup (Type container_type, Type queried_type, string name,
657 MemberTypes mt, BindingFlags bf, Location loc)
659 return MemberLookup (container_type, null, queried_type, name, mt, bf, loc);
663 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
664 // `qualifier_type' or null to lookup members in the current class.
667 public static Expression MemberLookup (Type container_type,
668 Type qualifier_type, Type queried_type,
669 string name, MemberTypes mt,
670 BindingFlags bf, Location loc)
672 almost_matched_members.Clear ();
674 MemberInfo [] mi = TypeManager.MemberLookup (container_type, qualifier_type,
675 queried_type, mt, bf, name, almost_matched_members);
681 bool is_interface = qualifier_type != null && qualifier_type.IsInterface;
682 ArrayList methods = new ArrayList (2);
683 ArrayList non_methods = null;
685 foreach (MemberInfo m in mi) {
686 if (m is MethodBase) {
691 if (non_methods == null) {
692 non_methods = new ArrayList (2);
697 foreach (MemberInfo n_m in non_methods) {
698 if (m.DeclaringType.IsInterface && TypeManager.ImplementsInterface (m.DeclaringType, n_m.DeclaringType))
701 Report.SymbolRelatedToPreviousError (m);
702 Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
703 TypeManager.GetFullNameSignature (m), TypeManager.GetFullNameSignature (n_m));
708 if (methods.Count == 0)
709 return ExprClassFromMemberInfo (container_type, (MemberInfo)non_methods [0], loc);
711 if (non_methods != null) {
712 MethodBase method = (MethodBase) methods [0];
713 MemberInfo non_method = (MemberInfo) non_methods [0];
714 if (method.DeclaringType == non_method.DeclaringType) {
715 // Cannot happen with C# code, but is valid in IL
716 Report.SymbolRelatedToPreviousError (method);
717 Report.SymbolRelatedToPreviousError (non_method);
718 Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
719 TypeManager.GetFullNameSignature (non_method),
720 TypeManager.CSharpSignature (method));
725 Report.SymbolRelatedToPreviousError (method);
726 Report.SymbolRelatedToPreviousError (non_method);
727 Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and non-method `{1}'. Using method `{0}'",
728 TypeManager.CSharpSignature (method), TypeManager.GetFullNameSignature (non_method));
732 return new MethodGroupExpr (methods, queried_type, loc);
735 if (mi [0] is MethodBase)
736 return new MethodGroupExpr (mi, queried_type, loc);
738 return ExprClassFromMemberInfo (container_type, mi [0], loc);
741 public const MemberTypes AllMemberTypes =
742 MemberTypes.Constructor |
746 MemberTypes.NestedType |
747 MemberTypes.Property;
749 public const BindingFlags AllBindingFlags =
750 BindingFlags.Public |
751 BindingFlags.Static |
752 BindingFlags.Instance;
754 public static Expression MemberLookup (Type container_type, Type queried_type,
755 string name, Location loc)
757 return MemberLookup (container_type, null, queried_type, name,
758 AllMemberTypes, AllBindingFlags, loc);
761 public static Expression MemberLookup (Type container_type, Type qualifier_type,
762 Type queried_type, string name, Location loc)
764 return MemberLookup (container_type, qualifier_type, queried_type,
765 name, AllMemberTypes, AllBindingFlags, loc);
768 public static MethodGroupExpr MethodLookup (Type container_type, Type queried_type,
769 string name, Location loc)
771 return (MethodGroupExpr)MemberLookup (container_type, null, queried_type, name,
772 MemberTypes.Method, AllBindingFlags, loc);
776 /// This is a wrapper for MemberLookup that is not used to "probe", but
777 /// to find a final definition. If the final definition is not found, we
778 /// look for private members and display a useful debugging message if we
781 protected Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
782 Type queried_type, string name,
783 MemberTypes mt, BindingFlags bf,
788 int errors = Report.Errors;
790 e = MemberLookup (ec.ContainerType, qualifier_type, queried_type, name, mt, bf, loc);
792 if (e != null || errors != Report.Errors)
795 // No errors were reported by MemberLookup, but there was an error.
796 return Error_MemberLookupFailed (ec.ContainerType, qualifier_type, queried_type,
800 protected virtual Expression Error_MemberLookupFailed (Type container_type, Type qualifier_type,
801 Type queried_type, string name, string class_name,
802 MemberTypes mt, BindingFlags bf)
804 if (almost_matched_members.Count != 0) {
805 for (int i = 0; i < almost_matched_members.Count; ++i) {
806 MemberInfo m = (MemberInfo) almost_matched_members [i];
807 for (int j = 0; j < i; ++j) {
808 if (m == almost_matched_members [j]) {
816 Type declaring_type = m.DeclaringType;
818 Report.SymbolRelatedToPreviousError (m);
819 if (qualifier_type == null) {
820 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
821 TypeManager.CSharpName (m.DeclaringType),
822 TypeManager.CSharpName (container_type));
824 } else if (qualifier_type != container_type &&
825 TypeManager.IsNestedFamilyAccessible (container_type, declaring_type)) {
826 // Although a derived class can access protected members of
827 // its base class it cannot do so through an instance of the
828 // base class (CS1540). If the qualifier_type is a base of the
829 // ec.ContainerType and the lookup succeeds with the latter one,
830 // then we are in this situation.
831 Error_CannotAccessProtected (loc, m, qualifier_type, container_type);
833 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (m));
836 almost_matched_members.Clear ();
840 MemberInfo[] lookup = null;
841 if (queried_type == null) {
842 class_name = "global::";
844 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
845 mt, (bf & ~BindingFlags.Public) | BindingFlags.NonPublic,
848 if (lookup != null) {
849 Report.SymbolRelatedToPreviousError (lookup [0]);
850 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (lookup [0]));
851 return Error_MemberLookupFailed (lookup);
854 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
855 AllMemberTypes, AllBindingFlags | BindingFlags.NonPublic,
859 if (lookup == null) {
860 if (class_name != null) {
861 Report.Error (103, loc, "The name `{0}' does not exist in the current context",
864 Error_TypeDoesNotContainDefinition (queried_type, name);
869 if (TypeManager.MemberLookup (queried_type, null, queried_type,
870 AllMemberTypes, AllBindingFlags |
871 BindingFlags.NonPublic, name, null) == null) {
872 if ((lookup.Length == 1) && (lookup [0] is Type)) {
873 Type t = (Type) lookup [0];
875 Report.Error (305, loc,
876 "Using the generic type `{0}' " +
877 "requires {1} type arguments",
878 TypeManager.CSharpName (t),
879 TypeManager.GetNumberOfTypeArguments (t).ToString ());
884 return Error_MemberLookupFailed (lookup);
887 protected virtual Expression Error_MemberLookupFailed (MemberInfo[] members)
889 for (int i = 0; i < members.Length; ++i) {
890 if (!(members [i] is MethodBase))
894 // By default propagate the closest candidates upwards
895 return new MethodGroupExpr (members, type, loc);
898 protected virtual void Error_NegativeArrayIndex (Location loc)
900 throw new NotImplementedException ();
904 /// Returns an expression that can be used to invoke operator true
905 /// on the expression if it exists.
907 static public Expression GetOperatorTrue (EmitContext ec, Expression e, Location loc)
909 return GetOperatorTrueOrFalse (ec, e, true, loc);
913 /// Returns an expression that can be used to invoke operator false
914 /// on the expression if it exists.
916 static public Expression GetOperatorFalse (EmitContext ec, Expression e, Location loc)
918 return GetOperatorTrueOrFalse (ec, e, false, loc);
921 static Expression GetOperatorTrueOrFalse (EmitContext ec, Expression e, bool is_true, Location loc)
923 MethodGroupExpr operator_group;
924 operator_group = MethodLookup (ec.ContainerType, e.Type, is_true ? "op_True" : "op_False", loc) as MethodGroupExpr;
925 if (operator_group == null)
928 ArrayList arguments = new ArrayList (1);
929 arguments.Add (new Argument (e, Argument.AType.Expression));
930 operator_group = operator_group.OverloadResolve (
931 ec, ref arguments, false, loc);
933 if (operator_group == null)
936 return new UserOperatorCall (operator_group, arguments, null, loc);
940 /// Resolves the expression `e' into a boolean expression: either through
941 /// an implicit conversion, or through an `operator true' invocation
943 public static Expression ResolveBoolean (EmitContext ec, Expression e, Location loc)
949 if (e.Type == TypeManager.bool_type)
952 Expression converted = Convert.ImplicitConversion (ec, e, TypeManager.bool_type, Location.Null);
954 if (converted != null)
958 // If no implicit conversion to bool exists, try using `operator true'
960 converted = Expression.GetOperatorTrue (ec, e, loc);
961 if (converted == null){
962 e.Error_ValueCannotBeConverted (ec, loc, TypeManager.bool_type, false);
968 public virtual string ExprClassName
972 case ExprClass.Invalid:
974 case ExprClass.Value:
976 case ExprClass.Variable:
978 case ExprClass.Namespace:
982 case ExprClass.MethodGroup:
983 return "method group";
984 case ExprClass.PropertyAccess:
985 return "property access";
986 case ExprClass.EventAccess:
987 return "event access";
988 case ExprClass.IndexerAccess:
989 return "indexer access";
990 case ExprClass.Nothing:
993 throw new Exception ("Should not happen");
998 /// Reports that we were expecting `expr' to be of class `expected'
1000 public void Error_UnexpectedKind (DeclSpace ds, string expected, Location loc)
1002 Error_UnexpectedKind (ds, expected, ExprClassName, loc);
1005 public void Error_UnexpectedKind (DeclSpace ds, string expected, string was, Location loc)
1007 string name = GetSignatureForError ();
1009 name = ds.GetSignatureForError () + '.' + name;
1011 Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
1012 name, was, expected);
1015 public void Error_UnexpectedKind (ResolveFlags flags, Location loc)
1017 string [] valid = new string [4];
1020 if ((flags & ResolveFlags.VariableOrValue) != 0) {
1021 valid [count++] = "variable";
1022 valid [count++] = "value";
1025 if ((flags & ResolveFlags.Type) != 0)
1026 valid [count++] = "type";
1028 if ((flags & ResolveFlags.MethodGroup) != 0)
1029 valid [count++] = "method group";
1032 valid [count++] = "unknown";
1034 StringBuilder sb = new StringBuilder (valid [0]);
1035 for (int i = 1; i < count - 1; i++) {
1037 sb.Append (valid [i]);
1040 sb.Append ("' or `");
1041 sb.Append (valid [count - 1]);
1044 Report.Error (119, loc,
1045 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1048 public static void UnsafeError (Location loc)
1050 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1054 // Load the object from the pointer.
1056 public static void LoadFromPtr (ILGenerator ig, Type t)
1058 if (t == TypeManager.int32_type)
1059 ig.Emit (OpCodes.Ldind_I4);
1060 else if (t == TypeManager.uint32_type)
1061 ig.Emit (OpCodes.Ldind_U4);
1062 else if (t == TypeManager.short_type)
1063 ig.Emit (OpCodes.Ldind_I2);
1064 else if (t == TypeManager.ushort_type)
1065 ig.Emit (OpCodes.Ldind_U2);
1066 else if (t == TypeManager.char_type)
1067 ig.Emit (OpCodes.Ldind_U2);
1068 else if (t == TypeManager.byte_type)
1069 ig.Emit (OpCodes.Ldind_U1);
1070 else if (t == TypeManager.sbyte_type)
1071 ig.Emit (OpCodes.Ldind_I1);
1072 else if (t == TypeManager.uint64_type)
1073 ig.Emit (OpCodes.Ldind_I8);
1074 else if (t == TypeManager.int64_type)
1075 ig.Emit (OpCodes.Ldind_I8);
1076 else if (t == TypeManager.float_type)
1077 ig.Emit (OpCodes.Ldind_R4);
1078 else if (t == TypeManager.double_type)
1079 ig.Emit (OpCodes.Ldind_R8);
1080 else if (t == TypeManager.bool_type)
1081 ig.Emit (OpCodes.Ldind_I1);
1082 else if (t == TypeManager.intptr_type)
1083 ig.Emit (OpCodes.Ldind_I);
1084 else if (TypeManager.IsEnumType (t)) {
1085 if (t == TypeManager.enum_type)
1086 ig.Emit (OpCodes.Ldind_Ref);
1088 LoadFromPtr (ig, TypeManager.GetEnumUnderlyingType (t));
1089 } else if (t.IsValueType || TypeManager.IsGenericParameter (t))
1090 ig.Emit (OpCodes.Ldobj, t);
1091 else if (t.IsPointer)
1092 ig.Emit (OpCodes.Ldind_I);
1094 ig.Emit (OpCodes.Ldind_Ref);
1098 // The stack contains the pointer and the value of type `type'
1100 public static void StoreFromPtr (ILGenerator ig, Type type)
1102 if (TypeManager.IsEnumType (type))
1103 type = TypeManager.GetEnumUnderlyingType (type);
1104 if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
1105 ig.Emit (OpCodes.Stind_I4);
1106 else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
1107 ig.Emit (OpCodes.Stind_I8);
1108 else if (type == TypeManager.char_type || type == TypeManager.short_type ||
1109 type == TypeManager.ushort_type)
1110 ig.Emit (OpCodes.Stind_I2);
1111 else if (type == TypeManager.float_type)
1112 ig.Emit (OpCodes.Stind_R4);
1113 else if (type == TypeManager.double_type)
1114 ig.Emit (OpCodes.Stind_R8);
1115 else if (type == TypeManager.byte_type || type == TypeManager.sbyte_type ||
1116 type == TypeManager.bool_type)
1117 ig.Emit (OpCodes.Stind_I1);
1118 else if (type == TypeManager.intptr_type)
1119 ig.Emit (OpCodes.Stind_I);
1120 else if (type.IsValueType || TypeManager.IsGenericParameter (type))
1121 ig.Emit (OpCodes.Stobj, type);
1123 ig.Emit (OpCodes.Stind_Ref);
1127 // Returns the size of type `t' if known, otherwise, 0
1129 public static int GetTypeSize (Type t)
1131 t = TypeManager.TypeToCoreType (t);
1132 if (t == TypeManager.int32_type ||
1133 t == TypeManager.uint32_type ||
1134 t == TypeManager.float_type)
1136 else if (t == TypeManager.int64_type ||
1137 t == TypeManager.uint64_type ||
1138 t == TypeManager.double_type)
1140 else if (t == TypeManager.byte_type ||
1141 t == TypeManager.sbyte_type ||
1142 t == TypeManager.bool_type)
1144 else if (t == TypeManager.short_type ||
1145 t == TypeManager.char_type ||
1146 t == TypeManager.ushort_type)
1148 else if (t == TypeManager.decimal_type)
1154 protected void Error_CannotCallAbstractBase (string name)
1156 Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
1159 protected void Error_CannotModifyIntermediateExpressionValue (EmitContext ec)
1161 Report.SymbolRelatedToPreviousError (type);
1162 if (ec.CurrentInitializerVariable != null) {
1163 Report.Error (1918, loc, "Members of a value type property `{0}' cannot be assigned with an object initializer",
1164 GetSignatureForError ());
1166 Report.Error (1612, loc, "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
1167 GetSignatureForError ());
1172 // Converts `source' to an int, uint, long or ulong.
1174 public Expression ConvertExpressionToArrayIndex (EmitContext ec, Expression source)
1176 Expression converted;
1178 using (ec.With (EmitContext.Flags.CheckState, true)) {
1179 converted = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, source.loc);
1180 if (converted == null)
1181 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, source.loc);
1182 if (converted == null)
1183 converted = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, source.loc);
1184 if (converted == null)
1185 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, source.loc);
1187 if (converted == null) {
1188 source.Error_ValueCannotBeConverted (ec, source.loc, TypeManager.int32_type, false);
1194 // Only positive constants are allowed at compile time
1196 Constant c = converted as Constant;
1199 Error_NegativeArrayIndex (source.loc);
1204 return new ArrayIndexCast (converted).Resolve (ec);
1208 // Derived classes implement this method by cloning the fields that
1209 // could become altered during the Resolve stage
1211 // Only expressions that are created for the parser need to implement
1214 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1216 throw new NotImplementedException (
1218 "CloneTo not implemented for expression {0}", this.GetType ()));
1222 // Clones an expression created by the parser.
1224 // We only support expressions created by the parser so far, not
1225 // expressions that have been resolved (many more classes would need
1226 // to implement CloneTo).
1228 // This infrastructure is here merely for Lambda expressions which
1229 // compile the same code using different type values for the same
1230 // arguments to find the correct overload
1232 public Expression Clone (CloneContext clonectx)
1234 Expression cloned = (Expression) MemberwiseClone ();
1235 CloneTo (clonectx, cloned);
1240 public virtual Expression CreateExpressionTree (EmitContext ec)
1242 throw new NotImplementedException (
1243 "Expression tree conversion not implemented for " + GetType ());
1246 protected Expression CreateExpressionFactoryCall (string name, ArrayList args)
1248 return CreateExpressionFactoryCall (name, null, args, loc);
1251 protected Expression CreateExpressionFactoryCall (string name, TypeArguments typeArguments, ArrayList args)
1253 return CreateExpressionFactoryCall (name, typeArguments, args, loc);
1256 public static Expression CreateExpressionFactoryCall (string name, TypeArguments typeArguments, ArrayList args, Location loc)
1258 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (loc), name, typeArguments, loc), args);
1261 protected static TypeExpr CreateExpressionTypeExpression (Location loc)
1263 TypeExpr texpr = TypeManager.expression_type_expr;
1264 if (texpr == null) {
1265 Type t = TypeManager.CoreLookupType ("System.Linq.Expressions", "Expression", Kind.Class, true);
1269 TypeManager.expression_type_expr = texpr = new TypeExpression (t, Location.Null);
1277 /// This is just a base class for expressions that can
1278 /// appear on statements (invocations, object creation,
1279 /// assignments, post/pre increment and decrement). The idea
1280 /// being that they would support an extra Emition interface that
1281 /// does not leave a result on the stack.
1283 public abstract class ExpressionStatement : Expression {
1285 public virtual ExpressionStatement ResolveStatement (EmitContext ec)
1287 Expression e = Resolve (ec);
1291 ExpressionStatement es = e as ExpressionStatement;
1293 Error_InvalidExpressionStatement ();
1299 /// Requests the expression to be emitted in a `statement'
1300 /// context. This means that no new value is left on the
1301 /// stack after invoking this method (constrasted with
1302 /// Emit that will always leave a value on the stack).
1304 public abstract void EmitStatement (EmitContext ec);
1308 /// This kind of cast is used to encapsulate the child
1309 /// whose type is child.Type into an expression that is
1310 /// reported to return "return_type". This is used to encapsulate
1311 /// expressions which have compatible types, but need to be dealt
1312 /// at higher levels with.
1314 /// For example, a "byte" expression could be encapsulated in one
1315 /// of these as an "unsigned int". The type for the expression
1316 /// would be "unsigned int".
1319 public class EmptyCast : Expression
1321 protected Expression child;
1323 protected EmptyCast (Expression child, Type return_type)
1325 eclass = child.eclass;
1326 loc = child.Location;
1331 public static Expression Create (Expression child, Type type)
1333 Constant c = child as Constant;
1335 return new EmptyConstantCast (c, type);
1337 return new EmptyCast (child, type);
1340 public override Expression CreateExpressionTree (EmitContext ec)
1342 ArrayList args = new ArrayList (2);
1343 args.Add (new Argument (child.CreateExpressionTree (ec)));
1344 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1345 return CreateExpressionFactoryCall (ec.CheckState ? "ConvertChecked" : "Convert", args);
1348 public override Expression DoResolve (EmitContext ec)
1350 // This should never be invoked, we are born in fully
1351 // initialized state.
1356 public override void Emit (EmitContext ec)
1361 public override bool GetAttributableValue (Type value_type, out object value)
1363 return child.GetAttributableValue (value_type, out value);
1366 protected override void CloneTo (CloneContext clonectx, Expression t)
1368 EmptyCast target = (EmptyCast) t;
1370 target.child = child.Clone (clonectx);
1375 /// Performs a cast using an operator (op_Explicit or op_Implicit)
1377 public class OperatorCast : EmptyCast {
1378 MethodInfo conversion_operator;
1381 public OperatorCast (Expression child, Type target_type) : this (child, target_type, false) {}
1383 public OperatorCast (Expression child, Type target_type, bool find_explicit)
1384 : base (child, target_type)
1386 this.find_explicit = find_explicit;
1389 // Returns the implicit operator that converts from
1390 // 'child.Type' to our target type (type)
1391 MethodInfo GetConversionOperator (bool find_explicit)
1393 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1397 mi = TypeManager.MemberLookup (child.Type, child.Type, child.Type, MemberTypes.Method,
1398 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1401 mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1402 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1405 foreach (MethodInfo oper in mi) {
1406 ParameterData pd = TypeManager.GetParameterData (oper);
1408 if (pd.ParameterType (0) == child.Type && TypeManager.TypeToCoreType (oper.ReturnType) == type)
1416 public override void Emit (EmitContext ec)
1418 ILGenerator ig = ec.ig;
1421 conversion_operator = GetConversionOperator (find_explicit);
1423 if (conversion_operator == null)
1424 throw new InternalErrorException ("Outer conversion routine is out of sync");
1426 ig.Emit (OpCodes.Call, conversion_operator);
1432 /// This is a numeric cast to a Decimal
1434 public class CastToDecimal : EmptyCast {
1435 MethodInfo conversion_operator;
1437 public CastToDecimal (Expression child)
1438 : this (child, false)
1442 public CastToDecimal (Expression child, bool find_explicit)
1443 : base (child, TypeManager.decimal_type)
1445 conversion_operator = GetConversionOperator (find_explicit);
1447 if (conversion_operator == null)
1448 throw new InternalErrorException ("Outer conversion routine is out of sync");
1451 // Returns the implicit operator that converts from
1452 // 'child.Type' to System.Decimal.
1453 MethodInfo GetConversionOperator (bool find_explicit)
1455 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1457 MemberInfo [] mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1458 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1460 foreach (MethodInfo oper in mi) {
1461 ParameterData pd = TypeManager.GetParameterData (oper);
1463 if (pd.ParameterType (0) == child.Type && TypeManager.TypeToCoreType (oper.ReturnType) == type)
1469 public override void Emit (EmitContext ec)
1471 ILGenerator ig = ec.ig;
1474 ig.Emit (OpCodes.Call, conversion_operator);
1479 /// This is an explicit numeric cast from a Decimal
1481 public class CastFromDecimal : EmptyCast
1483 static IDictionary operators;
1485 public CastFromDecimal (Expression child, Type return_type)
1486 : base (child, return_type)
1488 if (child.Type != TypeManager.decimal_type)
1489 throw new InternalErrorException (
1490 "The expected type is Decimal, instead it is " + child.Type.FullName);
1493 // Returns the explicit operator that converts from an
1494 // express of type System.Decimal to 'type'.
1495 public Expression Resolve ()
1497 if (operators == null) {
1498 MemberInfo[] all_oper = TypeManager.MemberLookup (TypeManager.decimal_type,
1499 TypeManager.decimal_type, TypeManager.decimal_type, MemberTypes.Method,
1500 BindingFlags.Static | BindingFlags.Public, "op_Explicit", null);
1502 operators = new System.Collections.Specialized.HybridDictionary ();
1503 foreach (MethodInfo oper in all_oper) {
1504 ParameterData pd = TypeManager.GetParameterData (oper);
1505 if (pd.ParameterType (0) == TypeManager.decimal_type)
1506 operators.Add (TypeManager.TypeToCoreType (oper.ReturnType), oper);
1510 return operators.Contains (type) ? this : null;
1513 public override void Emit (EmitContext ec)
1515 ILGenerator ig = ec.ig;
1518 ig.Emit (OpCodes.Call, (MethodInfo)operators [type]);
1524 // Constant specialization of EmptyCast.
1525 // We need to special case this since an empty cast of
1526 // a constant is still a constant.
1528 public class EmptyConstantCast : Constant
1530 public readonly Constant child;
1532 public EmptyConstantCast(Constant child, Type type)
1533 : base (child.Location)
1535 eclass = child.eclass;
1540 public override string AsString ()
1542 return child.AsString ();
1545 public override object GetValue ()
1547 return child.GetValue ();
1550 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
1552 // FIXME: check that 'type' can be converted to 'target_type' first
1553 return child.ConvertExplicitly (in_checked_context, target_type);
1556 public override Expression CreateExpressionTree (EmitContext ec)
1558 ArrayList args = new ArrayList (2);
1559 args.Add (new Argument (child.CreateExpressionTree (ec)));
1560 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1561 return CreateExpressionFactoryCall ("Convert", args);
1564 public override Constant Increment ()
1566 return child.Increment ();
1569 public override bool IsDefaultValue {
1570 get { return child.IsDefaultValue; }
1573 public override bool IsNegative {
1574 get { return child.IsNegative; }
1577 public override bool IsNull {
1578 get { return child.IsNull; }
1581 public override bool IsZeroInteger {
1582 get { return child.IsZeroInteger; }
1585 public override void Emit (EmitContext ec)
1590 public override Constant ConvertImplicitly (Type target_type)
1592 // FIXME: Do we need to check user conversions?
1593 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1595 return child.ConvertImplicitly (target_type);
1601 /// This class is used to wrap literals which belong inside Enums
1603 public class EnumConstant : Constant {
1604 public Constant Child;
1606 public EnumConstant (Constant child, Type enum_type):
1607 base (child.Location)
1609 eclass = child.eclass;
1614 public override Expression DoResolve (EmitContext ec)
1616 // This should never be invoked, we are born in fully
1617 // initialized state.
1622 public override void Emit (EmitContext ec)
1627 public override bool GetAttributableValue (Type value_type, out object value)
1629 value = GetTypedValue ();
1633 public override string GetSignatureForError()
1635 return TypeManager.CSharpName (Type);
1638 public override object GetValue ()
1640 return Child.GetValue ();
1643 public override object GetTypedValue ()
1645 // FIXME: runtime is not ready to work with just emited enums
1646 if (!RootContext.StdLib) {
1647 return Child.GetValue ();
1650 return System.Enum.ToObject (type, Child.GetValue ());
1653 public override string AsString ()
1655 return TypeManager.CSharpEnumValue (type, Child.GetValue ());
1658 public override Constant Increment()
1660 return new EnumConstant (Child.Increment (), type);
1663 public override bool IsDefaultValue {
1665 return Child.IsDefaultValue;
1669 public override bool IsZeroInteger {
1670 get { return Child.IsZeroInteger; }
1673 public override bool IsNegative {
1675 return Child.IsNegative;
1679 public override Constant ConvertExplicitly(bool in_checked_context, Type target_type)
1681 if (Child.Type == target_type)
1684 return Child.ConvertExplicitly (in_checked_context, target_type);
1687 public override Constant ConvertImplicitly (Type type)
1689 Type this_type = TypeManager.DropGenericTypeArguments (Type);
1690 type = TypeManager.DropGenericTypeArguments (type);
1692 if (this_type == type) {
1693 // This is workaround of mono bug. It can be removed when the latest corlib spreads enough
1694 if (TypeManager.IsEnumType (type.UnderlyingSystemType))
1697 Type child_type = TypeManager.DropGenericTypeArguments (Child.Type);
1698 if (type.UnderlyingSystemType != child_type)
1699 Child = Child.ConvertImplicitly (type.UnderlyingSystemType);
1703 if (!Convert.ImplicitStandardConversionExists (this, type)){
1707 return Child.ConvertImplicitly(type);
1713 /// This kind of cast is used to encapsulate Value Types in objects.
1715 /// The effect of it is to box the value type emitted by the previous
1718 public class BoxedCast : EmptyCast {
1720 public BoxedCast (Expression expr, Type target_type)
1721 : base (expr, target_type)
1723 eclass = ExprClass.Value;
1726 public override Expression DoResolve (EmitContext ec)
1728 // This should never be invoked, we are born in fully
1729 // initialized state.
1734 public override void Emit (EmitContext ec)
1738 ec.ig.Emit (OpCodes.Box, child.Type);
1742 public class UnboxCast : EmptyCast {
1743 public UnboxCast (Expression expr, Type return_type)
1744 : base (expr, return_type)
1748 public override Expression DoResolve (EmitContext ec)
1750 // This should never be invoked, we are born in fully
1751 // initialized state.
1756 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1758 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
1759 Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
1760 return base.DoResolveLValue (ec, right_side);
1763 public override void Emit (EmitContext ec)
1766 ILGenerator ig = ec.ig;
1770 if (t.IsGenericParameter || t.IsGenericType && t.IsValueType)
1771 ig.Emit (OpCodes.Unbox_Any, t);
1775 ig.Emit (OpCodes.Unbox, t);
1777 LoadFromPtr (ig, t);
1783 /// This is used to perform explicit numeric conversions.
1785 /// Explicit numeric conversions might trigger exceptions in a checked
1786 /// context, so they should generate the conv.ovf opcodes instead of
1789 public class ConvCast : EmptyCast {
1790 public enum Mode : byte {
1791 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1793 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1794 U2_I1, U2_U1, U2_I2, U2_CH,
1795 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1796 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1797 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH,
1798 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH,
1799 CH_I1, CH_U1, CH_I2,
1800 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1801 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4
1806 public ConvCast (Expression child, Type return_type, Mode m)
1807 : base (child, return_type)
1812 public override Expression DoResolve (EmitContext ec)
1814 // This should never be invoked, we are born in fully
1815 // initialized state.
1820 public override string ToString ()
1822 return String.Format ("ConvCast ({0}, {1})", mode, child);
1825 public override void Emit (EmitContext ec)
1827 ILGenerator ig = ec.ig;
1833 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1834 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1835 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1836 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1837 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1839 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1840 case Mode.U1_CH: /* nothing */ break;
1842 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1843 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1844 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1845 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1846 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1847 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1849 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1850 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1851 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1852 case Mode.U2_CH: /* nothing */ break;
1854 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1855 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1856 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1857 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1858 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1859 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1860 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1862 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1863 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1864 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1865 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1866 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1867 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1869 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1870 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1871 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1872 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1873 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1874 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1875 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1876 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1878 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1879 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1880 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1881 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1882 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1883 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1884 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1885 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1887 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1888 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1889 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1891 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1892 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1893 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1894 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1895 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1896 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1897 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1898 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1899 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1901 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1902 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1903 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1904 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1905 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1906 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1907 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1908 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1909 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1910 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1914 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
1915 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
1916 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
1917 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
1918 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
1920 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
1921 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
1923 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
1924 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
1925 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
1926 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
1927 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
1928 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
1930 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
1931 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
1932 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
1933 case Mode.U2_CH: /* nothing */ break;
1935 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
1936 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
1937 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
1938 case Mode.I4_U4: /* nothing */ break;
1939 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
1940 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
1941 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
1943 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
1944 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
1945 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
1946 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
1947 case Mode.U4_I4: /* nothing */ break;
1948 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
1950 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
1951 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
1952 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
1953 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
1954 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
1955 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
1956 case Mode.I8_U8: /* nothing */ break;
1957 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
1959 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
1960 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
1961 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
1962 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
1963 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
1964 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
1965 case Mode.U8_I8: /* nothing */ break;
1966 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
1968 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
1969 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
1970 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
1972 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
1973 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
1974 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
1975 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
1976 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
1977 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
1978 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
1979 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
1980 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
1982 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
1983 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
1984 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
1985 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
1986 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
1987 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
1988 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
1989 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
1990 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
1991 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1997 public class OpcodeCast : EmptyCast {
2001 public OpcodeCast (Expression child, Type return_type, OpCode op)
2002 : base (child, return_type)
2006 second_valid = false;
2009 public OpcodeCast (Expression child, Type return_type, OpCode op, OpCode op2)
2010 : base (child, return_type)
2015 second_valid = true;
2018 public override Expression DoResolve (EmitContext ec)
2020 // This should never be invoked, we are born in fully
2021 // initialized state.
2026 public override void Emit (EmitContext ec)
2035 public Type UnderlyingType {
2036 get { return child.Type; }
2041 /// This kind of cast is used to encapsulate a child and cast it
2042 /// to the class requested
2044 public class ClassCast : EmptyCast {
2045 public ClassCast (Expression child, Type return_type)
2046 : base (child, return_type)
2051 public override Expression DoResolve (EmitContext ec)
2053 // This should never be invoked, we are born in fully
2054 // initialized state.
2059 public override void Emit (EmitContext ec)
2063 if (TypeManager.IsGenericParameter (child.Type))
2064 ec.ig.Emit (OpCodes.Box, child.Type);
2067 if (type.IsGenericParameter)
2068 ec.ig.Emit (OpCodes.Unbox_Any, type);
2071 ec.ig.Emit (OpCodes.Castclass, type);
2076 // Used when resolved expression has different representations for
2077 // expression trees and emit phase
2079 public class ReducedExpression : Expression
2081 class ReducedConstantExpression : Constant
2083 readonly Constant expr;
2084 readonly Expression orig_expr;
2086 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2087 : base (expr.Location)
2090 this.orig_expr = orig_expr;
2091 eclass = expr.eclass;
2095 public override string AsString ()
2097 return expr.AsString ();
2100 public override Expression CreateExpressionTree (EmitContext ec)
2102 return orig_expr.CreateExpressionTree (ec);
2105 public override object GetValue ()
2107 return expr.GetValue ();
2110 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
2112 throw new NotImplementedException ();
2115 public override Expression DoResolve (EmitContext ec)
2120 public override Constant Increment ()
2122 throw new NotImplementedException ();
2125 public override bool IsDefaultValue {
2127 return expr.IsDefaultValue;
2131 public override bool IsNegative {
2133 return expr.IsNegative;
2137 public override void Emit (EmitContext ec)
2143 readonly Expression expr, orig_expr;
2145 private ReducedExpression (Expression expr, Expression orig_expr)
2148 this.orig_expr = orig_expr;
2149 this.loc = orig_expr.Location;
2152 public static Expression Create (Constant expr, Expression original_expr)
2154 return new ReducedConstantExpression (expr, original_expr);
2157 public static Expression Create (Expression expr, Expression original_expr)
2159 Constant c = expr as Constant;
2161 return Create (c, original_expr);
2163 return new ReducedExpression (expr, original_expr);
2166 public override Expression CreateExpressionTree (EmitContext ec)
2168 return orig_expr.CreateExpressionTree (ec);
2171 public override Expression DoResolve (EmitContext ec)
2173 eclass = expr.eclass;
2178 public override void Emit (EmitContext ec)
2183 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2185 expr.EmitBranchable (ec, target, on_true);
2190 /// SimpleName expressions are formed of a single word and only happen at the beginning
2191 /// of a dotted-name.
2193 public class SimpleName : Expression {
2194 public readonly string Name;
2195 public readonly TypeArguments Arguments;
2198 public SimpleName (string name, Location l)
2204 public SimpleName (string name, TypeArguments args, Location l)
2211 public SimpleName (string name, TypeParameter[] type_params, Location l)
2216 Arguments = new TypeArguments (l);
2217 foreach (TypeParameter type_param in type_params)
2218 Arguments.Add (new TypeParameterExpr (type_param, l));
2221 public static string RemoveGenericArity (string name)
2224 StringBuilder sb = null;
2226 int pos = name.IndexOf ('`', start);
2231 sb.Append (name.Substring (start));
2236 sb = new StringBuilder ();
2237 sb.Append (name.Substring (start, pos-start));
2240 while ((pos < name.Length) && Char.IsNumber (name [pos]))
2244 } while (start < name.Length);
2246 return sb.ToString ();
2249 public SimpleName GetMethodGroup ()
2251 return new SimpleName (RemoveGenericArity (Name), Arguments, loc);
2254 public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
2256 if (ec.IsInFieldInitializer)
2257 Report.Error (236, l,
2258 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2262 120, l, "`{0}': An object reference is required for the nonstatic field, method or property",
2266 public bool IdenticalNameAndTypeName (EmitContext ec, Expression resolved_to, Location loc)
2268 return resolved_to != null && resolved_to.Type != null &&
2269 resolved_to.Type.Name == Name &&
2270 (ec.DeclContainer.LookupNamespaceOrType (Name, loc, /* ignore_cs0104 = */ true) != null);
2273 public override Expression DoResolve (EmitContext ec)
2275 return SimpleNameResolve (ec, null, false);
2278 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
2280 return SimpleNameResolve (ec, right_side, false);
2284 public Expression DoResolve (EmitContext ec, bool intermediate)
2286 return SimpleNameResolve (ec, null, intermediate);
2289 static bool IsNestedChild (Type t, Type parent)
2291 while (parent != null) {
2292 if (TypeManager.IsNestedChildOf (t, TypeManager.DropGenericTypeArguments (parent)))
2295 parent = parent.BaseType;
2301 FullNamedExpression ResolveNested (IResolveContext ec, Type t)
2303 if (!TypeManager.IsGenericTypeDefinition (t) && !TypeManager.IsGenericType (t))
2306 DeclSpace ds = ec.DeclContainer;
2307 while (ds != null && !IsNestedChild (t, ds.TypeBuilder))
2313 Type[] gen_params = TypeManager.GetTypeArguments (t);
2315 int arg_count = Arguments != null ? Arguments.Count : 0;
2317 for (; (ds != null) && ds.IsGeneric; ds = ds.Parent) {
2318 if (arg_count + ds.CountTypeParameters == gen_params.Length) {
2319 TypeArguments new_args = new TypeArguments (loc);
2320 foreach (TypeParameter param in ds.TypeParameters)
2321 new_args.Add (new TypeParameterExpr (param, loc));
2323 if (Arguments != null)
2324 new_args.Add (Arguments);
2326 return new ConstructedType (t, new_args, loc);
2333 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2335 FullNamedExpression fne = ec.GenericDeclContainer.LookupGeneric (Name, loc);
2337 return fne.ResolveAsTypeStep (ec, silent);
2339 int errors = Report.Errors;
2340 fne = ec.DeclContainer.LookupNamespaceOrType (Name, loc, /*ignore_cs0104=*/ false);
2343 if (fne.Type == null)
2346 FullNamedExpression nested = ResolveNested (ec, fne.Type);
2348 return nested.ResolveAsTypeStep (ec, false);
2350 if (Arguments != null) {
2351 ConstructedType ct = new ConstructedType (fne, Arguments, loc);
2352 return ct.ResolveAsTypeStep (ec, false);
2358 if (silent || errors != Report.Errors)
2361 Error_TypeOrNamespaceNotFound (ec);
2365 protected virtual void Error_TypeOrNamespaceNotFound (IResolveContext ec)
2367 MemberCore mc = ec.DeclContainer.GetDefinition (Name);
2369 Error_UnexpectedKind (ec.DeclContainer, "type", GetMemberType (mc), loc);
2373 string ns = ec.DeclContainer.NamespaceEntry.NS.Name;
2374 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2375 foreach (Assembly a in RootNamespace.Global.Assemblies) {
2376 Type type = a.GetType (fullname);
2378 Report.SymbolRelatedToPreviousError (type);
2379 Expression.ErrorIsInaccesible (loc, TypeManager.CSharpName (type));
2384 Type t = ec.DeclContainer.LookupAnyGeneric (Name);
2386 Namespace.Error_InvalidNumberOfTypeArguments (t, loc);
2390 if (Arguments != null) {
2391 FullNamedExpression retval = ec.DeclContainer.LookupNamespaceOrType (SimpleName.RemoveGenericArity (Name), loc, true);
2392 if (retval != null) {
2393 Namespace.Error_TypeArgumentsCannotBeUsed (retval.Type, loc);
2398 NamespaceEntry.Error_NamespaceNotFound (loc, Name);
2401 // TODO: I am still not convinced about this. If someone else will need it
2402 // implement this as virtual property in MemberCore hierarchy
2403 public static string GetMemberType (MemberCore mc)
2409 if (mc is FieldBase)
2411 if (mc is MethodCore)
2413 if (mc is EnumMember)
2421 Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2427 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2433 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2440 /// 7.5.2: Simple Names.
2442 /// Local Variables and Parameters are handled at
2443 /// parse time, so they never occur as SimpleNames.
2445 /// The `intermediate' flag is used by MemberAccess only
2446 /// and it is used to inform us that it is ok for us to
2447 /// avoid the static check, because MemberAccess might end
2448 /// up resolving the Name as a Type name and the access as
2449 /// a static type access.
2451 /// ie: Type Type; .... { Type.GetType (""); }
2453 /// Type is both an instance variable and a Type; Type.GetType
2454 /// is the static method not an instance method of type.
2456 Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2458 Expression e = null;
2461 // Stage 1: Performed by the parser (binding to locals or parameters).
2463 Block current_block = ec.CurrentBlock;
2464 if (current_block != null){
2465 LocalInfo vi = current_block.GetLocalInfo (Name);
2467 if (Arguments != null) {
2468 Report.Error (307, loc,
2469 "The variable `{0}' cannot be used with type arguments",
2474 LocalVariableReference var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2475 if (right_side != null) {
2476 return var.ResolveLValue (ec, right_side, loc);
2478 ResolveFlags rf = ResolveFlags.VariableOrValue;
2480 rf |= ResolveFlags.DisableFlowAnalysis;
2481 return var.Resolve (ec, rf);
2485 ParameterReference pref = current_block.Toplevel.GetParameterReference (Name, loc);
2487 if (Arguments != null) {
2488 Report.Error (307, loc,
2489 "The variable `{0}' cannot be used with type arguments",
2494 if (right_side != null)
2495 return pref.ResolveLValue (ec, right_side, loc);
2497 return pref.Resolve (ec);
2500 Expression expr = current_block.Toplevel.GetTransparentIdentifier (Name);
2502 if (right_side != null)
2503 return expr.ResolveLValue (ec, right_side, loc);
2504 return expr.Resolve (ec);
2509 // Stage 2: Lookup members
2512 Type almost_matched_type = null;
2513 ArrayList almost_matched = null;
2514 for (DeclSpace lookup_ds = ec.DeclContainer; lookup_ds != null; lookup_ds = lookup_ds.Parent) {
2515 // either RootDeclSpace or GenericMethod
2516 if (lookup_ds.TypeBuilder == null)
2519 e = MemberLookup (ec.ContainerType, lookup_ds.TypeBuilder, Name, loc);
2521 if (e is PropertyExpr) {
2522 // since TypeManager.MemberLookup doesn't know if we're doing a lvalue access or not,
2523 // it doesn't know which accessor to check permissions against
2524 if (((PropertyExpr) e).IsAccessibleFrom (ec.ContainerType, right_side != null))
2526 } else if (e is EventExpr) {
2527 if (((EventExpr) e).IsAccessibleFrom (ec.ContainerType))
2535 if (almost_matched == null && almost_matched_members.Count > 0) {
2536 almost_matched_type = lookup_ds.TypeBuilder;
2537 almost_matched = (ArrayList) almost_matched_members.Clone ();
2542 if (almost_matched == null && almost_matched_members.Count > 0) {
2543 almost_matched_type = ec.ContainerType;
2544 almost_matched = (ArrayList) almost_matched_members.Clone ();
2546 e = ResolveAsTypeStep (ec, true);
2550 if (current_block != null) {
2551 IKnownVariable ikv = current_block.Explicit.GetKnownVariable (Name);
2553 LocalInfo li = ikv as LocalInfo;
2554 // Supress CS0219 warning
2558 Error_VariableIsUsedBeforeItIsDeclared (Name);
2563 if (almost_matched != null)
2564 almost_matched_members = almost_matched;
2565 if (almost_matched_type == null)
2566 almost_matched_type = ec.ContainerType;
2567 Error_MemberLookupFailed (ec.ContainerType, null, almost_matched_type, Name,
2568 ec.DeclContainer.Name, AllMemberTypes, AllBindingFlags);
2572 if (e is TypeExpr) {
2573 if (Arguments == null)
2576 ConstructedType ct = new ConstructedType (
2577 (FullNamedExpression) e, Arguments, loc);
2578 return ct.ResolveAsTypeStep (ec, false);
2581 if (e is MemberExpr) {
2582 MemberExpr me = (MemberExpr) e;
2585 if (me.IsInstance) {
2586 if (ec.IsStatic || ec.IsInFieldInitializer) {
2588 // Note that an MemberExpr can be both IsInstance and IsStatic.
2589 // An unresolved MethodGroupExpr can contain both kinds of methods
2590 // and each predicate is true if the MethodGroupExpr contains
2591 // at least one of that kind of method.
2595 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2596 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2601 // Pass the buck to MemberAccess and Invocation.
2603 left = EmptyExpression.Null;
2605 left = ec.GetThis (loc);
2608 left = new TypeExpression (ec.ContainerType, loc);
2611 me = me.ResolveMemberAccess (ec, left, loc, null);
2615 if (Arguments != null) {
2616 Arguments.Resolve (ec);
2617 me.SetTypeArguments (Arguments);
2620 if (!me.IsStatic && (me.InstanceExpression != null) &&
2621 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2622 me.InstanceExpression.Type != me.DeclaringType &&
2623 !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2624 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2625 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2626 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2630 return (right_side != null)
2631 ? me.DoResolveLValue (ec, right_side)
2632 : me.DoResolve (ec);
2638 public override void Emit (EmitContext ec)
2640 throw new InternalErrorException ("The resolve phase was not executed");
2643 public override string ToString ()
2648 public override string GetSignatureForError ()
2650 if (Arguments != null) {
2651 return TypeManager.RemoveGenericArity (Name) + "<" +
2652 Arguments.GetSignatureForError () + ">";
2658 protected override void CloneTo (CloneContext clonectx, Expression target)
2660 // CloneTo: Nothing, we do not keep any state on this expression
2665 /// Represents a namespace or a type. The name of the class was inspired by
2666 /// section 10.8.1 (Fully Qualified Names).
2668 public abstract class FullNamedExpression : Expression {
2669 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2674 public abstract string FullName {
2680 /// Expression that evaluates to a type
2682 public abstract class TypeExpr : FullNamedExpression {
2683 override public FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2685 TypeExpr t = DoResolveAsTypeStep (ec);
2689 eclass = ExprClass.Type;
2693 override public Expression DoResolve (EmitContext ec)
2695 return ResolveAsTypeTerminal (ec, false);
2698 override public void Emit (EmitContext ec)
2700 throw new Exception ("Should never be called");
2703 public virtual bool CheckAccessLevel (DeclSpace ds)
2705 return ds.CheckAccessLevel (Type);
2708 public virtual bool AsAccessible (DeclSpace ds)
2710 return ds.IsAccessibleAs (Type);
2713 public virtual bool IsClass {
2714 get { return Type.IsClass; }
2717 public virtual bool IsValueType {
2718 get { return Type.IsValueType; }
2721 public virtual bool IsInterface {
2722 get { return Type.IsInterface; }
2725 public virtual bool IsSealed {
2726 get { return Type.IsSealed; }
2729 public virtual bool CanInheritFrom ()
2731 if (Type == TypeManager.enum_type ||
2732 (Type == TypeManager.value_type && RootContext.StdLib) ||
2733 Type == TypeManager.multicast_delegate_type ||
2734 Type == TypeManager.delegate_type ||
2735 Type == TypeManager.array_type)
2741 protected abstract TypeExpr DoResolveAsTypeStep (IResolveContext ec);
2743 public abstract string Name {
2747 public override bool Equals (object obj)
2749 TypeExpr tobj = obj as TypeExpr;
2753 return Type == tobj.Type;
2756 public override int GetHashCode ()
2758 return Type.GetHashCode ();
2761 public override string ToString ()
2768 /// Fully resolved Expression that already evaluated to a type
2770 public class TypeExpression : TypeExpr {
2771 public TypeExpression (Type t, Location l)
2774 eclass = ExprClass.Type;
2778 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2783 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2788 public override string Name {
2789 get { return Type.ToString (); }
2792 public override string FullName {
2793 get { return Type.FullName; }
2798 /// Used to create types from a fully qualified name. These are just used
2799 /// by the parser to setup the core types. A TypeLookupExpression is always
2800 /// classified as a type.
2802 public sealed class TypeLookupExpression : TypeExpr {
2803 readonly string name;
2805 public TypeLookupExpression (string name)
2808 eclass = ExprClass.Type;
2811 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2813 // It's null for corlib compilation only
2815 return DoResolveAsTypeStep (ec);
2820 private class UnexpectedType
2824 // This performes recursive type lookup, providing support for generic types.
2825 // For example, given the type:
2827 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]]
2829 // The types will be checked in the following order:
2832 // System.Collections |
2833 // System.Collections.Generic |
2835 // System | recursive call 1 |
2836 // System.Int32 _| | main method call
2838 // System | recursive call 2 |
2839 // System.String _| |
2841 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]] _|
2843 private Type TypeLookup (IResolveContext ec, string name)
2848 FullNamedExpression resolved = null;
2850 Type recursive_type = null;
2851 while (index < name.Length) {
2852 if (name[index] == '[') {
2857 if (name[index] == '[')
2859 else if (name[index] == ']')
2861 } while (braces > 0);
2862 recursive_type = TypeLookup (ec, name.Substring (open + 1, index - open - 1));
2863 if (recursive_type == null || (recursive_type == typeof(UnexpectedType)))
2864 return recursive_type;
2867 if (name[index] == ',')
2869 else if ((name[index] == '.' && !done) || (index == name.Length && name[0] != '[')) {
2870 string substring = name.Substring(dot, index - dot);
2872 if (resolved == null)
2873 resolved = RootNamespace.Global.Lookup (ec.DeclContainer, substring, Location.Null);
2874 else if (resolved is Namespace)
2875 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
2876 else if (type != null)
2877 type = TypeManager.GetNestedType (type, substring);
2881 if (resolved == null)
2883 else if (type == null && resolved is TypeExpr)
2884 type = resolved.Type;
2891 if (name[0] != '[') {
2892 string substring = name.Substring(dot, index - dot);
2895 return TypeManager.GetNestedType (type, substring);
2897 if (resolved != null) {
2898 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
2899 if (resolved is TypeExpr)
2900 return resolved.Type;
2902 if (resolved == null)
2905 resolved.Error_UnexpectedKind (ec.DeclContainer, "type", loc);
2906 return typeof (UnexpectedType);
2912 return recursive_type;
2915 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2917 Type t = TypeLookup (ec, name);
2919 NamespaceEntry.Error_NamespaceNotFound (loc, name);
2922 if (t == typeof(UnexpectedType))
2928 public override string Name {
2929 get { return name; }
2932 public override string FullName {
2933 get { return name; }
2936 protected override void CloneTo (CloneContext clonectx, Expression target)
2938 // CloneTo: Nothing, we do not keep any state on this expression
2941 public override string GetSignatureForError ()
2944 return TypeManager.CSharpName (name);
2946 return base.GetSignatureForError ();
2951 /// Represents an "unbound generic type", ie. typeof (Foo<>).
2954 public class UnboundTypeExpression : TypeExpr
2958 public UnboundTypeExpression (MemberName name, Location l)
2964 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2967 if (name.Left != null) {
2968 Expression lexpr = name.Left.GetTypeExpression ();
2969 expr = new MemberAccess (lexpr, name.Basename);
2971 expr = new SimpleName (name.Basename, loc);
2974 FullNamedExpression fne = expr.ResolveAsTypeStep (ec, false);
2979 return new TypeExpression (type, loc);
2982 public override string Name {
2983 get { return name.FullName; }
2986 public override string FullName {
2987 get { return name.FullName; }
2991 public class TypeAliasExpression : TypeExpr {
2992 FullNamedExpression alias;
2997 public TypeAliasExpression (FullNamedExpression alias, TypeArguments args, Location l)
3003 eclass = ExprClass.Type;
3005 name = alias.FullName + "<" + args.ToString () + ">";
3007 name = alias.FullName;
3010 public override string Name {
3011 get { return alias.FullName; }
3014 public override string FullName {
3015 get { return name; }
3018 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
3020 texpr = alias.ResolveAsTypeTerminal (ec, false);
3024 Type type = texpr.Type;
3025 int num_args = TypeManager.GetNumberOfTypeArguments (type);
3028 if (num_args == 0) {
3029 Report.Error (308, loc,
3030 "The non-generic type `{0}' cannot " +
3031 "be used with type arguments.",
3032 TypeManager.CSharpName (type));
3036 ConstructedType ctype = new ConstructedType (type, args, loc);
3037 return ctype.ResolveAsTypeTerminal (ec, false);
3038 } else if (num_args > 0) {
3039 Report.Error (305, loc,
3040 "Using the generic type `{0}' " +
3041 "requires {1} type arguments",
3042 TypeManager.CSharpName (type), num_args.ToString ());
3049 public override bool CheckAccessLevel (DeclSpace ds)
3051 return texpr.CheckAccessLevel (ds);
3054 public override bool AsAccessible (DeclSpace ds)
3056 return texpr.AsAccessible (ds);
3059 public override bool IsClass {
3060 get { return texpr.IsClass; }
3063 public override bool IsValueType {
3064 get { return texpr.IsValueType; }
3067 public override bool IsInterface {
3068 get { return texpr.IsInterface; }
3071 public override bool IsSealed {
3072 get { return texpr.IsSealed; }
3077 /// This class denotes an expression which evaluates to a member
3078 /// of a struct or a class.
3080 public abstract class MemberExpr : Expression
3082 protected bool is_base;
3085 /// The name of this member.
3087 public abstract string Name {
3092 // When base.member is used
3094 public bool IsBase {
3095 get { return is_base; }
3096 set { is_base = value; }
3100 /// Whether this is an instance member.
3102 public abstract bool IsInstance {
3107 /// Whether this is a static member.
3109 public abstract bool IsStatic {
3114 /// The type which declares this member.
3116 public abstract Type DeclaringType {
3121 /// The instance expression associated with this member, if it's a
3122 /// non-static member.
3124 public Expression InstanceExpression;
3126 public static void error176 (Location loc, string name)
3128 Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
3129 "with an instance reference, qualify it with a type name instead", name);
3132 // TODO: possible optimalization
3133 // Cache resolved constant result in FieldBuilder <-> expression map
3134 public virtual MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3135 SimpleName original)
3139 // original == null || original.Resolve (...) ==> left
3142 if (left is TypeExpr) {
3143 left = left.ResolveAsTypeTerminal (ec, true);
3148 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3156 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3159 return ResolveExtensionMemberAccess (left);
3162 InstanceExpression = left;
3166 protected virtual MemberExpr ResolveExtensionMemberAccess (Expression left)
3168 error176 (loc, GetSignatureForError ());
3172 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3177 if (InstanceExpression == EmptyExpression.Null) {
3178 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3182 if (InstanceExpression.Type.IsValueType) {
3183 if (InstanceExpression is IMemoryLocation) {
3184 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
3186 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
3187 InstanceExpression.Emit (ec);
3189 t.AddressOf (ec, AddressOp.Store);
3192 InstanceExpression.Emit (ec);
3194 if (prepare_for_load)
3195 ec.ig.Emit (OpCodes.Dup);
3198 public virtual void SetTypeArguments (TypeArguments ta)
3200 // TODO: need to get correct member type
3201 Report.Error (307, loc, "The property `{0}' cannot be used with type arguments",
3202 GetSignatureForError ());
3207 /// Represents group of extension methods
3209 public class ExtensionMethodGroupExpr : MethodGroupExpr
3211 readonly NamespaceEntry namespace_entry;
3212 public Expression ExtensionExpression;
3213 Argument extension_argument;
3215 public ExtensionMethodGroupExpr (ArrayList list, NamespaceEntry n, Type extensionType, Location l)
3216 : base (list, extensionType, l)
3218 this.namespace_entry = n;
3221 public override bool IsStatic {
3222 get { return true; }
3225 public bool IsTopLevel {
3226 get { return namespace_entry == null; }
3229 public override void EmitArguments (EmitContext ec, ArrayList arguments)
3231 if (arguments == null)
3232 arguments = new ArrayList (1);
3233 arguments.Insert (0, extension_argument);
3234 base.EmitArguments (ec, arguments);
3237 public override void EmitCall (EmitContext ec, ArrayList arguments)
3239 if (arguments == null)
3240 arguments = new ArrayList (1);
3241 arguments.Insert (0, extension_argument);
3242 base.EmitCall (ec, arguments);
3245 public override MethodGroupExpr OverloadResolve (EmitContext ec, ref ArrayList arguments, bool may_fail, Location loc)
3247 if (arguments == null)
3248 arguments = new ArrayList (1);
3250 arguments.Insert (0, new Argument (ExtensionExpression));
3251 MethodGroupExpr mg = ResolveOverloadExtensions (ec, arguments, namespace_entry, loc);
3253 // Store resolved argument and restore original arguments
3255 ((ExtensionMethodGroupExpr)mg).extension_argument = (Argument)arguments [0];
3256 arguments.RemoveAt (0);
3261 MethodGroupExpr ResolveOverloadExtensions (EmitContext ec, ArrayList arguments, NamespaceEntry ns, Location loc)
3263 // Use normal resolve rules
3264 MethodGroupExpr mg = base.OverloadResolve (ec, ref arguments, ns != null, loc);
3272 ExtensionMethodGroupExpr e = ns.LookupExtensionMethod (type, null, Name, loc);
3274 return base.OverloadResolve (ec, ref arguments, false, loc);
3276 e.ExtensionExpression = ExtensionExpression;
3277 return e.ResolveOverloadExtensions (ec, arguments, e.namespace_entry, loc);
3282 /// MethodGroupExpr represents a group of method candidates which
3283 /// can be resolved to the best method overload
3285 public class MethodGroupExpr : MemberExpr
3287 public interface IErrorHandler
3289 bool NoExactMatch (EmitContext ec, MethodBase method);
3292 public IErrorHandler CustomErrorHandler;
3293 public MethodBase [] Methods;
3294 MethodBase best_candidate;
3295 // TODO: make private
3296 public TypeArguments type_arguments;
3297 bool identical_type_name;
3300 public MethodGroupExpr (MemberInfo [] mi, Type type, Location l)
3303 Methods = new MethodBase [mi.Length];
3304 mi.CopyTo (Methods, 0);
3307 public MethodGroupExpr (ArrayList list, Type type, Location l)
3311 Methods = (MethodBase[])list.ToArray (typeof (MethodBase));
3313 foreach (MemberInfo m in list){
3314 if (!(m is MethodBase)){
3315 Console.WriteLine ("Name " + m.Name);
3316 Console.WriteLine ("Found a: " + m.GetType ().FullName);
3325 protected MethodGroupExpr (Type type, Location loc)
3328 eclass = ExprClass.MethodGroup;
3332 public override Type DeclaringType {
3335 // We assume that the top-level type is in the end
3337 return Methods [Methods.Length - 1].DeclaringType;
3338 //return Methods [0].DeclaringType;
3342 public Type DelegateType {
3344 delegate_type = value;
3348 public bool IdenticalTypeName {
3350 return identical_type_name;
3354 identical_type_name = value;
3358 public override string GetSignatureForError ()
3360 if (best_candidate != null)
3361 return TypeManager.CSharpSignature (best_candidate);
3363 return TypeManager.CSharpSignature (Methods [0]);
3366 public override string Name {
3368 return Methods [0].Name;
3372 public override bool IsInstance {
3374 if (best_candidate != null)
3375 return !best_candidate.IsStatic;
3377 foreach (MethodBase mb in Methods)
3385 public override bool IsStatic {
3387 if (best_candidate != null)
3388 return best_candidate.IsStatic;
3390 foreach (MethodBase mb in Methods)
3398 public static explicit operator ConstructorInfo (MethodGroupExpr mg)
3400 return (ConstructorInfo)mg.best_candidate;
3403 public static explicit operator MethodInfo (MethodGroupExpr mg)
3405 return (MethodInfo)mg.best_candidate;
3409 // 7.4.3.3 Better conversion from expression
3410 // Returns : 1 if a->p is better,
3411 // 2 if a->q is better,
3412 // 0 if neither is better
3414 static int BetterExpressionConversion (EmitContext ec, Argument a, Type p, Type q)
3416 Type argument_type = TypeManager.TypeToCoreType (a.Type);
3417 if (argument_type == TypeManager.anonymous_method_type && RootContext.Version > LanguageVersion.ISO_2) {
3419 // Uwrap delegate from Expression<T>
3421 if (TypeManager.DropGenericTypeArguments (p) == TypeManager.expression_type) {
3422 p = TypeManager.GetTypeArguments (p) [0];
3423 q = TypeManager.GetTypeArguments (q) [0];
3425 p = Delegate.GetInvokeMethod (null, p).ReturnType;
3426 q = Delegate.GetInvokeMethod (null, q).ReturnType;
3428 if (argument_type == p)
3431 if (argument_type == q)
3435 return BetterTypeConversion (ec, p, q);
3439 // 7.4.3.4 Better conversion from type
3441 public static int BetterTypeConversion (EmitContext ec, Type p, Type q)
3443 if (p == null || q == null)
3444 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3446 if (p == TypeManager.int32_type) {
3447 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3449 } else if (p == TypeManager.int64_type) {
3450 if (q == TypeManager.uint64_type)
3452 } else if (p == TypeManager.sbyte_type) {
3453 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3454 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3456 } else if (p == TypeManager.short_type) {
3457 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3458 q == TypeManager.uint64_type)
3462 if (q == TypeManager.int32_type) {
3463 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3465 } if (q == TypeManager.int64_type) {
3466 if (p == TypeManager.uint64_type)
3468 } else if (q == TypeManager.sbyte_type) {
3469 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3470 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3472 } if (q == TypeManager.short_type) {
3473 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3474 p == TypeManager.uint64_type)
3478 // TODO: this is expensive
3479 Expression p_tmp = new EmptyExpression (p);
3480 Expression q_tmp = new EmptyExpression (q);
3482 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3483 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3485 if (p_to_q && !q_to_p)
3488 if (q_to_p && !p_to_q)
3495 /// Determines "Better function" between candidate
3496 /// and the current best match
3499 /// Returns a boolean indicating :
3500 /// false if candidate ain't better
3501 /// true if candidate is better than the current best match
3503 static bool BetterFunction (EmitContext ec, ArrayList args, int argument_count,
3504 MethodBase candidate, bool candidate_params,
3505 MethodBase best, bool best_params)
3507 ParameterData candidate_pd = TypeManager.GetParameterData (candidate);
3508 ParameterData best_pd = TypeManager.GetParameterData (best);
3510 bool better_at_least_one = false;
3512 for (int j = 0, c_idx = 0, b_idx = 0; j < argument_count; ++j, ++c_idx, ++b_idx)
3514 Argument a = (Argument) args [j];
3516 Type ct = TypeManager.TypeToCoreType (candidate_pd.ParameterType (c_idx));
3517 Type bt = TypeManager.TypeToCoreType (best_pd.ParameterType (b_idx));
3519 if (candidate_params && candidate_pd.ParameterModifier (c_idx) == Parameter.Modifier.PARAMS)
3521 ct = TypeManager.GetElementType (ct);
3525 if (best_params && best_pd.ParameterModifier (b_idx) == Parameter.Modifier.PARAMS)
3527 bt = TypeManager.GetElementType (bt);
3535 int result = BetterExpressionConversion (ec, a, ct, bt);
3537 // for each argument, the conversion to 'ct' should be no worse than
3538 // the conversion to 'bt'.
3542 // for at least one argument, the conversion to 'ct' should be better than
3543 // the conversion to 'bt'.
3545 better_at_least_one = true;
3548 if (better_at_least_one)
3552 // This handles the case
3554 // Add (float f1, float f2, float f3);
3555 // Add (params decimal [] foo);
3557 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3558 // first candidate would've chosen as better.
3564 // The two methods have equal parameter types. Now apply tie-breaking rules
3566 if (TypeManager.IsGenericMethod (best) && !TypeManager.IsGenericMethod (candidate))
3568 if (!TypeManager.IsGenericMethod (best) && TypeManager.IsGenericMethod (candidate))
3572 // This handles the following cases:
3574 // Trim () is better than Trim (params char[] chars)
3575 // Concat (string s1, string s2, string s3) is better than
3576 // Concat (string s1, params string [] srest)
3577 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3579 if (!candidate_params && best_params)
3581 if (candidate_params && !best_params)
3584 int candidate_param_count = candidate_pd.Count;
3585 int best_param_count = best_pd.Count;
3587 if (candidate_param_count != best_param_count)
3588 // can only happen if (candidate_params && best_params)
3589 return candidate_param_count > best_param_count;
3592 // now, both methods have the same number of parameters, and the parameters have the same types
3593 // Pick the "more specific" signature
3596 MethodBase orig_candidate = TypeManager.DropGenericMethodArguments (candidate);
3597 MethodBase orig_best = TypeManager.DropGenericMethodArguments (best);
3599 ParameterData orig_candidate_pd = TypeManager.GetParameterData (orig_candidate);
3600 ParameterData orig_best_pd = TypeManager.GetParameterData (orig_best);
3602 bool specific_at_least_once = false;
3603 for (int j = 0; j < candidate_param_count; ++j)
3605 Type ct = TypeManager.TypeToCoreType (orig_candidate_pd.ParameterType (j));
3606 Type bt = TypeManager.TypeToCoreType (orig_best_pd.ParameterType (j));
3609 Type specific = MoreSpecific (ct, bt);
3613 specific_at_least_once = true;
3616 if (specific_at_least_once)
3619 // FIXME: handle lifted operators
3625 protected override MemberExpr ResolveExtensionMemberAccess (Expression left)
3628 return base.ResolveExtensionMemberAccess (left);
3631 // When left side is an expression and at least one candidate method is
3632 // static, it can be extension method
3634 InstanceExpression = left;
3638 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3639 SimpleName original)
3641 if (!(left is TypeExpr) &&
3642 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3643 IdenticalTypeName = true;
3645 return base.ResolveMemberAccess (ec, left, loc, original);
3648 public override Expression CreateExpressionTree (EmitContext ec)
3650 Type t = best_candidate.IsConstructor ?
3651 typeof (ConstructorInfo) : typeof (MethodInfo);
3653 return new Cast (new TypeExpression (t, loc), new TypeOfMethod (best_candidate, loc));
3656 override public Expression DoResolve (EmitContext ec)
3658 if (InstanceExpression != null) {
3659 InstanceExpression = InstanceExpression.DoResolve (ec);
3660 if (InstanceExpression == null)
3667 public void ReportUsageError ()
3669 Report.Error (654, loc, "Method `" + DeclaringType + "." +
3670 Name + "()' is referenced without parentheses");
3673 override public void Emit (EmitContext ec)
3675 ReportUsageError ();
3678 public virtual void EmitArguments (EmitContext ec, ArrayList arguments)
3680 Invocation.EmitArguments (ec, arguments, false, null);
3683 public virtual void EmitCall (EmitContext ec, ArrayList arguments)
3685 Invocation.EmitCall (ec, IsBase, InstanceExpression, best_candidate, arguments, loc);
3688 protected virtual void Error_InvalidArguments (EmitContext ec, Location loc, int idx, MethodBase method,
3689 Argument a, ParameterData expected_par, Type paramType)
3691 if (a is CollectionElementInitializer.ElementInitializerArgument) {
3692 Report.SymbolRelatedToPreviousError (method);
3693 if ((expected_par.ParameterModifier (idx) & Parameter.Modifier.ISBYREF) != 0) {
3694 Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
3695 TypeManager.CSharpSignature (method));
3698 Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
3699 TypeManager.CSharpSignature (method));
3700 } else if (delegate_type == null) {
3701 Report.SymbolRelatedToPreviousError (method);
3702 Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
3703 TypeManager.CSharpSignature (method));
3705 Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
3706 TypeManager.CSharpName (delegate_type));
3708 Parameter.Modifier mod = expected_par.ParameterModifier (idx);
3710 string index = (idx + 1).ToString ();
3711 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
3712 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
3713 if ((mod & Parameter.Modifier.ISBYREF) == 0)
3714 Report.Error (1615, loc, "Argument `{0}' should not be passed with the `{1}' keyword",
3715 index, Parameter.GetModifierSignature (a.Modifier));
3717 Report.Error (1620, loc, "Argument `{0}' must be passed with the `{1}' keyword",
3718 index, Parameter.GetModifierSignature (mod));
3720 string p1 = a.GetSignatureForError ();
3721 string p2 = TypeManager.CSharpName (paramType);
3724 Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
3725 Report.SymbolRelatedToPreviousError (a.Expr.Type);
3726 Report.SymbolRelatedToPreviousError (paramType);
3728 Report.Error (1503, loc, "Argument {0}: Cannot convert type `{1}' to `{2}'", index, p1, p2);
3732 public override void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl)
3734 Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3735 Name, TypeManager.CSharpName (target));
3738 protected virtual int GetApplicableParametersCount (MethodBase method, ParameterData parameters)
3740 return parameters.Count;
3743 public static bool IsAncestralType (Type first_type, Type second_type)
3745 return first_type != second_type &&
3746 (TypeManager.IsSubclassOf (second_type, first_type) ||
3747 TypeManager.ImplementsInterface (second_type, first_type));
3751 /// Determines if the candidate method is applicable (section 14.4.2.1)
3752 /// to the given set of arguments
3753 /// A return value rates candidate method compatibility,
3754 /// 0 = the best, int.MaxValue = the worst
3756 public int IsApplicable (EmitContext ec,
3757 ArrayList arguments, int arg_count, ref MethodBase method, ref bool params_expanded_form)
3759 MethodBase candidate = method;
3761 ParameterData pd = TypeManager.GetParameterData (candidate);
3762 int param_count = GetApplicableParametersCount (candidate, pd);
3764 if (arg_count != param_count) {
3766 return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
3767 if (arg_count < param_count - 1)
3768 return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
3773 // 1. Handle generic method using type arguments when specified or type inference
3775 if (TypeManager.IsGenericMethod (candidate)) {
3776 if (type_arguments != null) {
3777 Type [] g_args = candidate.GetGenericArguments ();
3778 if (g_args.Length != type_arguments.Count)
3779 return int.MaxValue - 20000 + Math.Abs (type_arguments.Count - g_args.Length);
3781 // TODO: Don't create new method, create Parameters only
3782 method = ((MethodInfo) candidate).MakeGenericMethod (type_arguments.Arguments);
3784 pd = TypeManager.GetParameterData (candidate);
3786 int score = TypeManager.InferTypeArguments (ec, arguments, ref candidate);
3788 return score - 20000;
3790 if (TypeManager.IsGenericMethodDefinition (candidate))
3791 throw new InternalErrorException ("A generic method `{0}' definition took part in overload resolution",
3792 TypeManager.CSharpSignature (candidate));
3794 pd = TypeManager.GetParameterData (candidate);
3797 if (type_arguments != null)
3798 return int.MaxValue - 15000;
3803 // 2. Each argument has to be implicitly convertible to method parameter
3806 Parameter.Modifier p_mod = 0;
3808 for (int i = 0; i < arg_count; i++) {
3809 Argument a = (Argument) arguments [i];
3810 Parameter.Modifier a_mod = a.Modifier &
3811 ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3813 if (p_mod != Parameter.Modifier.PARAMS) {
3814 p_mod = pd.ParameterModifier (i) & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3816 if (p_mod == Parameter.Modifier.ARGLIST) {
3817 if (a.Type == TypeManager.runtime_argument_handle_type)
3823 pt = pd.ParameterType (i);
3825 params_expanded_form = true;
3829 if (!params_expanded_form)
3830 score = IsArgumentCompatible (ec, a_mod, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
3832 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0) {
3833 // It can be applicable in expanded form
3834 score = IsArgumentCompatible (ec, a_mod, a, 0, pt.GetElementType ());
3836 params_expanded_form = true;
3840 if (params_expanded_form)
3842 return (arg_count - i) * 2 + score;
3846 if (arg_count != param_count)
3847 params_expanded_form = true;
3852 int IsArgumentCompatible (EmitContext ec, Parameter.Modifier arg_mod, Argument argument, Parameter.Modifier param_mod, Type parameter)
3855 // Types have to be identical when ref or out modifer is used
3857 if (arg_mod != 0 || param_mod != 0) {
3858 if (TypeManager.HasElementType (parameter))
3859 parameter = parameter.GetElementType ();
3861 Type a_type = argument.Type;
3862 if (TypeManager.HasElementType (a_type))
3863 a_type = a_type.GetElementType ();
3865 if (a_type != parameter)
3871 // FIXME: Kill this abomination (EmitContext.TempEc)
3872 EmitContext prevec = EmitContext.TempEc;
3873 EmitContext.TempEc = ec;
3875 if (delegate_type != null ?
3876 !Delegate.IsTypeCovariant (argument.Expr, parameter) :
3877 !Convert.ImplicitConversionExists (ec, argument.Expr, parameter))
3880 if (arg_mod != param_mod)
3884 EmitContext.TempEc = prevec;
3890 public static bool IsOverride (MethodBase cand_method, MethodBase base_method)
3892 if (!IsAncestralType (base_method.DeclaringType, cand_method.DeclaringType))
3895 ParameterData cand_pd = TypeManager.GetParameterData (cand_method);
3896 ParameterData base_pd = TypeManager.GetParameterData (base_method);
3898 if (cand_pd.Count != base_pd.Count)
3901 for (int j = 0; j < cand_pd.Count; ++j)
3903 Parameter.Modifier cm = cand_pd.ParameterModifier (j);
3904 Parameter.Modifier bm = base_pd.ParameterModifier (j);
3905 Type ct = TypeManager.TypeToCoreType (cand_pd.ParameterType (j));
3906 Type bt = TypeManager.TypeToCoreType (base_pd.ParameterType (j));
3908 if (cm != bm || ct != bt)
3915 public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2, Location loc)
3917 MemberInfo [] miset;
3918 MethodGroupExpr union;
3923 return (MethodGroupExpr) mg2;
3926 return (MethodGroupExpr) mg1;
3929 MethodGroupExpr left_set = null, right_set = null;
3930 int length1 = 0, length2 = 0;
3932 left_set = (MethodGroupExpr) mg1;
3933 length1 = left_set.Methods.Length;
3935 right_set = (MethodGroupExpr) mg2;
3936 length2 = right_set.Methods.Length;
3938 ArrayList common = new ArrayList ();
3940 foreach (MethodBase r in right_set.Methods){
3941 if (TypeManager.ArrayContainsMethod (left_set.Methods, r))
3945 miset = new MemberInfo [length1 + length2 - common.Count];
3946 left_set.Methods.CopyTo (miset, 0);
3950 foreach (MethodBase r in right_set.Methods) {
3951 if (!common.Contains (r))
3955 union = new MethodGroupExpr (miset, mg1.Type, loc);
3960 static Type MoreSpecific (Type p, Type q)
3962 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
3964 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
3967 if (TypeManager.HasElementType (p))
3969 Type pe = TypeManager.GetElementType (p);
3970 Type qe = TypeManager.GetElementType (q);
3971 Type specific = MoreSpecific (pe, qe);
3977 else if (TypeManager.IsGenericType (p))
3979 Type[] pargs = TypeManager.GetTypeArguments (p);
3980 Type[] qargs = TypeManager.GetTypeArguments (q);
3982 bool p_specific_at_least_once = false;
3983 bool q_specific_at_least_once = false;
3985 for (int i = 0; i < pargs.Length; i++)
3987 Type specific = MoreSpecific (pargs [i], qargs [i]);
3988 if (specific == pargs [i])
3989 p_specific_at_least_once = true;
3990 if (specific == qargs [i])
3991 q_specific_at_least_once = true;
3994 if (p_specific_at_least_once && !q_specific_at_least_once)
3996 if (!p_specific_at_least_once && q_specific_at_least_once)
4004 /// Find the Applicable Function Members (7.4.2.1)
4006 /// me: Method Group expression with the members to select.
4007 /// it might contain constructors or methods (or anything
4008 /// that maps to a method).
4010 /// Arguments: ArrayList containing resolved Argument objects.
4012 /// loc: The location if we want an error to be reported, or a Null
4013 /// location for "probing" purposes.
4015 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4016 /// that is the best match of me on Arguments.
4019 public virtual MethodGroupExpr OverloadResolve (EmitContext ec, ref ArrayList Arguments,
4020 bool may_fail, Location loc)
4022 bool method_params = false;
4023 Type applicable_type = null;
4025 ArrayList candidates = new ArrayList (2);
4026 ArrayList candidate_overrides = null;
4029 // Used to keep a map between the candidate
4030 // and whether it is being considered in its
4031 // normal or expanded form
4033 // false is normal form, true is expanded form
4035 Hashtable candidate_to_form = null;
4037 if (Arguments != null)
4038 arg_count = Arguments.Count;
4040 if (RootContext.Version == LanguageVersion.ISO_1 && Name == "Invoke" && TypeManager.IsDelegateType (DeclaringType)) {
4042 Report.Error (1533, loc, "Invoke cannot be called directly on a delegate");
4046 int nmethods = Methods.Length;
4050 // Methods marked 'override' don't take part in 'applicable_type'
4051 // computation, nor in the actual overload resolution.
4052 // However, they still need to be emitted instead of a base virtual method.
4053 // So, we salt them away into the 'candidate_overrides' array.
4055 // In case of reflected methods, we replace each overriding method with
4056 // its corresponding base virtual method. This is to improve compatibility
4057 // with non-C# libraries which change the visibility of overrides (#75636)
4060 for (int i = 0; i < Methods.Length; ++i) {
4061 MethodBase m = Methods [i];
4062 if (TypeManager.IsOverride (m)) {
4063 if (candidate_overrides == null)
4064 candidate_overrides = new ArrayList ();
4065 candidate_overrides.Add (m);
4066 m = TypeManager.TryGetBaseDefinition (m);
4075 // Enable message recording, it's used mainly by lambda expressions
4077 Report.IMessageRecorder msg_recorder = new Report.MessageRecorder ();
4078 Report.IMessageRecorder prev_recorder = Report.SetMessageRecorder (msg_recorder);
4081 // First we construct the set of applicable methods
4083 bool is_sorted = true;
4084 int best_candidate_rate = int.MaxValue;
4085 for (int i = 0; i < nmethods; i++) {
4086 Type decl_type = Methods [i].DeclaringType;
4089 // If we have already found an applicable method
4090 // we eliminate all base types (Section 14.5.5.1)
4092 if (applicable_type != null && IsAncestralType (decl_type, applicable_type))
4096 // Check if candidate is applicable (section 14.4.2.1)
4098 bool params_expanded_form = false;
4099 int candidate_rate = IsApplicable (ec, Arguments, arg_count, ref Methods [i], ref params_expanded_form);
4101 if (candidate_rate < best_candidate_rate) {
4102 best_candidate_rate = candidate_rate;
4103 best_candidate = Methods [i];
4106 if (params_expanded_form) {
4107 if (candidate_to_form == null)
4108 candidate_to_form = new PtrHashtable ();
4109 MethodBase candidate = Methods [i];
4110 candidate_to_form [candidate] = candidate;
4113 if (candidate_rate != 0) {
4114 if (msg_recorder != null)
4115 msg_recorder.EndSession ();
4119 msg_recorder = null;
4120 candidates.Add (Methods [i]);
4122 if (applicable_type == null)
4123 applicable_type = decl_type;
4124 else if (applicable_type != decl_type) {
4126 if (IsAncestralType (applicable_type, decl_type))
4127 applicable_type = decl_type;
4131 Report.SetMessageRecorder (prev_recorder);
4132 if (msg_recorder != null && msg_recorder.PrintMessages ())
4135 int candidate_top = candidates.Count;
4137 if (applicable_type == null) {
4139 // When we found a top level method which does not match and it's
4140 // not an extension method. We start extension methods lookup from here
4142 if (InstanceExpression != null) {
4143 ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (type, Name, loc);
4144 if (ex_method_lookup != null) {
4145 ex_method_lookup.ExtensionExpression = InstanceExpression;
4146 ex_method_lookup.SetTypeArguments (type_arguments);
4147 return ex_method_lookup.OverloadResolve (ec, ref Arguments, may_fail, loc);
4155 // Okay so we have failed to find exact match so we
4156 // return error info about the closest match
4158 if (best_candidate != null) {
4159 if (CustomErrorHandler != null) {
4160 if (CustomErrorHandler.NoExactMatch (ec, best_candidate))
4164 ParameterData pd = TypeManager.GetParameterData (best_candidate);
4165 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4166 if (arg_count == pd.Count || pd.HasParams) {
4167 if (TypeManager.IsGenericMethodDefinition (best_candidate)) {
4168 if (type_arguments == null) {
4169 Report.Error (411, loc,
4170 "The type arguments for method `{0}' cannot be inferred from " +
4171 "the usage. Try specifying the type arguments explicitly",
4172 TypeManager.CSharpSignature (best_candidate));
4176 Type [] g_args = TypeManager.GetGenericArguments (best_candidate);
4177 if (type_arguments.Count != g_args.Length) {
4178 Report.SymbolRelatedToPreviousError (best_candidate);
4179 Report.Error (305, loc, "Using the generic method `{0}' requires `{1}' type argument(s)",
4180 TypeManager.CSharpSignature (best_candidate),
4181 g_args.Length.ToString ());
4185 if (type_arguments != null && !TypeManager.IsGenericMethod (best_candidate)) {
4186 Namespace.Error_TypeArgumentsCannotBeUsed (best_candidate, loc);
4191 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate, cand_params, may_fail, loc))
4196 if (almost_matched_members.Count != 0) {
4197 Error_MemberLookupFailed (ec.ContainerType, type, type, ".ctor",
4198 null, MemberTypes.Constructor, AllBindingFlags);
4203 // We failed to find any method with correct argument count
4205 if (Name == ConstructorInfo.ConstructorName) {
4206 Report.SymbolRelatedToPreviousError (type);
4207 Report.Error (1729, loc,
4208 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4209 TypeManager.CSharpName (type), arg_count);
4211 Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4212 Name, arg_count.ToString ());
4220 // At this point, applicable_type is _one_ of the most derived types
4221 // in the set of types containing the methods in this MethodGroup.
4222 // Filter the candidates so that they only contain methods from the
4223 // most derived types.
4226 int finalized = 0; // Number of finalized candidates
4229 // Invariant: applicable_type is a most derived type
4231 // We'll try to complete Section 14.5.5.1 for 'applicable_type' by
4232 // eliminating all it's base types. At the same time, we'll also move
4233 // every unrelated type to the end of the array, and pick the next
4234 // 'applicable_type'.
4236 Type next_applicable_type = null;
4237 int j = finalized; // where to put the next finalized candidate
4238 int k = finalized; // where to put the next undiscarded candidate
4239 for (int i = finalized; i < candidate_top; ++i) {
4240 MethodBase candidate = (MethodBase) candidates [i];
4241 Type decl_type = candidate.DeclaringType;
4243 if (decl_type == applicable_type) {
4244 candidates [k++] = candidates [j];
4245 candidates [j++] = candidates [i];
4249 if (IsAncestralType (decl_type, applicable_type))
4252 if (next_applicable_type != null &&
4253 IsAncestralType (decl_type, next_applicable_type))
4256 candidates [k++] = candidates [i];
4258 if (next_applicable_type == null ||
4259 IsAncestralType (next_applicable_type, decl_type))
4260 next_applicable_type = decl_type;
4263 applicable_type = next_applicable_type;
4266 } while (applicable_type != null);
4270 // Now we actually find the best method
4273 best_candidate = (MethodBase) candidates [0];
4274 if (delegate_type == null)
4275 method_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4277 for (int ix = 1; ix < candidate_top; ix++) {
4278 MethodBase candidate = (MethodBase) candidates [ix];
4280 if (candidate == best_candidate)
4283 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4285 if (BetterFunction (ec, Arguments, arg_count,
4286 candidate, cand_params,
4287 best_candidate, method_params)) {
4288 best_candidate = candidate;
4289 method_params = cand_params;
4293 // Now check that there are no ambiguities i.e the selected method
4294 // should be better than all the others
4296 MethodBase ambiguous = null;
4297 for (int ix = 1; ix < candidate_top; ix++) {
4298 MethodBase candidate = (MethodBase) candidates [ix];
4300 if (candidate == best_candidate)
4303 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4304 if (!BetterFunction (ec, Arguments, arg_count,
4305 best_candidate, method_params,
4306 candidate, cand_params))
4309 Report.SymbolRelatedToPreviousError (candidate);
4310 ambiguous = candidate;
4314 if (ambiguous != null) {
4315 Report.SymbolRelatedToPreviousError (best_candidate);
4316 Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4317 TypeManager.CSharpSignature (ambiguous), TypeManager.CSharpSignature (best_candidate));
4322 // If the method is a virtual function, pick an override closer to the LHS type.
4324 if (!IsBase && best_candidate.IsVirtual) {
4325 if (TypeManager.IsOverride (best_candidate))
4326 throw new InternalErrorException (
4327 "Should not happen. An 'override' method took part in overload resolution: " + best_candidate);
4329 if (candidate_overrides != null) {
4330 Type[] gen_args = null;
4331 bool gen_override = false;
4332 if (TypeManager.IsGenericMethod (best_candidate))
4333 gen_args = TypeManager.GetGenericArguments (best_candidate);
4335 foreach (MethodBase candidate in candidate_overrides) {
4336 if (TypeManager.IsGenericMethod (candidate)) {
4337 if (gen_args == null)
4340 if (gen_args.Length != TypeManager.GetGenericArguments (candidate).Length)
4343 if (gen_args != null)
4347 if (IsOverride (candidate, best_candidate)) {
4348 gen_override = true;
4349 best_candidate = candidate;
4353 if (gen_override && gen_args != null) {
4355 best_candidate = ((MethodInfo) best_candidate).MakeGenericMethod (gen_args);
4362 // And now check if the arguments are all
4363 // compatible, perform conversions if
4364 // necessary etc. and return if everything is
4367 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate,
4368 method_params, may_fail, loc))
4371 if (best_candidate == null)
4374 MethodBase the_method = TypeManager.DropGenericMethodArguments (best_candidate);
4376 if (the_method.IsGenericMethodDefinition &&
4377 !ConstraintChecker.CheckConstraints (ec, the_method, best_candidate, loc))
4381 IMethodData data = TypeManager.GetMethod (the_method);
4383 data.SetMemberIsUsed ();
4388 public override void SetTypeArguments (TypeArguments ta)
4390 type_arguments = ta;
4393 public bool VerifyArgumentsCompat (EmitContext ec, ref ArrayList arguments,
4394 int arg_count, MethodBase method,
4395 bool chose_params_expanded,
4396 bool may_fail, Location loc)
4398 ParameterData pd = TypeManager.GetParameterData (method);
4400 int errors = Report.Errors;
4401 Parameter.Modifier p_mod = 0;
4403 int a_idx = 0, a_pos = 0;
4405 ArrayList params_initializers = null;
4407 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4408 a = (Argument) arguments [a_idx];
4409 if (p_mod != Parameter.Modifier.PARAMS) {
4410 p_mod = pd.ParameterModifier (a_idx);
4411 pt = pd.ParameterType (a_idx);
4413 if (p_mod == Parameter.Modifier.ARGLIST) {
4414 if (a.Type != TypeManager.runtime_argument_handle_type)
4419 if (pt.IsPointer && !ec.InUnsafe) {
4426 if (p_mod == Parameter.Modifier.PARAMS) {
4427 if (chose_params_expanded) {
4428 params_initializers = new ArrayList (arg_count - a_idx);
4429 pt = TypeManager.GetElementType (pt);
4431 } else if (p_mod != 0) {
4432 pt = TypeManager.GetElementType (pt);
4437 // Types have to be identical when ref or out modifer is used
4439 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4440 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4443 if (!TypeManager.IsEqual (a.Expr.Type, pt))
4450 if (TypeManager.IsEqual (a.Type, pt)) {
4453 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4459 // Convert params arguments to an array initializer
4461 if (params_initializers != null) {
4462 params_initializers.Add (conv);
4463 arguments.RemoveAt (a_idx--);
4468 // Update the argument with the implicit conversion
4473 // Fill not provided arguments required by params modifier
4475 if (params_initializers == null && pd.HasParams && arg_count < pd.Count && a_idx + 1 == pd.Count) {
4476 if (arguments == null)
4477 arguments = new ArrayList (1);
4479 pt = pd.Types [GetApplicableParametersCount (method, pd) - 1];
4480 pt = TypeManager.GetElementType (pt);
4481 params_initializers = new ArrayList (0);
4484 if (a_idx == arg_count) {
4486 // Append an array argument with all params arguments
4488 if (params_initializers != null) {
4489 arguments.Add (new Argument (
4490 new ArrayCreation (new TypeExpression (pt, loc), "[]",
4491 params_initializers, loc).Resolve (ec)));
4496 if (!may_fail && Report.Errors == errors) {
4497 if (CustomErrorHandler != null)
4498 CustomErrorHandler.NoExactMatch (ec, best_candidate);
4500 Error_InvalidArguments (ec, loc, a_pos, method, a, pd, pt);
4506 public class ConstantExpr : MemberExpr
4510 public ConstantExpr (FieldInfo constant, Location loc)
4512 this.constant = constant;
4516 public override string Name {
4517 get { throw new NotImplementedException (); }
4520 public override bool IsInstance {
4521 get { return !IsStatic; }
4524 public override bool IsStatic {
4525 get { return constant.IsStatic; }
4528 public override Type DeclaringType {
4529 get { return constant.DeclaringType; }
4532 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc, SimpleName original)
4534 constant = TypeManager.GetGenericFieldDefinition (constant);
4536 IConstant ic = TypeManager.GetConstant (constant);
4538 if (constant.IsLiteral) {
4539 ic = new ExternalConstant (constant);
4541 ic = ExternalConstant.CreateDecimal (constant);
4542 // HACK: decimal field was not resolved as constant
4544 return new FieldExpr (constant, loc).ResolveMemberAccess (ec, left, loc, original);
4546 TypeManager.RegisterConstant (constant, ic);
4549 return base.ResolveMemberAccess (ec, left, loc, original);
4552 public override Expression CreateExpressionTree (EmitContext ec)
4554 throw new NotSupportedException ();
4557 public override Expression DoResolve (EmitContext ec)
4559 IConstant ic = TypeManager.GetConstant (constant);
4560 if (ic.ResolveValue ()) {
4561 if (!ec.IsInObsoleteScope)
4562 ic.CheckObsoleteness (loc);
4565 return ic.CreateConstantReference (loc);
4568 public override void Emit (EmitContext ec)
4570 throw new NotSupportedException ();
4573 public override string GetSignatureForError ()
4575 return TypeManager.GetFullNameSignature (constant);
4580 /// Fully resolved expression that evaluates to a Field
4582 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariable {
4583 public readonly FieldInfo FieldInfo;
4584 VariableInfo variable_info;
4586 LocalTemporary temp;
4588 bool in_initializer;
4590 public FieldExpr (FieldInfo fi, Location l, bool in_initializer):
4593 this.in_initializer = in_initializer;
4596 public FieldExpr (FieldInfo fi, Location l)
4599 eclass = ExprClass.Variable;
4600 type = TypeManager.TypeToCoreType (fi.FieldType);
4604 public override string Name {
4606 return FieldInfo.Name;
4610 public override bool IsInstance {
4612 return !FieldInfo.IsStatic;
4616 public override bool IsStatic {
4618 return FieldInfo.IsStatic;
4622 public override Type DeclaringType {
4624 return FieldInfo.DeclaringType;
4628 public override string GetSignatureForError ()
4630 return TypeManager.GetFullNameSignature (FieldInfo);
4633 public VariableInfo VariableInfo {
4635 return variable_info;
4639 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
4640 SimpleName original)
4642 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
4643 Type t = fi.FieldType;
4645 if (t.IsPointer && !ec.InUnsafe) {
4649 return base.ResolveMemberAccess (ec, left, loc, original);
4652 public override Expression CreateExpressionTree (EmitContext ec)
4654 Expression instance;
4655 if (InstanceExpression == null) {
4656 instance = new NullLiteral (loc);
4658 instance = InstanceExpression.CreateExpressionTree (ec);
4661 ArrayList args = new ArrayList (2);
4662 args.Add (new Argument (instance));
4663 args.Add (new Argument (CreateTypeOfExpression ()));
4664 return CreateExpressionFactoryCall ("Field", args);
4667 public Expression CreateTypeOfExpression ()
4669 return new TypeOfField (FieldInfo, loc);
4672 override public Expression DoResolve (EmitContext ec)
4674 return DoResolve (ec, false, false);
4677 Expression DoResolve (EmitContext ec, bool lvalue_instance, bool out_access)
4679 if (!FieldInfo.IsStatic){
4680 if (InstanceExpression == null){
4682 // This can happen when referencing an instance field using
4683 // a fully qualified type expression: TypeName.InstanceField = xxx
4685 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4689 // Resolve the field's instance expression while flow analysis is turned
4690 // off: when accessing a field "a.b", we must check whether the field
4691 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4693 if (lvalue_instance) {
4694 using (ec.With (EmitContext.Flags.DoFlowAnalysis, false)) {
4695 Expression right_side =
4696 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4697 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side, loc);
4700 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
4701 InstanceExpression = InstanceExpression.Resolve (ec, rf);
4704 if (InstanceExpression == null)
4707 using (ec.Set (EmitContext.Flags.OmitStructFlowAnalysis)) {
4708 InstanceExpression.CheckMarshalByRefAccess (ec);
4712 if (!in_initializer && !ec.IsInFieldInitializer) {
4713 ObsoleteAttribute oa;
4714 FieldBase f = TypeManager.GetField (FieldInfo);
4716 if (!ec.IsInObsoleteScope)
4717 f.CheckObsoleteness (loc);
4719 // To be sure that type is external because we do not register generated fields
4720 } else if (!(FieldInfo.DeclaringType is TypeBuilder)) {
4721 oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
4723 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
4727 AnonymousContainer am = ec.CurrentAnonymousMethod;
4729 if (!FieldInfo.IsStatic){
4730 if (!am.IsIterator && (ec.TypeContainer is Struct)){
4731 Report.Error (1673, loc,
4732 "Anonymous methods inside structs cannot access instance members of `{0}'. Consider copying `{0}' to a local variable outside the anonymous method and using the local instead",
4739 IFixedBuffer fb = AttributeTester.GetFixedBuffer (FieldInfo);
4741 if (!ec.InFixedInitializer && ec.ContainerType.IsValueType) {
4742 Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4745 if (InstanceExpression.eclass != ExprClass.Variable) {
4746 Report.SymbolRelatedToPreviousError (FieldInfo);
4747 Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4748 TypeManager.GetFullNameSignature (FieldInfo));
4751 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4754 // If the instance expression is a local variable or parameter.
4755 IVariable var = InstanceExpression as IVariable;
4756 if ((var == null) || (var.VariableInfo == null))
4759 VariableInfo vi = var.VariableInfo;
4760 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
4763 variable_info = vi.GetSubStruct (FieldInfo.Name);
4767 static readonly int [] codes = {
4768 191, // instance, write access
4769 192, // instance, out access
4770 198, // static, write access
4771 199, // static, out access
4772 1648, // member of value instance, write access
4773 1649, // member of value instance, out access
4774 1650, // member of value static, write access
4775 1651 // member of value static, out access
4778 static readonly string [] msgs = {
4779 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4780 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4781 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4782 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4783 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4784 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4785 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4786 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4789 // The return value is always null. Returning a value simplifies calling code.
4790 Expression Report_AssignToReadonly (Expression right_side)
4793 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4797 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4799 Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4804 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4806 IVariable var = InstanceExpression as IVariable;
4807 if ((var != null) && (var.VariableInfo != null))
4808 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
4810 bool lvalue_instance = !FieldInfo.IsStatic && FieldInfo.DeclaringType.IsValueType;
4811 bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
4813 Expression e = DoResolve (ec, lvalue_instance, out_access);
4818 FieldBase fb = TypeManager.GetField (FieldInfo);
4822 if (FieldInfo.IsInitOnly) {
4823 // InitOnly fields can only be assigned in constructors or initializers
4824 if (!ec.IsInFieldInitializer && !ec.IsConstructor)
4825 return Report_AssignToReadonly (right_side);
4827 if (ec.IsConstructor) {
4828 Type ctype = ec.TypeContainer.CurrentType;
4830 ctype = ec.ContainerType;
4832 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4833 if (!TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
4834 return Report_AssignToReadonly (right_side);
4835 // static InitOnly fields cannot be assigned-to in an instance constructor
4836 if (IsStatic && !ec.IsStatic)
4837 return Report_AssignToReadonly (right_side);
4838 // instance constructors can't modify InitOnly fields of other instances of the same type
4839 if (!IsStatic && !(InstanceExpression is This))
4840 return Report_AssignToReadonly (right_side);
4844 if (right_side == EmptyExpression.OutAccess &&
4845 !IsStatic && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type)) {
4846 Report.SymbolRelatedToPreviousError (DeclaringType);
4847 Report.Warning (197, 1, loc,
4848 "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",
4849 GetSignatureForError ());
4855 public override void CheckMarshalByRefAccess (EmitContext ec)
4857 if (!IsStatic && Type.IsValueType && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type)) {
4858 Report.SymbolRelatedToPreviousError (DeclaringType);
4859 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",
4860 GetSignatureForError ());
4864 public bool VerifyFixed ()
4866 IVariable variable = InstanceExpression as IVariable;
4867 // A variable of the form V.I is fixed when V is a fixed variable of a struct type.
4868 // We defer the InstanceExpression check after the variable check to avoid a
4869 // separate null check on InstanceExpression.
4870 return variable != null && InstanceExpression.Type.IsValueType && variable.VerifyFixed ();
4873 public override int GetHashCode ()
4875 return FieldInfo.GetHashCode ();
4878 public override bool Equals (object obj)
4880 FieldExpr fe = obj as FieldExpr;
4884 if (FieldInfo != fe.FieldInfo)
4887 if (InstanceExpression == null || fe.InstanceExpression == null)
4890 return InstanceExpression.Equals (fe.InstanceExpression);
4893 public void Emit (EmitContext ec, bool leave_copy)
4895 ILGenerator ig = ec.ig;
4896 bool is_volatile = false;
4898 FieldBase f = TypeManager.GetField (FieldInfo);
4900 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4903 f.SetMemberIsUsed ();
4906 if (FieldInfo.IsStatic){
4908 ig.Emit (OpCodes.Volatile);
4910 ig.Emit (OpCodes.Ldsfld, FieldInfo);
4913 EmitInstance (ec, false);
4915 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
4917 ig.Emit (OpCodes.Ldflda, FieldInfo);
4918 ig.Emit (OpCodes.Ldflda, ff.Element);
4921 ig.Emit (OpCodes.Volatile);
4923 ig.Emit (OpCodes.Ldfld, FieldInfo);
4928 ec.ig.Emit (OpCodes.Dup);
4929 if (!FieldInfo.IsStatic) {
4930 temp = new LocalTemporary (this.Type);
4936 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4938 FieldAttributes fa = FieldInfo.Attributes;
4939 bool is_static = (fa & FieldAttributes.Static) != 0;
4940 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
4941 ILGenerator ig = ec.ig;
4943 if (is_readonly && !ec.IsConstructor){
4944 Report_AssignToReadonly (source);
4949 // String concatenation creates a new string instance
4951 prepared = prepare_for_load && !(source is StringConcat);
4952 EmitInstance (ec, prepared);
4956 ec.ig.Emit (OpCodes.Dup);
4957 if (!FieldInfo.IsStatic) {
4958 temp = new LocalTemporary (this.Type);
4963 FieldBase f = TypeManager.GetField (FieldInfo);
4965 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4966 ig.Emit (OpCodes.Volatile);
4972 ig.Emit (OpCodes.Stsfld, FieldInfo);
4974 ig.Emit (OpCodes.Stfld, FieldInfo);
4982 public override void Emit (EmitContext ec)
4987 public void AddressOf (EmitContext ec, AddressOp mode)
4989 ILGenerator ig = ec.ig;
4991 FieldBase f = TypeManager.GetField (FieldInfo);
4993 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
4994 Report.Warning (420, 1, loc, "`{0}': A volatile field references will not be treated as volatile",
4995 f.GetSignatureForError ());
4998 if ((mode & AddressOp.Store) != 0)
5000 if ((mode & AddressOp.Load) != 0)
5001 f.SetMemberIsUsed ();
5005 // Handle initonly fields specially: make a copy and then
5006 // get the address of the copy.
5009 if (FieldInfo.IsInitOnly){
5011 if (ec.IsConstructor){
5012 if (FieldInfo.IsStatic){
5024 local = ig.DeclareLocal (type);
5025 ig.Emit (OpCodes.Stloc, local);
5026 ig.Emit (OpCodes.Ldloca, local);
5031 if (FieldInfo.IsStatic){
5032 ig.Emit (OpCodes.Ldsflda, FieldInfo);
5035 EmitInstance (ec, false);
5036 ig.Emit (OpCodes.Ldflda, FieldInfo);
5043 /// Expression that evaluates to a Property. The Assign class
5044 /// might set the `Value' expression if we are in an assignment.
5046 /// This is not an LValue because we need to re-write the expression, we
5047 /// can not take data from the stack and store it.
5049 public class PropertyExpr : MemberExpr, IAssignMethod {
5050 public readonly PropertyInfo PropertyInfo;
5051 MethodInfo getter, setter;
5056 LocalTemporary temp;
5059 public PropertyExpr (Type container_type, PropertyInfo pi, Location l)
5062 eclass = ExprClass.PropertyAccess;
5066 type = TypeManager.TypeToCoreType (pi.PropertyType);
5068 ResolveAccessors (container_type);
5071 public override string Name {
5073 return PropertyInfo.Name;
5077 public override bool IsInstance {
5083 public override bool IsStatic {
5089 public override Expression CreateExpressionTree (EmitContext ec)
5091 if (IsSingleDimensionalArrayLength ()) {
5092 ArrayList args = new ArrayList (1);
5093 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5094 return CreateExpressionFactoryCall ("ArrayLength", args);
5097 // TODO: it's waiting for PropertyExpr refactoring
5098 //ArrayList args = new ArrayList (2);
5099 //args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5100 //args.Add (getter expression);
5101 //return CreateExpressionFactoryCall ("Property", args);
5102 return base.CreateExpressionTree (ec);
5105 public Expression CreateSetterTypeOfExpression ()
5107 return new Cast (new TypeExpression (typeof (MethodInfo), loc), new TypeOfMethod (setter, loc));
5110 public override Type DeclaringType {
5112 return PropertyInfo.DeclaringType;
5116 public override string GetSignatureForError ()
5118 return TypeManager.GetFullNameSignature (PropertyInfo);
5121 void FindAccessors (Type invocation_type)
5123 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
5124 BindingFlags.Static | BindingFlags.Instance |
5125 BindingFlags.DeclaredOnly;
5127 Type current = PropertyInfo.DeclaringType;
5128 for (; current != null; current = current.BaseType) {
5129 MemberInfo[] group = TypeManager.MemberLookup (
5130 invocation_type, invocation_type, current,
5131 MemberTypes.Property, flags, PropertyInfo.Name, null);
5136 if (group.Length != 1)
5137 // Oooops, can this ever happen ?
5140 PropertyInfo pi = (PropertyInfo) group [0];
5143 getter = pi.GetGetMethod (true);
5146 setter = pi.GetSetMethod (true);
5148 MethodInfo accessor = getter != null ? getter : setter;
5150 if (!accessor.IsVirtual)
5156 // We also perform the permission checking here, as the PropertyInfo does not
5157 // hold the information for the accessibility of its setter/getter
5159 // TODO: Refactor to use some kind of cache together with GetPropertyFromAccessor
5160 void ResolveAccessors (Type container_type)
5162 FindAccessors (container_type);
5164 if (getter != null) {
5165 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
5166 IMethodData md = TypeManager.GetMethod (the_getter);
5168 md.SetMemberIsUsed ();
5170 is_static = getter.IsStatic;
5173 if (setter != null) {
5174 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
5175 IMethodData md = TypeManager.GetMethod (the_setter);
5177 md.SetMemberIsUsed ();
5179 is_static = setter.IsStatic;
5183 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
5186 InstanceExpression = null;
5190 if (InstanceExpression == null) {
5191 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5195 InstanceExpression = InstanceExpression.DoResolve (ec);
5196 if (lvalue_instance && InstanceExpression != null)
5197 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
5199 if (InstanceExpression == null)
5202 InstanceExpression.CheckMarshalByRefAccess (ec);
5204 if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) &&
5205 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
5206 !TypeManager.IsNestedChildOf (ec.ContainerType, InstanceExpression.Type) &&
5207 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.ContainerType)) {
5208 Report.SymbolRelatedToPreviousError (PropertyInfo);
5209 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
5216 void Error_PropertyNotFound (MethodInfo mi, bool getter)
5218 // TODO: correctly we should compare arguments but it will lead to bigger changes
5219 if (mi is MethodBuilder) {
5220 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
5224 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
5226 ParameterData iparams = TypeManager.GetParameterData (mi);
5227 sig.Append (getter ? "get_" : "set_");
5229 sig.Append (iparams.GetSignatureForError ());
5231 Report.SymbolRelatedToPreviousError (mi);
5232 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
5233 Name, sig.ToString ());
5236 public bool IsAccessibleFrom (Type invocation_type, bool lvalue)
5239 MethodInfo accessor = lvalue ? setter : getter;
5240 if (accessor == null && lvalue)
5242 return accessor != null && IsAccessorAccessible (invocation_type, accessor, out dummy);
5245 bool IsSingleDimensionalArrayLength ()
5247 if (DeclaringType != TypeManager.array_type || getter == null || Name != "Length")
5250 string t_name = InstanceExpression.Type.Name;
5251 int t_name_len = t_name.Length;
5252 return t_name_len > 2 && t_name [t_name_len - 2] == '[' && t_name [t_name_len - 3] != ']';
5255 override public Expression DoResolve (EmitContext ec)
5260 if (getter != null){
5261 if (TypeManager.GetParameterData (getter).Count != 0){
5262 Error_PropertyNotFound (getter, true);
5267 if (getter == null){
5269 // The following condition happens if the PropertyExpr was
5270 // created, but is invalid (ie, the property is inaccessible),
5271 // and we did not want to embed the knowledge about this in
5272 // the caller routine. This only avoids double error reporting.
5277 if (InstanceExpression != EmptyExpression.Null) {
5278 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5279 TypeManager.GetFullNameSignature (PropertyInfo));
5284 bool must_do_cs1540_check = false;
5285 if (getter != null &&
5286 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
5287 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
5288 if (pm != null && pm.HasCustomAccessModifier) {
5289 Report.SymbolRelatedToPreviousError (pm);
5290 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5291 TypeManager.CSharpSignature (getter));
5294 Report.SymbolRelatedToPreviousError (getter);
5295 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
5300 if (!InstanceResolve (ec, false, must_do_cs1540_check))
5304 // Only base will allow this invocation to happen.
5306 if (IsBase && getter.IsAbstract) {
5307 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5311 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
5321 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
5323 if (right_side == EmptyExpression.OutAccess) {
5324 if (ec.CurrentBlock.Toplevel.GetTransparentIdentifier (PropertyInfo.Name) != null) {
5325 Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5328 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as `ref' or `out' parameter",
5329 GetSignatureForError ());
5334 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5335 Error_CannotModifyIntermediateExpressionValue (ec);
5338 if (setter == null){
5340 // The following condition happens if the PropertyExpr was
5341 // created, but is invalid (ie, the property is inaccessible),
5342 // and we did not want to embed the knowledge about this in
5343 // the caller routine. This only avoids double error reporting.
5347 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
5348 GetSignatureForError ());
5352 if (TypeManager.GetParameterData (setter).Count != 1){
5353 Error_PropertyNotFound (setter, false);
5357 bool must_do_cs1540_check;
5358 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
5359 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
5360 if (pm != null && pm.HasCustomAccessModifier) {
5361 Report.SymbolRelatedToPreviousError (pm);
5362 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5363 TypeManager.CSharpSignature (setter));
5366 Report.SymbolRelatedToPreviousError (setter);
5367 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
5372 if (!InstanceResolve (ec, PropertyInfo.DeclaringType.IsValueType, must_do_cs1540_check))
5376 // Only base will allow this invocation to happen.
5378 if (IsBase && setter.IsAbstract){
5379 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5386 public override void Emit (EmitContext ec)
5391 public void Emit (EmitContext ec, bool leave_copy)
5394 // Special case: length of single dimension array property is turned into ldlen
5396 if (IsSingleDimensionalArrayLength ()) {
5398 EmitInstance (ec, false);
5399 ec.ig.Emit (OpCodes.Ldlen);
5400 ec.ig.Emit (OpCodes.Conv_I4);
5404 Invocation.EmitCall (ec, IsBase, InstanceExpression, getter, null, loc, prepared, false);
5407 ec.ig.Emit (OpCodes.Dup);
5409 temp = new LocalTemporary (this.Type);
5416 // Implements the IAssignMethod interface for assignments
5418 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5420 Expression my_source = source;
5422 if (prepare_for_load) {
5423 if (source is StringConcat)
5424 EmitInstance (ec, false);
5432 ec.ig.Emit (OpCodes.Dup);
5434 temp = new LocalTemporary (this.Type);
5438 } else if (leave_copy) {
5440 temp = new LocalTemporary (this.Type);
5445 ArrayList args = new ArrayList (1);
5446 args.Add (new Argument (my_source, Argument.AType.Expression));
5448 Invocation.EmitCall (ec, IsBase, InstanceExpression, setter, args, loc, false, prepared);
5458 /// Fully resolved expression that evaluates to an Event
5460 public class EventExpr : MemberExpr {
5461 public readonly EventInfo EventInfo;
5464 MethodInfo add_accessor, remove_accessor;
5466 public EventExpr (EventInfo ei, Location loc)
5470 eclass = ExprClass.EventAccess;
5472 add_accessor = TypeManager.GetAddMethod (ei);
5473 remove_accessor = TypeManager.GetRemoveMethod (ei);
5474 if (add_accessor.IsStatic || remove_accessor.IsStatic)
5477 if (EventInfo is MyEventBuilder){
5478 MyEventBuilder eb = (MyEventBuilder) EventInfo;
5479 type = eb.EventType;
5482 type = EventInfo.EventHandlerType;
5485 public override string Name {
5487 return EventInfo.Name;
5491 public override bool IsInstance {
5497 public override bool IsStatic {
5503 public override Type DeclaringType {
5505 return EventInfo.DeclaringType;
5509 void Error_AssignmentEventOnly ()
5511 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5512 GetSignatureForError ());
5515 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
5516 SimpleName original)
5519 // If the event is local to this class, we transform ourselves into a FieldExpr
5522 if (EventInfo.DeclaringType == ec.ContainerType ||
5523 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
5524 EventField mi = TypeManager.GetEventField (EventInfo);
5527 if (!ec.IsInObsoleteScope)
5528 mi.CheckObsoleteness (loc);
5530 if ((mi.ModFlags & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0 && !ec.IsInCompoundAssignment)
5531 Error_AssignmentEventOnly ();
5533 FieldExpr ml = new FieldExpr (mi.FieldBuilder, loc);
5535 InstanceExpression = null;
5537 return ml.ResolveMemberAccess (ec, left, loc, original);
5541 if (left is This && !ec.IsInCompoundAssignment)
5542 Error_AssignmentEventOnly ();
5544 return base.ResolveMemberAccess (ec, left, loc, original);
5548 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
5551 InstanceExpression = null;
5555 if (InstanceExpression == null) {
5556 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5560 InstanceExpression = InstanceExpression.DoResolve (ec);
5561 if (InstanceExpression == null)
5564 if (IsBase && add_accessor.IsAbstract) {
5565 Error_CannotCallAbstractBase(TypeManager.CSharpSignature(add_accessor));
5570 // This is using the same mechanism as the CS1540 check in PropertyExpr.
5571 // However, in the Event case, we reported a CS0122 instead.
5573 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
5574 InstanceExpression.Type != ec.ContainerType &&
5575 TypeManager.IsSubclassOf (ec.ContainerType, InstanceExpression.Type)) {
5576 Report.SymbolRelatedToPreviousError (EventInfo);
5577 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5584 public bool IsAccessibleFrom (Type invocation_type)
5587 return IsAccessorAccessible (invocation_type, add_accessor, out dummy) &&
5588 IsAccessorAccessible (invocation_type, remove_accessor, out dummy);
5591 public override Expression CreateExpressionTree (EmitContext ec)
5593 throw new NotSupportedException ();
5596 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5598 return DoResolve (ec);
5601 public override Expression DoResolve (EmitContext ec)
5603 bool must_do_cs1540_check;
5604 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
5605 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
5606 Report.SymbolRelatedToPreviousError (EventInfo);
5607 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5611 if (!InstanceResolve (ec, must_do_cs1540_check))
5617 public override void Emit (EmitContext ec)
5619 Report.Error (70, loc, "The event `{0}' can only appear on the left hand side of += or -= "+
5620 "(except on the defining type)", GetSignatureForError ());
5623 public override string GetSignatureForError ()
5625 return TypeManager.CSharpSignature (EventInfo);
5628 public void EmitAddOrRemove (EmitContext ec, Expression source)
5630 BinaryDelegate source_del = source as BinaryDelegate;
5631 if (source_del == null) {
5635 Expression handler = source_del.Right;
5637 Argument arg = new Argument (handler, Argument.AType.Expression);
5638 ArrayList args = new ArrayList ();
5642 if (source_del.IsAddition)
5643 Invocation.EmitCall (
5644 ec, IsBase, InstanceExpression, add_accessor, args, loc);
5646 Invocation.EmitCall (
5647 ec, IsBase, InstanceExpression, remove_accessor, args, loc);
5651 public class TemporaryVariable : Expression, IMemoryLocation
5656 public TemporaryVariable (Type type, Location loc)
5660 eclass = ExprClass.Value;
5663 public override Expression DoResolve (EmitContext ec)
5668 TypeExpr te = new TypeExpression (type, loc);
5669 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
5670 if (!li.Resolve (ec))
5673 if (ec.MustCaptureVariable (li)) {
5674 ScopeInfo scope = li.Block.CreateScopeInfo ();
5675 var = scope.AddLocal (li);
5682 public Variable Variable {
5683 get { return var != null ? var : li.Variable; }
5686 public override void Emit (EmitContext ec)
5688 Variable.EmitInstance (ec);
5692 public void EmitLoadAddress (EmitContext ec)
5694 Variable.EmitInstance (ec);
5695 Variable.EmitAddressOf (ec);
5698 public void Store (EmitContext ec, Expression right_side)
5700 Variable.EmitInstance (ec);
5701 right_side.Emit (ec);
5702 Variable.EmitAssign (ec);
5705 public void EmitThis (EmitContext ec)
5707 Variable.EmitInstance (ec);
5710 public void EmitStore (EmitContext ec)
5712 Variable.EmitAssign (ec);
5715 public void AddressOf (EmitContext ec, AddressOp mode)
5717 EmitLoadAddress (ec);
5722 /// Handles `var' contextual keyword; var becomes a keyword only
5723 /// if no type called var exists in a variable scope
5725 public class VarExpr : SimpleName
5727 // Used for error reporting only
5728 ArrayList initializer;
5730 public VarExpr (Location loc)
5735 public ArrayList VariableInitializer {
5737 this.initializer = value;
5741 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5744 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
5746 type = right_side.Type;
5747 if (type == TypeManager.null_type || type == TypeManager.void_type || type == TypeManager.anonymous_method_type) {
5748 Report.Error (815, loc, "An implicitly typed local variable declaration cannot be initialized with `{0}'",
5749 right_side.GetSignatureForError ());
5753 eclass = ExprClass.Variable;
5757 protected override void Error_TypeOrNamespaceNotFound (IResolveContext ec)
5759 Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");
5762 public override TypeExpr ResolveAsContextualType (IResolveContext rc, bool silent)
5764 TypeExpr te = base.ResolveAsContextualType (rc, true);
5768 if (initializer == null)
5771 if (initializer.Count > 1) {
5772 Location loc = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [1]).Location;
5773 Report.Error (819, loc, "An implicitly typed local variable declaration cannot include multiple declarators");
5778 Expression variable_initializer = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [0]).expression_or_array_initializer;
5779 if (variable_initializer == null) {
5780 Report.Error (818, loc, "An implicitly typed local variable declarator must include an initializer");