2 // ecore.cs: Core of the Expression representation for the intermediate tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@seznam.cz)
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
13 namespace Mono.CSharp {
15 using System.Collections;
16 using System.Diagnostics;
17 using System.Reflection;
18 using System.Reflection.Emit;
22 /// The ExprClass class contains the is used to pass the
23 /// classification of an expression (value, variable, namespace,
24 /// type, method group, property access, event access, indexer access,
27 public enum ExprClass : byte {
42 /// This is used to tell Resolve in which types of expressions we're
46 public enum ResolveFlags {
47 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
50 // Returns a type expression.
53 // Returns a method group.
56 // Mask of all the expression class flags.
59 // Disable control flow analysis while resolving the expression.
60 // This is used when resolving the instance expression of a field expression.
61 DisableFlowAnalysis = 8,
63 // Set if this is resolving the first part of a MemberAccess.
66 // Disable control flow analysis _of struct_ while resolving the expression.
67 // This is used when resolving the instance expression of a field expression.
68 DisableStructFlowAnalysis = 32,
73 // This is just as a hint to AddressOf of what will be done with the
76 public enum AddressOp {
83 /// This interface is implemented by variables
85 public interface IMemoryLocation {
87 /// The AddressOf method should generate code that loads
88 /// the address of the object and leaves it on the stack.
90 /// The `mode' argument is used to notify the expression
91 /// of whether this will be used to read from the address or
92 /// write to the address.
94 /// This is just a hint that can be used to provide good error
95 /// reporting, and should have no other side effects.
97 void AddressOf (EmitContext ec, AddressOp mode);
101 /// This interface is implemented by variables
103 public interface IVariable {
104 VariableInfo VariableInfo {
112 /// Base class for expressions
114 public abstract class Expression {
115 public ExprClass eclass;
117 protected Location loc;
121 set { type = value; }
124 public virtual Location Location {
129 /// Utility wrapper routine for Error, just to beautify the code
131 public void Error (int error, string s)
133 Report.Error (error, loc, s);
136 // Not nice but we have broken hierarchy.
137 public virtual void CheckMarshalByRefAccess (EmitContext ec)
141 public virtual bool GetAttributableValue (Type value_type, out object value)
143 Attribute.Error_AttributeArgumentNotValid (loc);
148 public virtual string GetSignatureForError ()
150 return TypeManager.CSharpName (type);
153 public static bool IsAccessorAccessible (Type invocation_type, MethodInfo mi, out bool must_do_cs1540_check)
155 MethodAttributes ma = mi.Attributes & MethodAttributes.MemberAccessMask;
157 must_do_cs1540_check = false; // by default we do not check for this
159 if (ma == MethodAttributes.Public)
163 // If only accessible to the current class or children
165 if (ma == MethodAttributes.Private)
166 return TypeManager.IsPrivateAccessible (invocation_type, mi.DeclaringType) ||
167 TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType);
169 if (TypeManager.IsThisOrFriendAssembly (mi.DeclaringType.Assembly)) {
170 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamORAssem)
173 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamANDAssem)
177 // Family and FamANDAssem require that we derive.
178 // FamORAssem requires that we derive if in different assemblies.
179 if (!TypeManager.IsNestedFamilyAccessible (invocation_type, mi.DeclaringType))
182 if (!TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType))
183 must_do_cs1540_check = true;
188 public virtual bool IsNull {
195 /// Performs semantic analysis on the Expression
199 /// The Resolve method is invoked to perform the semantic analysis
202 /// The return value is an expression (it can be the
203 /// same expression in some cases) or a new
204 /// expression that better represents this node.
206 /// For example, optimizations of Unary (LiteralInt)
207 /// would return a new LiteralInt with a negated
210 /// If there is an error during semantic analysis,
211 /// then an error should be reported (using Report)
212 /// and a null value should be returned.
214 /// There are two side effects expected from calling
215 /// Resolve(): the the field variable "eclass" should
216 /// be set to any value of the enumeration
217 /// `ExprClass' and the type variable should be set
218 /// to a valid type (this is the type of the
221 public abstract Expression DoResolve (EmitContext ec);
223 public virtual Expression DoResolveLValue (EmitContext ec, Expression right_side)
229 // This is used if the expression should be resolved as a type or namespace name.
230 // the default implementation fails.
232 public virtual FullNamedExpression ResolveAsTypeStep (IResolveContext rc, bool silent)
236 EmitContext ec = rc as EmitContext;
240 e.Error_UnexpectedKind (ResolveFlags.Type, loc);
246 // C# 3.0 introduced contextual keywords (var) which behaves like a type if type with
247 // same name exists or as a keyword when no type was found
249 public virtual TypeExpr ResolveAsContextualType (IResolveContext rc, bool silent)
251 return ResolveAsTypeTerminal (rc, silent);
255 // This is used to resolve the expression as a type, a null
256 // value will be returned if the expression is not a type
259 public virtual TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
261 TypeExpr te = ResolveAsBaseTerminal (ec, silent);
265 if (!silent) { // && !(te is TypeParameterExpr)) {
266 ObsoleteAttribute obsolete_attr = AttributeTester.GetObsoleteAttribute (te.Type);
267 if (obsolete_attr != null && !ec.IsInObsoleteScope) {
268 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location);
272 // Constrains don't need to be checked for overrides
273 GenericMethod gm = ec.GenericDeclContainer as GenericMethod;
274 if (gm != null && (gm.ModFlags & Modifiers.OVERRIDE) != 0) {
279 ConstructedType ct = te as ConstructedType;
280 if ((ct != null) && !ct.CheckConstraints (ec))
286 public TypeExpr ResolveAsBaseTerminal (IResolveContext ec, bool silent)
288 int errors = Report.Errors;
290 FullNamedExpression fne = ResolveAsTypeStep (ec, silent);
295 if (fne.eclass != ExprClass.Type) {
296 if (!silent && errors == Report.Errors)
297 fne.Error_UnexpectedKind (null, "type", loc);
301 TypeExpr te = fne as TypeExpr;
303 if (!te.CheckAccessLevel (ec.DeclContainer)) {
304 Report.SymbolRelatedToPreviousError (te.Type);
305 ErrorIsInaccesible (loc, TypeManager.CSharpName (te.Type));
313 public static void ErrorIsInaccesible (Location loc, string name)
315 Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", name);
318 protected static void Error_CannotAccessProtected (Location loc, MemberInfo m, Type qualifier, Type container)
320 Report.Error (1540, loc, "Cannot access protected member `{0}' via a qualifier of type `{1}'."
321 + " The qualifier must be of type `{2}' or derived from it",
322 TypeManager.GetFullNameSignature (m),
323 TypeManager.CSharpName (qualifier),
324 TypeManager.CSharpName (container));
328 public static void Error_InvalidExpressionStatement (Location loc)
330 Report.Error (201, loc, "Only assignment, call, increment, decrement, and new object " +
331 "expressions can be used as a statement");
334 public void Error_InvalidExpressionStatement ()
336 Error_InvalidExpressionStatement (loc);
339 protected void Error_CannotAssign (string to, string roContext)
341 Report.Error (1656, loc, "Cannot assign to `{0}' because it is a `{1}'",
345 public static void Error_VoidInvalidInTheContext (Location loc)
347 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
350 public virtual void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl)
352 // The error was already reported as CS1660
353 if (type == TypeManager.anonymous_method_type)
356 if (TypeManager.IsGenericParameter (Type) && TypeManager.IsGenericParameter (target) && type.Name == target.Name) {
358 string sig1 = type.DeclaringMethod == null ?
359 TypeManager.CSharpName (type.DeclaringType) :
360 TypeManager.CSharpSignature (type.DeclaringMethod);
361 string sig2 = target.DeclaringMethod == null ?
362 TypeManager.CSharpName (target.DeclaringType) :
363 TypeManager.CSharpSignature (target.DeclaringMethod);
364 Report.ExtraInformation (loc,
366 "The generic parameter `{0}' of `{1}' cannot be converted to the generic parameter `{0}' of `{2}' (in the previous ",
367 Type.Name, sig1, sig2));
369 } else if (Type.FullName == target.FullName){
370 Report.ExtraInformation (loc,
372 "The type `{0}' has two conflicting definitions, one comes from `{1}' and the other from `{2}' (in the previous ",
373 Type.FullName, Type.Assembly.FullName, target.Assembly.FullName));
377 Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
378 TypeManager.CSharpName (type), TypeManager.CSharpName (target));
382 Expression e = (this is EnumConstant) ? ((EnumConstant)this).Child : this;
383 bool b = Convert.ExplicitNumericConversion (e, target) != null;
386 Convert.ExplicitReferenceConversionExists (Type, target) ||
387 Convert.ExplicitUnsafe (e, target) != null ||
388 (ec != null && Convert.ExplicitUserConversion (ec, this, target, Location.Null) != null))
390 Report.Error (266, loc, "Cannot implicitly convert type `{0}' to `{1}'. " +
391 "An explicit conversion exists (are you missing a cast?)",
392 TypeManager.CSharpName (Type), TypeManager.CSharpName (target));
396 if (Type != TypeManager.string_type && this is Constant && !(this is EmptyConstantCast)) {
397 Report.Error (31, loc, "Constant value `{0}' cannot be converted to a `{1}'",
398 ((Constant)(this)).GetValue ().ToString (), TypeManager.CSharpName (target));
402 Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
403 TypeManager.CSharpName (type),
404 TypeManager.CSharpName (target));
407 protected void Error_VariableIsUsedBeforeItIsDeclared (string name)
409 Report.Error (841, loc, "The variable `{0}' cannot be used before it is declared",
413 protected virtual void Error_TypeDoesNotContainDefinition (Type type, string name)
415 Error_TypeDoesNotContainDefinition (loc, type, name);
418 public static void Error_TypeDoesNotContainDefinition (Location loc, Type type, string name)
420 Report.SymbolRelatedToPreviousError (type);
421 Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
422 TypeManager.CSharpName (type), name);
425 protected static void Error_ValueAssignment (Location loc)
427 Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
430 ResolveFlags ExprClassToResolveFlags
435 case ExprClass.Namespace:
436 return ResolveFlags.Type;
438 case ExprClass.MethodGroup:
439 return ResolveFlags.MethodGroup;
441 case ExprClass.Value:
442 case ExprClass.Variable:
443 case ExprClass.PropertyAccess:
444 case ExprClass.EventAccess:
445 case ExprClass.IndexerAccess:
446 return ResolveFlags.VariableOrValue;
449 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
455 /// Resolves an expression and performs semantic analysis on it.
459 /// Currently Resolve wraps DoResolve to perform sanity
460 /// checking and assertion checking on what we expect from Resolve.
462 public Expression Resolve (EmitContext ec, ResolveFlags flags)
464 if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type)
465 return ResolveAsTypeStep (ec, false);
467 bool do_flow_analysis = ec.DoFlowAnalysis;
468 bool omit_struct_analysis = ec.OmitStructFlowAnalysis;
469 if ((flags & ResolveFlags.DisableFlowAnalysis) != 0)
470 do_flow_analysis = false;
471 if ((flags & ResolveFlags.DisableStructFlowAnalysis) != 0)
472 omit_struct_analysis = true;
475 using (ec.WithFlowAnalysis (do_flow_analysis, omit_struct_analysis)) {
476 if (this is SimpleName) {
477 bool intermediate = (flags & ResolveFlags.Intermediate) == ResolveFlags.Intermediate;
478 e = ((SimpleName) this).DoResolve (ec, intermediate);
487 if ((flags & e.ExprClassToResolveFlags) == 0) {
488 e.Error_UnexpectedKind (flags, loc);
492 if (e.type == null && !(e is Namespace)) {
493 throw new Exception (
494 "Expression " + e.GetType () +
495 " did not set its type after Resolve\n" +
496 "called from: " + this.GetType ());
503 /// Resolves an expression and performs semantic analysis on it.
505 public Expression Resolve (EmitContext ec)
507 Expression e = Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
509 if (e != null && e.eclass == ExprClass.MethodGroup && RootContext.Version == LanguageVersion.ISO_1) {
510 ((MethodGroupExpr) e).ReportUsageError ();
516 public Constant ResolveAsConstant (EmitContext ec, MemberCore mc)
518 Expression e = Resolve (ec);
522 Constant c = e as Constant;
526 Const.Error_ExpressionMustBeConstant (loc, mc.GetSignatureForError ());
531 /// Resolves an expression for LValue assignment
535 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
536 /// checking and assertion checking on what we expect from Resolve
538 public Expression ResolveLValue (EmitContext ec, Expression right_side, Location loc)
540 int errors = Report.Errors;
541 bool out_access = right_side == EmptyExpression.OutAccess;
543 Expression e = DoResolveLValue (ec, right_side);
545 if (e != null && out_access && !(e is IMemoryLocation)) {
546 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
547 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
549 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
550 // e.GetType () + " " + e.GetSignatureForError ());
555 if (errors == Report.Errors) {
557 Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
559 Error_ValueAssignment (loc);
564 if (e.eclass == ExprClass.Invalid)
565 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
567 if (e.eclass == ExprClass.MethodGroup) {
568 ((MethodGroupExpr) e).ReportUsageError ();
572 if ((e.type == null) && !(e is ConstructedType))
573 throw new Exception ("Expression " + e + " did not set its type after Resolve");
579 /// Emits the code for the expression
583 /// The Emit method is invoked to generate the code
584 /// for the expression.
586 public abstract void Emit (EmitContext ec);
588 // Emit code to branch to @target if this expression is equivalent to @on_true.
589 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
590 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
591 // including the use of conditional branches. Note also that a branch MUST be emitted
592 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
595 ec.ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
598 // Emit this expression for its side effects, not for its value.
599 // The default implementation is to emit the value, and then throw it away.
600 // Subclasses can provide more efficient implementations, but those MUST be equivalent
601 public virtual void EmitSideEffect (EmitContext ec)
604 ec.ig.Emit (OpCodes.Pop);
608 /// Protected constructor. Only derivate types should
609 /// be able to be created
612 protected Expression ()
614 eclass = ExprClass.Invalid;
619 /// Returns a fully formed expression after a MemberLookup
622 public static Expression ExprClassFromMemberInfo (Type container_type, MemberInfo mi, Location loc)
625 return new EventExpr ((EventInfo) mi, loc);
626 else if (mi is FieldInfo) {
627 FieldInfo fi = (FieldInfo) mi;
628 if (fi.IsLiteral || (fi.IsInitOnly && fi.FieldType == TypeManager.decimal_type))
629 return new ConstantExpr (fi, loc);
630 return new FieldExpr (fi, loc);
631 } else if (mi is PropertyInfo)
632 return new PropertyExpr (container_type, (PropertyInfo) mi, loc);
633 else if (mi is Type) {
634 return new TypeExpression ((System.Type) mi, loc);
640 protected static ArrayList almost_matched_members = new ArrayList (4);
643 // FIXME: Probably implement a cache for (t,name,current_access_set)?
645 // This code could use some optimizations, but we need to do some
646 // measurements. For example, we could use a delegate to `flag' when
647 // something can not any longer be a method-group (because it is something
651 // If the return value is an Array, then it is an array of
654 // If the return value is an MemberInfo, it is anything, but a Method
658 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
659 // the arguments here and have MemberLookup return only the methods that
660 // match the argument count/type, unlike we are doing now (we delay this
663 // This is so we can catch correctly attempts to invoke instance methods
664 // from a static body (scan for error 120 in ResolveSimpleName).
667 // FIXME: Potential optimization, have a static ArrayList
670 public static Expression MemberLookup (Type container_type, Type queried_type, string name,
671 MemberTypes mt, BindingFlags bf, Location loc)
673 return MemberLookup (container_type, null, queried_type, name, mt, bf, loc);
677 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
678 // `qualifier_type' or null to lookup members in the current class.
681 public static Expression MemberLookup (Type container_type,
682 Type qualifier_type, Type queried_type,
683 string name, MemberTypes mt,
684 BindingFlags bf, Location loc)
686 almost_matched_members.Clear ();
688 MemberInfo [] mi = TypeManager.MemberLookup (container_type, qualifier_type,
689 queried_type, mt, bf, name, almost_matched_members);
695 bool is_interface = qualifier_type != null && qualifier_type.IsInterface;
696 ArrayList methods = new ArrayList (2);
697 ArrayList non_methods = null;
699 foreach (MemberInfo m in mi) {
700 if (m is MethodBase) {
705 if (non_methods == null) {
706 non_methods = new ArrayList (2);
711 foreach (MemberInfo n_m in non_methods) {
712 if (m.DeclaringType.IsInterface && TypeManager.ImplementsInterface (m.DeclaringType, n_m.DeclaringType))
715 Report.SymbolRelatedToPreviousError (m);
716 Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
717 TypeManager.GetFullNameSignature (m), TypeManager.GetFullNameSignature (n_m));
722 if (methods.Count == 0)
723 return ExprClassFromMemberInfo (container_type, (MemberInfo)non_methods [0], loc);
725 if (non_methods != null) {
726 MethodBase method = (MethodBase) methods [0];
727 MemberInfo non_method = (MemberInfo) non_methods [0];
728 if (method.DeclaringType == non_method.DeclaringType) {
729 // Cannot happen with C# code, but is valid in IL
730 Report.SymbolRelatedToPreviousError (method);
731 Report.SymbolRelatedToPreviousError (non_method);
732 Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
733 TypeManager.GetFullNameSignature (non_method),
734 TypeManager.CSharpSignature (method));
739 Report.SymbolRelatedToPreviousError (method);
740 Report.SymbolRelatedToPreviousError (non_method);
741 Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and non-method `{1}'. Using method `{0}'",
742 TypeManager.CSharpSignature (method), TypeManager.GetFullNameSignature (non_method));
746 return new MethodGroupExpr (methods, queried_type, loc);
749 if (mi [0] is MethodBase)
750 return new MethodGroupExpr (mi, queried_type, loc);
752 return ExprClassFromMemberInfo (container_type, mi [0], loc);
755 public const MemberTypes AllMemberTypes =
756 MemberTypes.Constructor |
760 MemberTypes.NestedType |
761 MemberTypes.Property;
763 public const BindingFlags AllBindingFlags =
764 BindingFlags.Public |
765 BindingFlags.Static |
766 BindingFlags.Instance;
768 public static Expression MemberLookup (Type container_type, Type queried_type,
769 string name, Location loc)
771 return MemberLookup (container_type, null, queried_type, name,
772 AllMemberTypes, AllBindingFlags, loc);
775 public static Expression MemberLookup (Type container_type, Type qualifier_type,
776 Type queried_type, string name, Location loc)
778 return MemberLookup (container_type, qualifier_type, queried_type,
779 name, AllMemberTypes, AllBindingFlags, loc);
782 public static MethodGroupExpr MethodLookup (Type container_type, Type queried_type,
783 string name, Location loc)
785 return (MethodGroupExpr)MemberLookup (container_type, null, queried_type, name,
786 MemberTypes.Method, AllBindingFlags, loc);
790 /// This is a wrapper for MemberLookup that is not used to "probe", but
791 /// to find a final definition. If the final definition is not found, we
792 /// look for private members and display a useful debugging message if we
795 protected Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
796 Type queried_type, string name,
797 MemberTypes mt, BindingFlags bf,
802 int errors = Report.Errors;
804 e = MemberLookup (ec.ContainerType, qualifier_type, queried_type, name, mt, bf, loc);
806 if (e != null || errors != Report.Errors)
809 // No errors were reported by MemberLookup, but there was an error.
810 return Error_MemberLookupFailed (ec.ContainerType, qualifier_type, queried_type,
814 protected virtual Expression Error_MemberLookupFailed (Type container_type, Type qualifier_type,
815 Type queried_type, string name, string class_name,
816 MemberTypes mt, BindingFlags bf)
818 if (almost_matched_members.Count != 0) {
819 for (int i = 0; i < almost_matched_members.Count; ++i) {
820 MemberInfo m = (MemberInfo) almost_matched_members [i];
821 for (int j = 0; j < i; ++j) {
822 if (m == almost_matched_members [j]) {
830 Type declaring_type = m.DeclaringType;
832 Report.SymbolRelatedToPreviousError (m);
833 if (qualifier_type == null) {
834 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
835 TypeManager.CSharpName (m.DeclaringType),
836 TypeManager.CSharpName (container_type));
838 } else if (qualifier_type != container_type &&
839 TypeManager.IsNestedFamilyAccessible (container_type, declaring_type)) {
840 // Although a derived class can access protected members of
841 // its base class it cannot do so through an instance of the
842 // base class (CS1540). If the qualifier_type is a base of the
843 // ec.ContainerType and the lookup succeeds with the latter one,
844 // then we are in this situation.
845 Error_CannotAccessProtected (loc, m, qualifier_type, container_type);
847 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (m));
850 almost_matched_members.Clear ();
854 MemberInfo[] lookup = null;
855 if (queried_type == null) {
856 class_name = "global::";
858 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
859 mt, (bf & ~BindingFlags.Public) | BindingFlags.NonPublic,
862 if (lookup != null) {
863 Report.SymbolRelatedToPreviousError (lookup [0]);
864 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (lookup [0]));
865 return Error_MemberLookupFailed (lookup);
868 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
869 AllMemberTypes, AllBindingFlags | BindingFlags.NonPublic,
873 if (lookup == null) {
874 if (class_name != null) {
875 Report.Error (103, loc, "The name `{0}' does not exist in the current context",
878 Error_TypeDoesNotContainDefinition (queried_type, name);
883 if (TypeManager.MemberLookup (queried_type, null, queried_type,
884 AllMemberTypes, AllBindingFlags |
885 BindingFlags.NonPublic, name, null) == null) {
886 if ((lookup.Length == 1) && (lookup [0] is Type)) {
887 Type t = (Type) lookup [0];
889 Report.Error (305, loc,
890 "Using the generic type `{0}' " +
891 "requires {1} type arguments",
892 TypeManager.CSharpName (t),
893 TypeManager.GetNumberOfTypeArguments (t).ToString ());
898 return Error_MemberLookupFailed (lookup);
901 protected virtual Expression Error_MemberLookupFailed (MemberInfo[] members)
903 for (int i = 0; i < members.Length; ++i) {
904 if (!(members [i] is MethodBase))
908 // By default propagate the closest candidates upwards
909 return new MethodGroupExpr (members, type, loc);
912 protected virtual void Error_NegativeArrayIndex (Location loc)
914 throw new NotImplementedException ();
918 /// Returns an expression that can be used to invoke operator true
919 /// on the expression if it exists.
921 static public Expression GetOperatorTrue (EmitContext ec, Expression e, Location loc)
923 return GetOperatorTrueOrFalse (ec, e, true, loc);
927 /// Returns an expression that can be used to invoke operator false
928 /// on the expression if it exists.
930 static public Expression GetOperatorFalse (EmitContext ec, Expression e, Location loc)
932 return GetOperatorTrueOrFalse (ec, e, false, loc);
935 static Expression GetOperatorTrueOrFalse (EmitContext ec, Expression e, bool is_true, Location loc)
937 MethodGroupExpr operator_group;
938 operator_group = MethodLookup (ec.ContainerType, e.Type, is_true ? "op_True" : "op_False", loc) as MethodGroupExpr;
939 if (operator_group == null)
942 ArrayList arguments = new ArrayList (1);
943 arguments.Add (new Argument (e, Argument.AType.Expression));
944 operator_group = operator_group.OverloadResolve (
945 ec, ref arguments, false, loc);
947 if (operator_group == null)
950 return new UserOperatorCall (operator_group, arguments, null, loc);
954 /// Resolves the expression `e' into a boolean expression: either through
955 /// an implicit conversion, or through an `operator true' invocation
957 public static Expression ResolveBoolean (EmitContext ec, Expression e, Location loc)
963 if (e.Type == TypeManager.bool_type)
966 Expression converted = Convert.ImplicitConversion (ec, e, TypeManager.bool_type, Location.Null);
968 if (converted != null)
972 // If no implicit conversion to bool exists, try using `operator true'
974 converted = Expression.GetOperatorTrue (ec, e, loc);
975 if (converted == null){
976 e.Error_ValueCannotBeConverted (ec, loc, TypeManager.bool_type, false);
982 public virtual string ExprClassName
986 case ExprClass.Invalid:
988 case ExprClass.Value:
990 case ExprClass.Variable:
992 case ExprClass.Namespace:
996 case ExprClass.MethodGroup:
997 return "method group";
998 case ExprClass.PropertyAccess:
999 return "property access";
1000 case ExprClass.EventAccess:
1001 return "event access";
1002 case ExprClass.IndexerAccess:
1003 return "indexer access";
1004 case ExprClass.Nothing:
1007 throw new Exception ("Should not happen");
1012 /// Reports that we were expecting `expr' to be of class `expected'
1014 public void Error_UnexpectedKind (DeclSpace ds, string expected, Location loc)
1016 Error_UnexpectedKind (ds, expected, ExprClassName, loc);
1019 public void Error_UnexpectedKind (DeclSpace ds, string expected, string was, Location loc)
1021 string name = GetSignatureForError ();
1023 name = ds.GetSignatureForError () + '.' + name;
1025 Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
1026 name, was, expected);
1029 public void Error_UnexpectedKind (ResolveFlags flags, Location loc)
1031 string [] valid = new string [4];
1034 if ((flags & ResolveFlags.VariableOrValue) != 0) {
1035 valid [count++] = "variable";
1036 valid [count++] = "value";
1039 if ((flags & ResolveFlags.Type) != 0)
1040 valid [count++] = "type";
1042 if ((flags & ResolveFlags.MethodGroup) != 0)
1043 valid [count++] = "method group";
1046 valid [count++] = "unknown";
1048 StringBuilder sb = new StringBuilder (valid [0]);
1049 for (int i = 1; i < count - 1; i++) {
1051 sb.Append (valid [i]);
1054 sb.Append ("' or `");
1055 sb.Append (valid [count - 1]);
1058 Report.Error (119, loc,
1059 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1062 public static void UnsafeError (Location loc)
1064 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1068 // Load the object from the pointer.
1070 public static void LoadFromPtr (ILGenerator ig, Type t)
1072 if (t == TypeManager.int32_type)
1073 ig.Emit (OpCodes.Ldind_I4);
1074 else if (t == TypeManager.uint32_type)
1075 ig.Emit (OpCodes.Ldind_U4);
1076 else if (t == TypeManager.short_type)
1077 ig.Emit (OpCodes.Ldind_I2);
1078 else if (t == TypeManager.ushort_type)
1079 ig.Emit (OpCodes.Ldind_U2);
1080 else if (t == TypeManager.char_type)
1081 ig.Emit (OpCodes.Ldind_U2);
1082 else if (t == TypeManager.byte_type)
1083 ig.Emit (OpCodes.Ldind_U1);
1084 else if (t == TypeManager.sbyte_type)
1085 ig.Emit (OpCodes.Ldind_I1);
1086 else if (t == TypeManager.uint64_type)
1087 ig.Emit (OpCodes.Ldind_I8);
1088 else if (t == TypeManager.int64_type)
1089 ig.Emit (OpCodes.Ldind_I8);
1090 else if (t == TypeManager.float_type)
1091 ig.Emit (OpCodes.Ldind_R4);
1092 else if (t == TypeManager.double_type)
1093 ig.Emit (OpCodes.Ldind_R8);
1094 else if (t == TypeManager.bool_type)
1095 ig.Emit (OpCodes.Ldind_I1);
1096 else if (t == TypeManager.intptr_type)
1097 ig.Emit (OpCodes.Ldind_I);
1098 else if (TypeManager.IsEnumType (t)) {
1099 if (t == TypeManager.enum_type)
1100 ig.Emit (OpCodes.Ldind_Ref);
1102 LoadFromPtr (ig, TypeManager.GetEnumUnderlyingType (t));
1103 } else if (t.IsValueType || TypeManager.IsGenericParameter (t))
1104 ig.Emit (OpCodes.Ldobj, t);
1105 else if (t.IsPointer)
1106 ig.Emit (OpCodes.Ldind_I);
1108 ig.Emit (OpCodes.Ldind_Ref);
1112 // The stack contains the pointer and the value of type `type'
1114 public static void StoreFromPtr (ILGenerator ig, Type type)
1116 if (TypeManager.IsEnumType (type))
1117 type = TypeManager.GetEnumUnderlyingType (type);
1118 if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
1119 ig.Emit (OpCodes.Stind_I4);
1120 else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
1121 ig.Emit (OpCodes.Stind_I8);
1122 else if (type == TypeManager.char_type || type == TypeManager.short_type ||
1123 type == TypeManager.ushort_type)
1124 ig.Emit (OpCodes.Stind_I2);
1125 else if (type == TypeManager.float_type)
1126 ig.Emit (OpCodes.Stind_R4);
1127 else if (type == TypeManager.double_type)
1128 ig.Emit (OpCodes.Stind_R8);
1129 else if (type == TypeManager.byte_type || type == TypeManager.sbyte_type ||
1130 type == TypeManager.bool_type)
1131 ig.Emit (OpCodes.Stind_I1);
1132 else if (type == TypeManager.intptr_type)
1133 ig.Emit (OpCodes.Stind_I);
1134 else if (type.IsValueType || TypeManager.IsGenericParameter (type))
1135 ig.Emit (OpCodes.Stobj, type);
1137 ig.Emit (OpCodes.Stind_Ref);
1141 // Returns the size of type `t' if known, otherwise, 0
1143 public static int GetTypeSize (Type t)
1145 t = TypeManager.TypeToCoreType (t);
1146 if (t == TypeManager.int32_type ||
1147 t == TypeManager.uint32_type ||
1148 t == TypeManager.float_type)
1150 else if (t == TypeManager.int64_type ||
1151 t == TypeManager.uint64_type ||
1152 t == TypeManager.double_type)
1154 else if (t == TypeManager.byte_type ||
1155 t == TypeManager.sbyte_type ||
1156 t == TypeManager.bool_type)
1158 else if (t == TypeManager.short_type ||
1159 t == TypeManager.char_type ||
1160 t == TypeManager.ushort_type)
1162 else if (t == TypeManager.decimal_type)
1168 protected void Error_CannotCallAbstractBase (string name)
1170 Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
1173 protected void Error_CannotModifyIntermediateExpressionValue (EmitContext ec)
1175 Report.SymbolRelatedToPreviousError (type);
1176 if (ec.CurrentInitializerVariable != null) {
1177 Report.Error (1918, loc, "Members of a value type property `{0}' cannot be assigned with an object initializer",
1178 GetSignatureForError ());
1180 Report.Error (1612, loc, "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
1181 GetSignatureForError ());
1186 // Converts `source' to an int, uint, long or ulong.
1188 public Expression ConvertExpressionToArrayIndex (EmitContext ec, Expression source)
1190 Expression converted;
1192 using (ec.With (EmitContext.Flags.CheckState, true)) {
1193 converted = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, source.loc);
1194 if (converted == null)
1195 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, source.loc);
1196 if (converted == null)
1197 converted = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, source.loc);
1198 if (converted == null)
1199 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, source.loc);
1201 if (converted == null) {
1202 source.Error_ValueCannotBeConverted (ec, source.loc, TypeManager.int32_type, false);
1208 // Only positive constants are allowed at compile time
1210 Constant c = converted as Constant;
1213 Error_NegativeArrayIndex (source.loc);
1218 return new ArrayIndexCast (converted).Resolve (ec);
1222 // Derived classes implement this method by cloning the fields that
1223 // could become altered during the Resolve stage
1225 // Only expressions that are created for the parser need to implement
1228 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1230 throw new NotImplementedException (
1232 "CloneTo not implemented for expression {0}", this.GetType ()));
1236 // Clones an expression created by the parser.
1238 // We only support expressions created by the parser so far, not
1239 // expressions that have been resolved (many more classes would need
1240 // to implement CloneTo).
1242 // This infrastructure is here merely for Lambda expressions which
1243 // compile the same code using different type values for the same
1244 // arguments to find the correct overload
1246 public Expression Clone (CloneContext clonectx)
1248 Expression cloned = (Expression) MemberwiseClone ();
1249 CloneTo (clonectx, cloned);
1254 public virtual Expression CreateExpressionTree (EmitContext ec)
1256 throw new NotImplementedException (
1257 "Expression tree conversion not implemented for " + GetType ());
1260 protected Expression CreateExpressionFactoryCall (string name, ArrayList args)
1262 return CreateExpressionFactoryCall (name, null, args, loc);
1265 protected Expression CreateExpressionFactoryCall (string name, TypeArguments typeArguments, ArrayList args)
1267 return CreateExpressionFactoryCall (name, typeArguments, args, loc);
1270 public static Expression CreateExpressionFactoryCall (string name, TypeArguments typeArguments, ArrayList args, Location loc)
1272 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (loc), name, typeArguments, loc), args);
1275 protected static TypeExpr CreateExpressionTypeExpression (Location loc)
1277 TypeExpr texpr = TypeManager.expression_type_expr;
1278 if (texpr == null) {
1279 Type t = TypeManager.CoreLookupType ("System.Linq.Expressions", "Expression", Kind.Class, true);
1283 TypeManager.expression_type_expr = texpr = new TypeExpression (t, Location.Null);
1291 /// This is just a base class for expressions that can
1292 /// appear on statements (invocations, object creation,
1293 /// assignments, post/pre increment and decrement). The idea
1294 /// being that they would support an extra Emition interface that
1295 /// does not leave a result on the stack.
1297 public abstract class ExpressionStatement : Expression {
1299 public virtual ExpressionStatement ResolveStatement (EmitContext ec)
1301 Expression e = Resolve (ec);
1305 ExpressionStatement es = e as ExpressionStatement;
1307 Error_InvalidExpressionStatement ();
1313 /// Requests the expression to be emitted in a `statement'
1314 /// context. This means that no new value is left on the
1315 /// stack after invoking this method (constrasted with
1316 /// Emit that will always leave a value on the stack).
1318 public abstract void EmitStatement (EmitContext ec);
1320 public override void EmitSideEffect (EmitContext ec)
1327 /// This kind of cast is used to encapsulate the child
1328 /// whose type is child.Type into an expression that is
1329 /// reported to return "return_type". This is used to encapsulate
1330 /// expressions which have compatible types, but need to be dealt
1331 /// at higher levels with.
1333 /// For example, a "byte" expression could be encapsulated in one
1334 /// of these as an "unsigned int". The type for the expression
1335 /// would be "unsigned int".
1338 public abstract class TypeCast : Expression
1340 protected Expression child;
1342 protected TypeCast (Expression child, Type return_type)
1344 eclass = child.eclass;
1345 loc = child.Location;
1350 public override Expression CreateExpressionTree (EmitContext ec)
1352 ArrayList args = new ArrayList (2);
1353 args.Add (new Argument (child.CreateExpressionTree (ec)));
1354 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1355 return CreateExpressionFactoryCall (ec.CheckState ? "ConvertChecked" : "Convert", args);
1358 public override Expression DoResolve (EmitContext ec)
1360 // This should never be invoked, we are born in fully
1361 // initialized state.
1366 public override void Emit (EmitContext ec)
1371 public override bool GetAttributableValue (Type value_type, out object value)
1373 return child.GetAttributableValue (value_type, out value);
1376 protected override void CloneTo (CloneContext clonectx, Expression t)
1378 TypeCast target = (TypeCast) t;
1380 target.child = child.Clone (clonectx);
1383 public override bool IsNull {
1385 return child.IsNull;
1390 public class EmptyCast : TypeCast {
1393 EmptyCast (Expression child, Type target_type)
1394 : base (child, target_type)
1399 // HACK: This is just temporary hack before real EmptyCast clean-up required by expression trees
1401 public static Expression Create (Expression child, Type type, bool is_implicit)
1403 EmptyCast e = new EmptyCast (child, type);
1404 e.is_implicit = true;
1408 public static Expression Create (Expression child, Type type)
1410 Constant c = child as Constant;
1412 return new EmptyConstantCast (c, type);
1414 return new EmptyCast (child, type);
1417 public override Expression CreateExpressionTree (EmitContext ec)
1420 return child.CreateExpressionTree (ec);
1422 return base.CreateExpressionTree (ec);
1425 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1427 child.EmitBranchable (ec, label, on_true);
1430 public override void EmitSideEffect (EmitContext ec)
1432 child.EmitSideEffect (ec);
1438 /// Performs a cast using an operator (op_Explicit or op_Implicit)
1440 public class OperatorCast : TypeCast {
1441 MethodInfo conversion_operator;
1444 public OperatorCast (Expression child, Type target_type) : this (child, target_type, false) {}
1446 public OperatorCast (Expression child, Type target_type, bool find_explicit)
1447 : base (child, target_type)
1449 this.find_explicit = find_explicit;
1452 // Returns the implicit operator that converts from
1453 // 'child.Type' to our target type (type)
1454 MethodInfo GetConversionOperator (bool find_explicit)
1456 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1460 mi = TypeManager.MemberLookup (child.Type, child.Type, child.Type, MemberTypes.Method,
1461 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1464 mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1465 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1468 foreach (MethodInfo oper in mi) {
1469 ParameterData pd = TypeManager.GetParameterData (oper);
1471 if (pd.ParameterType (0) == child.Type && TypeManager.TypeToCoreType (oper.ReturnType) == type)
1479 public override void Emit (EmitContext ec)
1481 ILGenerator ig = ec.ig;
1484 conversion_operator = GetConversionOperator (find_explicit);
1486 if (conversion_operator == null)
1487 throw new InternalErrorException ("Outer conversion routine is out of sync");
1489 ig.Emit (OpCodes.Call, conversion_operator);
1495 /// This is a numeric cast to a Decimal
1497 public class CastToDecimal : TypeCast {
1498 MethodInfo conversion_operator;
1500 public CastToDecimal (Expression child)
1501 : this (child, false)
1505 public CastToDecimal (Expression child, bool find_explicit)
1506 : base (child, TypeManager.decimal_type)
1508 conversion_operator = GetConversionOperator (find_explicit);
1510 if (conversion_operator == null)
1511 throw new InternalErrorException ("Outer conversion routine is out of sync");
1514 // Returns the implicit operator that converts from
1515 // 'child.Type' to System.Decimal.
1516 MethodInfo GetConversionOperator (bool find_explicit)
1518 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1520 MemberInfo [] mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1521 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1523 foreach (MethodInfo oper in mi) {
1524 ParameterData pd = TypeManager.GetParameterData (oper);
1526 if (pd.ParameterType (0) == child.Type && TypeManager.TypeToCoreType (oper.ReturnType) == type)
1532 public override void Emit (EmitContext ec)
1534 ILGenerator ig = ec.ig;
1537 ig.Emit (OpCodes.Call, conversion_operator);
1542 /// This is an explicit numeric cast from a Decimal
1544 public class CastFromDecimal : TypeCast
1546 static IDictionary operators;
1548 public CastFromDecimal (Expression child, Type return_type)
1549 : base (child, return_type)
1551 if (child.Type != TypeManager.decimal_type)
1552 throw new InternalErrorException (
1553 "The expected type is Decimal, instead it is " + child.Type.FullName);
1556 // Returns the explicit operator that converts from an
1557 // express of type System.Decimal to 'type'.
1558 public Expression Resolve ()
1560 if (operators == null) {
1561 MemberInfo[] all_oper = TypeManager.MemberLookup (TypeManager.decimal_type,
1562 TypeManager.decimal_type, TypeManager.decimal_type, MemberTypes.Method,
1563 BindingFlags.Static | BindingFlags.Public, "op_Explicit", null);
1565 operators = new System.Collections.Specialized.HybridDictionary ();
1566 foreach (MethodInfo oper in all_oper) {
1567 ParameterData pd = TypeManager.GetParameterData (oper);
1568 if (pd.ParameterType (0) == TypeManager.decimal_type)
1569 operators.Add (TypeManager.TypeToCoreType (oper.ReturnType), oper);
1573 return operators.Contains (type) ? this : null;
1576 public override void Emit (EmitContext ec)
1578 ILGenerator ig = ec.ig;
1581 ig.Emit (OpCodes.Call, (MethodInfo)operators [type]);
1587 // Constant specialization of EmptyCast.
1588 // We need to special case this since an empty cast of
1589 // a constant is still a constant.
1591 public class EmptyConstantCast : Constant
1593 public readonly Constant child;
1595 public EmptyConstantCast(Constant child, Type type)
1596 : base (child.Location)
1598 eclass = child.eclass;
1603 public override string AsString ()
1605 return child.AsString ();
1608 public override object GetValue ()
1610 return child.GetValue ();
1613 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
1615 // FIXME: check that 'type' can be converted to 'target_type' first
1616 return child.ConvertExplicitly (in_checked_context, target_type);
1619 public override Expression CreateExpressionTree (EmitContext ec)
1621 ArrayList args = new ArrayList (2);
1622 args.Add (new Argument (child.CreateExpressionTree (ec)));
1623 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1624 return CreateExpressionFactoryCall ("Convert", args);
1627 public override Constant Increment ()
1629 return child.Increment ();
1632 public override bool IsDefaultValue {
1633 get { return child.IsDefaultValue; }
1636 public override bool IsNegative {
1637 get { return child.IsNegative; }
1640 public override bool IsNull {
1641 get { return child.IsNull; }
1644 public override bool IsZeroInteger {
1645 get { return child.IsZeroInteger; }
1648 public override void Emit (EmitContext ec)
1653 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1655 child.EmitBranchable (ec, label, on_true);
1658 public override void EmitSideEffect (EmitContext ec)
1660 child.EmitSideEffect (ec);
1663 public override Constant ConvertImplicitly (Type target_type)
1665 // FIXME: Do we need to check user conversions?
1666 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1668 return child.ConvertImplicitly (target_type);
1674 /// This class is used to wrap literals which belong inside Enums
1676 public class EnumConstant : Constant {
1677 public Constant Child;
1679 public EnumConstant (Constant child, Type enum_type):
1680 base (child.Location)
1682 eclass = child.eclass;
1687 public override Expression DoResolve (EmitContext ec)
1689 // This should never be invoked, we are born in fully
1690 // initialized state.
1695 public override void Emit (EmitContext ec)
1700 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1702 Child.EmitBranchable (ec, label, on_true);
1705 public override void EmitSideEffect (EmitContext ec)
1707 Child.EmitSideEffect (ec);
1710 public override bool GetAttributableValue (Type value_type, out object value)
1712 value = GetTypedValue ();
1716 public override string GetSignatureForError()
1718 return TypeManager.CSharpName (Type);
1721 public override object GetValue ()
1723 return Child.GetValue ();
1726 public override object GetTypedValue ()
1728 // FIXME: runtime is not ready to work with just emited enums
1729 if (!RootContext.StdLib) {
1730 return Child.GetValue ();
1733 return System.Enum.ToObject (type, Child.GetValue ());
1736 public override string AsString ()
1738 return TypeManager.CSharpEnumValue (type, Child.GetValue ());
1741 public override Constant Increment()
1743 return new EnumConstant (Child.Increment (), type);
1746 public override bool IsDefaultValue {
1748 return Child.IsDefaultValue;
1752 public override bool IsZeroInteger {
1753 get { return Child.IsZeroInteger; }
1756 public override bool IsNegative {
1758 return Child.IsNegative;
1762 public override Constant ConvertExplicitly(bool in_checked_context, Type target_type)
1764 if (Child.Type == target_type)
1767 return Child.ConvertExplicitly (in_checked_context, target_type);
1770 public override Constant ConvertImplicitly (Type type)
1772 Type this_type = TypeManager.DropGenericTypeArguments (Type);
1773 type = TypeManager.DropGenericTypeArguments (type);
1775 if (this_type == type) {
1776 // This is workaround of mono bug. It can be removed when the latest corlib spreads enough
1777 if (TypeManager.IsEnumType (type.UnderlyingSystemType))
1780 Type child_type = TypeManager.DropGenericTypeArguments (Child.Type);
1781 if (type.UnderlyingSystemType != child_type)
1782 Child = Child.ConvertImplicitly (type.UnderlyingSystemType);
1786 if (!Convert.ImplicitStandardConversionExists (this, type)){
1790 return Child.ConvertImplicitly(type);
1796 /// This kind of cast is used to encapsulate Value Types in objects.
1798 /// The effect of it is to box the value type emitted by the previous
1801 public class BoxedCast : TypeCast {
1803 public BoxedCast (Expression expr, Type target_type)
1804 : base (expr, target_type)
1806 eclass = ExprClass.Value;
1809 public override Expression DoResolve (EmitContext ec)
1811 // This should never be invoked, we are born in fully
1812 // initialized state.
1817 public override void Emit (EmitContext ec)
1821 ec.ig.Emit (OpCodes.Box, child.Type);
1824 public override void EmitSideEffect (EmitContext ec)
1826 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1827 // so, we need to emit the box+pop instructions in most cases
1828 if (child.Type.IsValueType &&
1829 (type == TypeManager.object_type || type == TypeManager.value_type))
1830 child.EmitSideEffect (ec);
1832 base.EmitSideEffect (ec);
1836 public class UnboxCast : TypeCast {
1837 public UnboxCast (Expression expr, Type return_type)
1838 : base (expr, return_type)
1842 public override Expression DoResolve (EmitContext ec)
1844 // This should never be invoked, we are born in fully
1845 // initialized state.
1850 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1852 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
1853 Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
1854 return base.DoResolveLValue (ec, right_side);
1857 public override void Emit (EmitContext ec)
1860 ILGenerator ig = ec.ig;
1864 if (t.IsGenericParameter || t.IsGenericType && t.IsValueType)
1865 ig.Emit (OpCodes.Unbox_Any, t);
1869 ig.Emit (OpCodes.Unbox, t);
1871 LoadFromPtr (ig, t);
1877 /// This is used to perform explicit numeric conversions.
1879 /// Explicit numeric conversions might trigger exceptions in a checked
1880 /// context, so they should generate the conv.ovf opcodes instead of
1883 public class ConvCast : TypeCast {
1884 public enum Mode : byte {
1885 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1887 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1888 U2_I1, U2_U1, U2_I2, U2_CH,
1889 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1890 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1891 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH,
1892 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH,
1893 CH_I1, CH_U1, CH_I2,
1894 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1895 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4
1900 public ConvCast (Expression child, Type return_type, Mode m)
1901 : base (child, return_type)
1906 public override Expression DoResolve (EmitContext ec)
1908 // This should never be invoked, we are born in fully
1909 // initialized state.
1914 public override string ToString ()
1916 return String.Format ("ConvCast ({0}, {1})", mode, child);
1919 public override void Emit (EmitContext ec)
1921 ILGenerator ig = ec.ig;
1927 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1928 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1929 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1930 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1931 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1933 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1934 case Mode.U1_CH: /* nothing */ break;
1936 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1937 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1938 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1939 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1940 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1941 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1943 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1944 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1945 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1946 case Mode.U2_CH: /* nothing */ break;
1948 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1949 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1950 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1951 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1952 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1953 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1954 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1956 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1957 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1958 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1959 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1960 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1961 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1963 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1964 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1965 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1966 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1967 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1968 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1969 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1970 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1972 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1973 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1974 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1975 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1976 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1977 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1978 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1979 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1981 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1982 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1983 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1985 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1986 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1987 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1988 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1989 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1990 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1991 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1992 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1993 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1995 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1996 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1997 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1998 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1999 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
2000 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
2001 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
2002 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
2003 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
2004 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
2008 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
2009 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
2010 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
2011 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
2012 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
2014 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
2015 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
2017 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
2018 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
2019 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
2020 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
2021 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
2022 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
2024 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
2025 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
2026 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
2027 case Mode.U2_CH: /* nothing */ break;
2029 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
2030 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
2031 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
2032 case Mode.I4_U4: /* nothing */ break;
2033 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
2034 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
2035 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
2037 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
2038 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
2039 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
2040 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
2041 case Mode.U4_I4: /* nothing */ break;
2042 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
2044 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
2045 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
2046 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
2047 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
2048 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
2049 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
2050 case Mode.I8_U8: /* nothing */ break;
2051 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
2053 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
2054 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
2055 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
2056 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
2057 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
2058 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
2059 case Mode.U8_I8: /* nothing */ break;
2060 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
2062 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
2063 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
2064 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
2066 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
2067 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
2068 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
2069 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
2070 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
2071 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
2072 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
2073 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
2074 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
2076 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
2077 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
2078 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
2079 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
2080 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
2081 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
2082 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
2083 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
2084 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
2085 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
2091 public class OpcodeCast : TypeCast {
2095 public OpcodeCast (Expression child, Type return_type, OpCode op)
2096 : base (child, return_type)
2100 second_valid = false;
2103 public OpcodeCast (Expression child, Type return_type, OpCode op, OpCode op2)
2104 : base (child, return_type)
2109 second_valid = true;
2112 public override Expression DoResolve (EmitContext ec)
2114 // This should never be invoked, we are born in fully
2115 // initialized state.
2120 public override void Emit (EmitContext ec)
2129 public Type UnderlyingType {
2130 get { return child.Type; }
2135 /// This kind of cast is used to encapsulate a child and cast it
2136 /// to the class requested
2138 public class ClassCast : TypeCast {
2139 public ClassCast (Expression child, Type return_type)
2140 : base (child, return_type)
2145 public override Expression DoResolve (EmitContext ec)
2147 // This should never be invoked, we are born in fully
2148 // initialized state.
2153 public override void Emit (EmitContext ec)
2157 if (TypeManager.IsGenericParameter (child.Type))
2158 ec.ig.Emit (OpCodes.Box, child.Type);
2161 if (type.IsGenericParameter)
2162 ec.ig.Emit (OpCodes.Unbox_Any, type);
2165 ec.ig.Emit (OpCodes.Castclass, type);
2170 // Used when resolved expression has different representations for
2171 // expression trees and emit phase
2173 public class ReducedExpression : Expression
2175 class ReducedConstantExpression : Constant
2177 readonly Constant expr;
2178 readonly Expression orig_expr;
2180 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2181 : base (expr.Location)
2184 this.orig_expr = orig_expr;
2185 eclass = expr.eclass;
2189 public override string AsString ()
2191 return expr.AsString ();
2194 public override Expression CreateExpressionTree (EmitContext ec)
2196 return orig_expr.CreateExpressionTree (ec);
2199 public override object GetValue ()
2201 return expr.GetValue ();
2204 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
2206 throw new NotImplementedException ();
2209 public override Expression DoResolve (EmitContext ec)
2214 public override Constant Increment ()
2216 throw new NotImplementedException ();
2219 public override bool IsDefaultValue {
2221 return expr.IsDefaultValue;
2225 public override bool IsNegative {
2227 return expr.IsNegative;
2231 public override void Emit (EmitContext ec)
2237 readonly Expression expr, orig_expr;
2239 private ReducedExpression (Expression expr, Expression orig_expr)
2242 this.orig_expr = orig_expr;
2243 this.loc = orig_expr.Location;
2246 public static Expression Create (Constant expr, Expression original_expr)
2248 return new ReducedConstantExpression (expr, original_expr);
2251 public static Expression Create (Expression expr, Expression original_expr)
2253 Constant c = expr as Constant;
2255 return Create (c, original_expr);
2257 return new ReducedExpression (expr, original_expr);
2260 public override Expression CreateExpressionTree (EmitContext ec)
2262 return orig_expr.CreateExpressionTree (ec);
2265 public override Expression DoResolve (EmitContext ec)
2267 eclass = expr.eclass;
2272 public override void Emit (EmitContext ec)
2277 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2279 expr.EmitBranchable (ec, target, on_true);
2284 // Unresolved type name expressions
2286 public abstract class ATypeNameExpression : FullNamedExpression
2288 public readonly string Name;
2289 protected TypeArguments targs;
2291 protected ATypeNameExpression (string name, Location l)
2297 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2304 public bool HasTypeArguments {
2306 return targs != null;
2310 public override string GetSignatureForError ()
2312 if (targs != null) {
2313 return TypeManager.RemoveGenericArity (Name) + "<" +
2314 targs.GetSignatureForError () + ">";
2322 /// SimpleName expressions are formed of a single word and only happen at the beginning
2323 /// of a dotted-name.
2325 public class SimpleName : ATypeNameExpression {
2328 public SimpleName (string name, Location l)
2333 public SimpleName (string name, TypeArguments args, Location l)
2334 : base (name, args, l)
2338 public SimpleName (string name, TypeParameter[] type_params, Location l)
2341 targs = new TypeArguments (l);
2342 foreach (TypeParameter type_param in type_params)
2343 targs.Add (new TypeParameterExpr (type_param, l));
2346 public static string RemoveGenericArity (string name)
2349 StringBuilder sb = null;
2351 int pos = name.IndexOf ('`', start);
2356 sb.Append (name.Substring (start));
2361 sb = new StringBuilder ();
2362 sb.Append (name.Substring (start, pos-start));
2365 while ((pos < name.Length) && Char.IsNumber (name [pos]))
2369 } while (start < name.Length);
2371 return sb.ToString ();
2374 public SimpleName GetMethodGroup ()
2376 return new SimpleName (RemoveGenericArity (Name), targs, loc);
2379 public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
2381 if (ec.IsInFieldInitializer)
2382 Report.Error (236, l,
2383 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2387 120, l, "`{0}': An object reference is required for the nonstatic field, method or property",
2391 public bool IdenticalNameAndTypeName (EmitContext ec, Expression resolved_to, Location loc)
2393 return resolved_to != null && resolved_to.Type != null &&
2394 resolved_to.Type.Name == Name &&
2395 (ec.DeclContainer.LookupNamespaceOrType (Name, loc, /* ignore_cs0104 = */ true) != null);
2398 public override Expression DoResolve (EmitContext ec)
2400 return SimpleNameResolve (ec, null, false);
2403 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
2405 return SimpleNameResolve (ec, right_side, false);
2409 public Expression DoResolve (EmitContext ec, bool intermediate)
2411 return SimpleNameResolve (ec, null, intermediate);
2414 static bool IsNestedChild (Type t, Type parent)
2416 while (parent != null) {
2417 if (TypeManager.IsNestedChildOf (t, TypeManager.DropGenericTypeArguments (parent)))
2420 parent = parent.BaseType;
2426 FullNamedExpression ResolveNested (IResolveContext ec, Type t)
2428 if (!TypeManager.IsGenericTypeDefinition (t) && !TypeManager.IsGenericType (t))
2431 DeclSpace ds = ec.DeclContainer;
2432 while (ds != null && !IsNestedChild (t, ds.TypeBuilder))
2438 Type[] gen_params = TypeManager.GetTypeArguments (t);
2440 int arg_count = targs != null ? targs.Count : 0;
2442 for (; (ds != null) && ds.IsGeneric; ds = ds.Parent) {
2443 if (arg_count + ds.CountTypeParameters == gen_params.Length) {
2444 TypeArguments new_args = new TypeArguments (loc);
2445 foreach (TypeParameter param in ds.TypeParameters)
2446 new_args.Add (new TypeParameterExpr (param, loc));
2449 new_args.Add (targs);
2451 return new ConstructedType (t, new_args, loc);
2458 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2460 FullNamedExpression fne = ec.GenericDeclContainer.LookupGeneric (Name, loc);
2462 return fne.ResolveAsTypeStep (ec, silent);
2464 int errors = Report.Errors;
2465 fne = ec.DeclContainer.LookupNamespaceOrType (Name, loc, /*ignore_cs0104=*/ false);
2468 if (fne.Type == null)
2471 FullNamedExpression nested = ResolveNested (ec, fne.Type);
2473 return nested.ResolveAsTypeStep (ec, false);
2475 if (targs != null) {
2476 ConstructedType ct = new ConstructedType (fne, targs, loc);
2477 return ct.ResolveAsTypeStep (ec, false);
2483 if (silent || errors != Report.Errors)
2486 Error_TypeOrNamespaceNotFound (ec);
2490 protected virtual void Error_TypeOrNamespaceNotFound (IResolveContext ec)
2492 MemberCore mc = ec.DeclContainer.GetDefinition (Name);
2494 Error_UnexpectedKind (ec.DeclContainer, "type", GetMemberType (mc), loc);
2498 string ns = ec.DeclContainer.NamespaceEntry.NS.Name;
2499 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2500 foreach (Assembly a in RootNamespace.Global.Assemblies) {
2501 Type type = a.GetType (fullname);
2503 Report.SymbolRelatedToPreviousError (type);
2504 Expression.ErrorIsInaccesible (loc, TypeManager.CSharpName (type));
2509 Type t = ec.DeclContainer.LookupAnyGeneric (Name);
2511 Namespace.Error_InvalidNumberOfTypeArguments (t, loc);
2515 if (targs != null) {
2516 FullNamedExpression retval = ec.DeclContainer.LookupNamespaceOrType (SimpleName.RemoveGenericArity (Name), loc, true);
2517 if (retval != null) {
2518 Namespace.Error_TypeArgumentsCannotBeUsed (retval.Type, loc);
2523 NamespaceEntry.Error_NamespaceNotFound (loc, Name);
2526 // TODO: I am still not convinced about this. If someone else will need it
2527 // implement this as virtual property in MemberCore hierarchy
2528 public static string GetMemberType (MemberCore mc)
2534 if (mc is FieldBase)
2536 if (mc is MethodCore)
2538 if (mc is EnumMember)
2546 Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2552 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2558 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2565 /// 7.5.2: Simple Names.
2567 /// Local Variables and Parameters are handled at
2568 /// parse time, so they never occur as SimpleNames.
2570 /// The `intermediate' flag is used by MemberAccess only
2571 /// and it is used to inform us that it is ok for us to
2572 /// avoid the static check, because MemberAccess might end
2573 /// up resolving the Name as a Type name and the access as
2574 /// a static type access.
2576 /// ie: Type Type; .... { Type.GetType (""); }
2578 /// Type is both an instance variable and a Type; Type.GetType
2579 /// is the static method not an instance method of type.
2581 Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2583 Expression e = null;
2586 // Stage 1: Performed by the parser (binding to locals or parameters).
2588 Block current_block = ec.CurrentBlock;
2589 if (current_block != null){
2590 LocalInfo vi = current_block.GetLocalInfo (Name);
2592 if (targs != null) {
2593 Report.Error (307, loc,
2594 "The variable `{0}' cannot be used with type arguments",
2599 LocalVariableReference var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2600 if (right_side != null) {
2601 return var.ResolveLValue (ec, right_side, loc);
2603 ResolveFlags rf = ResolveFlags.VariableOrValue;
2605 rf |= ResolveFlags.DisableFlowAnalysis;
2606 return var.Resolve (ec, rf);
2610 ParameterReference pref = current_block.Toplevel.GetParameterReference (Name, loc);
2612 if (targs != null) {
2613 Report.Error (307, loc,
2614 "The variable `{0}' cannot be used with type arguments",
2619 if (right_side != null)
2620 return pref.ResolveLValue (ec, right_side, loc);
2622 return pref.Resolve (ec);
2625 Expression expr = current_block.Toplevel.GetTransparentIdentifier (Name);
2627 if (right_side != null)
2628 return expr.ResolveLValue (ec, right_side, loc);
2629 return expr.Resolve (ec);
2634 // Stage 2: Lookup members
2637 Type almost_matched_type = null;
2638 ArrayList almost_matched = null;
2639 for (DeclSpace lookup_ds = ec.DeclContainer; lookup_ds != null; lookup_ds = lookup_ds.Parent) {
2640 // either RootDeclSpace or GenericMethod
2641 if (lookup_ds.TypeBuilder == null)
2644 e = MemberLookup (ec.ContainerType, lookup_ds.TypeBuilder, Name, loc);
2646 if (e is PropertyExpr) {
2647 // since TypeManager.MemberLookup doesn't know if we're doing a lvalue access or not,
2648 // it doesn't know which accessor to check permissions against
2649 if (((PropertyExpr) e).IsAccessibleFrom (ec.ContainerType, right_side != null))
2651 } else if (e is EventExpr) {
2652 if (((EventExpr) e).IsAccessibleFrom (ec.ContainerType))
2660 if (almost_matched == null && almost_matched_members.Count > 0) {
2661 almost_matched_type = lookup_ds.TypeBuilder;
2662 almost_matched = (ArrayList) almost_matched_members.Clone ();
2667 if (almost_matched == null && almost_matched_members.Count > 0) {
2668 almost_matched_type = ec.ContainerType;
2669 almost_matched = (ArrayList) almost_matched_members.Clone ();
2671 e = ResolveAsTypeStep (ec, true);
2675 if (current_block != null) {
2676 IKnownVariable ikv = current_block.Explicit.GetKnownVariable (Name);
2678 LocalInfo li = ikv as LocalInfo;
2679 // Supress CS0219 warning
2683 Error_VariableIsUsedBeforeItIsDeclared (Name);
2688 if (almost_matched != null)
2689 almost_matched_members = almost_matched;
2690 if (almost_matched_type == null)
2691 almost_matched_type = ec.ContainerType;
2692 Error_MemberLookupFailed (ec.ContainerType, null, almost_matched_type, Name,
2693 ec.DeclContainer.Name, AllMemberTypes, AllBindingFlags);
2697 if (e is TypeExpr) {
2701 ConstructedType ct = new ConstructedType (
2702 e.Type, targs, loc);
2703 return ct.ResolveAsTypeStep (ec, false);
2706 if (e is MemberExpr) {
2707 MemberExpr me = (MemberExpr) e;
2710 if (me.IsInstance) {
2711 if (ec.IsStatic || ec.IsInFieldInitializer) {
2713 // Note that an MemberExpr can be both IsInstance and IsStatic.
2714 // An unresolved MethodGroupExpr can contain both kinds of methods
2715 // and each predicate is true if the MethodGroupExpr contains
2716 // at least one of that kind of method.
2720 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2721 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2726 // Pass the buck to MemberAccess and Invocation.
2728 left = EmptyExpression.Null;
2730 left = ec.GetThis (loc);
2733 left = new TypeExpression (ec.ContainerType, loc);
2736 me = me.ResolveMemberAccess (ec, left, loc, null);
2740 if (targs != null) {
2742 me.SetTypeArguments (targs);
2745 if (!me.IsStatic && (me.InstanceExpression != null) &&
2746 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2747 me.InstanceExpression.Type != me.DeclaringType &&
2748 !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2749 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2750 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2751 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2755 return (right_side != null)
2756 ? me.DoResolveLValue (ec, right_side)
2757 : me.DoResolve (ec);
2763 protected override void CloneTo (CloneContext clonectx, Expression target)
2765 // CloneTo: Nothing, we do not keep any state on this expression
2770 /// Represents a namespace or a type. The name of the class was inspired by
2771 /// section 10.8.1 (Fully Qualified Names).
2773 public abstract class FullNamedExpression : Expression {
2774 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2779 public override void Emit (EmitContext ec)
2781 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2782 GetSignatureForError ());
2787 /// Expression that evaluates to a type
2789 public abstract class TypeExpr : FullNamedExpression {
2790 override public FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2792 TypeExpr t = DoResolveAsTypeStep (ec);
2796 eclass = ExprClass.Type;
2800 override public Expression DoResolve (EmitContext ec)
2802 return ResolveAsTypeTerminal (ec, false);
2805 public virtual bool CheckAccessLevel (DeclSpace ds)
2807 return ds.CheckAccessLevel (Type);
2810 public virtual bool AsAccessible (DeclSpace ds)
2812 return ds.IsAccessibleAs (Type);
2815 public virtual bool IsClass {
2816 get { return Type.IsClass; }
2819 public virtual bool IsValueType {
2820 get { return Type.IsValueType; }
2823 public virtual bool IsInterface {
2824 get { return Type.IsInterface; }
2827 public virtual bool IsSealed {
2828 get { return Type.IsSealed; }
2831 public virtual bool CanInheritFrom ()
2833 if (Type == TypeManager.enum_type ||
2834 (Type == TypeManager.value_type && RootContext.StdLib) ||
2835 Type == TypeManager.multicast_delegate_type ||
2836 Type == TypeManager.delegate_type ||
2837 Type == TypeManager.array_type)
2843 protected abstract TypeExpr DoResolveAsTypeStep (IResolveContext ec);
2845 public override bool Equals (object obj)
2847 TypeExpr tobj = obj as TypeExpr;
2851 return Type == tobj.Type;
2854 public override int GetHashCode ()
2856 return Type.GetHashCode ();
2861 /// Fully resolved Expression that already evaluated to a type
2863 public class TypeExpression : TypeExpr {
2864 public TypeExpression (Type t, Location l)
2867 eclass = ExprClass.Type;
2871 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2876 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2883 /// Used to create types from a fully qualified name. These are just used
2884 /// by the parser to setup the core types. A TypeLookupExpression is always
2885 /// classified as a type.
2887 public sealed class TypeLookupExpression : TypeExpr {
2888 readonly string name;
2890 public TypeLookupExpression (string name)
2893 eclass = ExprClass.Type;
2896 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2898 // It's null for corlib compilation only
2900 return DoResolveAsTypeStep (ec);
2905 private class UnexpectedType
2909 // This performes recursive type lookup, providing support for generic types.
2910 // For example, given the type:
2912 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]]
2914 // The types will be checked in the following order:
2917 // System.Collections |
2918 // System.Collections.Generic |
2920 // System | recursive call 1 |
2921 // System.Int32 _| | main method call
2923 // System | recursive call 2 |
2924 // System.String _| |
2926 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]] _|
2928 private Type TypeLookup (IResolveContext ec, string name)
2933 FullNamedExpression resolved = null;
2935 Type recursive_type = null;
2936 while (index < name.Length) {
2937 if (name[index] == '[') {
2942 if (name[index] == '[')
2944 else if (name[index] == ']')
2946 } while (braces > 0);
2947 recursive_type = TypeLookup (ec, name.Substring (open + 1, index - open - 1));
2948 if (recursive_type == null || (recursive_type == typeof(UnexpectedType)))
2949 return recursive_type;
2952 if (name[index] == ',')
2954 else if ((name[index] == '.' && !done) || (index == name.Length && name[0] != '[')) {
2955 string substring = name.Substring(dot, index - dot);
2957 if (resolved == null)
2958 resolved = RootNamespace.Global.Lookup (ec.DeclContainer, substring, Location.Null);
2959 else if (resolved is Namespace)
2960 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
2961 else if (type != null)
2962 type = TypeManager.GetNestedType (type, substring);
2966 if (resolved == null)
2968 else if (type == null && resolved is TypeExpr)
2969 type = resolved.Type;
2976 if (name[0] != '[') {
2977 string substring = name.Substring(dot, index - dot);
2980 return TypeManager.GetNestedType (type, substring);
2982 if (resolved != null) {
2983 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
2984 if (resolved is TypeExpr)
2985 return resolved.Type;
2987 if (resolved == null)
2990 resolved.Error_UnexpectedKind (ec.DeclContainer, "type", loc);
2991 return typeof (UnexpectedType);
2997 return recursive_type;
3000 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
3002 Type t = TypeLookup (ec, name);
3004 NamespaceEntry.Error_NamespaceNotFound (loc, name);
3007 if (t == typeof(UnexpectedType))
3013 protected override void CloneTo (CloneContext clonectx, Expression target)
3015 // CloneTo: Nothing, we do not keep any state on this expression
3018 public override string GetSignatureForError ()
3021 return TypeManager.CSharpName (name);
3023 return base.GetSignatureForError ();
3028 /// Represents an "unbound generic type", ie. typeof (Foo<>).
3031 public class UnboundTypeExpression : TypeExpr
3035 public UnboundTypeExpression (MemberName name, Location l)
3041 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
3044 if (name.Left != null) {
3045 Expression lexpr = name.Left.GetTypeExpression ();
3046 expr = new MemberAccess (lexpr, name.Basename);
3048 expr = new SimpleName (name.Basename, loc);
3051 FullNamedExpression fne = expr.ResolveAsTypeStep (ec, false);
3056 return new TypeExpression (type, loc);
3061 /// This class denotes an expression which evaluates to a member
3062 /// of a struct or a class.
3064 public abstract class MemberExpr : Expression
3066 protected bool is_base;
3069 /// The name of this member.
3071 public abstract string Name {
3076 // When base.member is used
3078 public bool IsBase {
3079 get { return is_base; }
3080 set { is_base = value; }
3084 /// Whether this is an instance member.
3086 public abstract bool IsInstance {
3091 /// Whether this is a static member.
3093 public abstract bool IsStatic {
3098 /// The type which declares this member.
3100 public abstract Type DeclaringType {
3105 /// The instance expression associated with this member, if it's a
3106 /// non-static member.
3108 public Expression InstanceExpression;
3110 public static void error176 (Location loc, string name)
3112 Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
3113 "with an instance reference, qualify it with a type name instead", name);
3116 // TODO: possible optimalization
3117 // Cache resolved constant result in FieldBuilder <-> expression map
3118 public virtual MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3119 SimpleName original)
3123 // original == null || original.Resolve (...) ==> left
3126 if (left is TypeExpr) {
3127 left = left.ResolveAsTypeTerminal (ec, true);
3132 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3140 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3143 return ResolveExtensionMemberAccess (left);
3146 InstanceExpression = left;
3150 protected virtual MemberExpr ResolveExtensionMemberAccess (Expression left)
3152 error176 (loc, GetSignatureForError ());
3156 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3161 if (InstanceExpression == EmptyExpression.Null) {
3162 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3166 if (InstanceExpression.Type.IsValueType) {
3167 if (InstanceExpression is IMemoryLocation) {
3168 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
3170 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
3171 InstanceExpression.Emit (ec);
3173 t.AddressOf (ec, AddressOp.Store);
3176 InstanceExpression.Emit (ec);
3178 if (prepare_for_load)
3179 ec.ig.Emit (OpCodes.Dup);
3182 public virtual void SetTypeArguments (TypeArguments ta)
3184 // TODO: need to get correct member type
3185 Report.Error (307, loc, "The property `{0}' cannot be used with type arguments",
3186 GetSignatureForError ());
3191 /// Represents group of extension methods
3193 public class ExtensionMethodGroupExpr : MethodGroupExpr
3195 readonly NamespaceEntry namespace_entry;
3196 public Expression ExtensionExpression;
3197 Argument extension_argument;
3199 public ExtensionMethodGroupExpr (ArrayList list, NamespaceEntry n, Type extensionType, Location l)
3200 : base (list, extensionType, l)
3202 this.namespace_entry = n;
3205 public override bool IsStatic {
3206 get { return true; }
3209 public bool IsTopLevel {
3210 get { return namespace_entry == null; }
3213 public override void EmitArguments (EmitContext ec, ArrayList arguments)
3215 if (arguments == null)
3216 arguments = new ArrayList (1);
3217 arguments.Insert (0, extension_argument);
3218 base.EmitArguments (ec, arguments);
3221 public override void EmitCall (EmitContext ec, ArrayList arguments)
3223 if (arguments == null)
3224 arguments = new ArrayList (1);
3225 arguments.Insert (0, extension_argument);
3226 base.EmitCall (ec, arguments);
3229 public override MethodGroupExpr OverloadResolve (EmitContext ec, ref ArrayList arguments, bool may_fail, Location loc)
3231 if (arguments == null)
3232 arguments = new ArrayList (1);
3234 arguments.Insert (0, new Argument (ExtensionExpression));
3235 MethodGroupExpr mg = ResolveOverloadExtensions (ec, arguments, namespace_entry, loc);
3237 // Store resolved argument and restore original arguments
3239 ((ExtensionMethodGroupExpr)mg).extension_argument = (Argument)arguments [0];
3240 arguments.RemoveAt (0);
3245 MethodGroupExpr ResolveOverloadExtensions (EmitContext ec, ArrayList arguments, NamespaceEntry ns, Location loc)
3247 // Use normal resolve rules
3248 MethodGroupExpr mg = base.OverloadResolve (ec, ref arguments, ns != null, loc);
3256 ExtensionMethodGroupExpr e = ns.LookupExtensionMethod (type, null, Name, loc);
3258 return base.OverloadResolve (ec, ref arguments, false, loc);
3260 e.ExtensionExpression = ExtensionExpression;
3261 return e.ResolveOverloadExtensions (ec, arguments, e.namespace_entry, loc);
3266 /// MethodGroupExpr represents a group of method candidates which
3267 /// can be resolved to the best method overload
3269 public class MethodGroupExpr : MemberExpr
3271 public interface IErrorHandler
3273 bool NoExactMatch (EmitContext ec, MethodBase method);
3276 public IErrorHandler CustomErrorHandler;
3277 public MethodBase [] Methods;
3278 MethodBase best_candidate;
3279 // TODO: make private
3280 public TypeArguments type_arguments;
3281 bool identical_type_name;
3284 public MethodGroupExpr (MemberInfo [] mi, Type type, Location l)
3287 Methods = new MethodBase [mi.Length];
3288 mi.CopyTo (Methods, 0);
3291 public MethodGroupExpr (ArrayList list, Type type, Location l)
3295 Methods = (MethodBase[])list.ToArray (typeof (MethodBase));
3297 foreach (MemberInfo m in list){
3298 if (!(m is MethodBase)){
3299 Console.WriteLine ("Name " + m.Name);
3300 Console.WriteLine ("Found a: " + m.GetType ().FullName);
3309 protected MethodGroupExpr (Type type, Location loc)
3312 eclass = ExprClass.MethodGroup;
3316 public override Type DeclaringType {
3319 // We assume that the top-level type is in the end
3321 return Methods [Methods.Length - 1].DeclaringType;
3322 //return Methods [0].DeclaringType;
3326 public Type DelegateType {
3328 delegate_type = value;
3332 public bool IdenticalTypeName {
3334 return identical_type_name;
3338 identical_type_name = value;
3342 public override string GetSignatureForError ()
3344 if (best_candidate != null)
3345 return TypeManager.CSharpSignature (best_candidate);
3347 return TypeManager.CSharpSignature (Methods [0]);
3350 public override string Name {
3352 return Methods [0].Name;
3356 public override bool IsInstance {
3358 if (best_candidate != null)
3359 return !best_candidate.IsStatic;
3361 foreach (MethodBase mb in Methods)
3369 public override bool IsStatic {
3371 if (best_candidate != null)
3372 return best_candidate.IsStatic;
3374 foreach (MethodBase mb in Methods)
3382 public static explicit operator ConstructorInfo (MethodGroupExpr mg)
3384 return (ConstructorInfo)mg.best_candidate;
3387 public static explicit operator MethodInfo (MethodGroupExpr mg)
3389 return (MethodInfo)mg.best_candidate;
3393 // 7.4.3.3 Better conversion from expression
3394 // Returns : 1 if a->p is better,
3395 // 2 if a->q is better,
3396 // 0 if neither is better
3398 static int BetterExpressionConversion (EmitContext ec, Argument a, Type p, Type q)
3400 Type argument_type = TypeManager.TypeToCoreType (a.Type);
3401 if (argument_type == TypeManager.anonymous_method_type && RootContext.Version > LanguageVersion.ISO_2) {
3403 // Uwrap delegate from Expression<T>
3405 if (TypeManager.DropGenericTypeArguments (p) == TypeManager.expression_type) {
3406 p = TypeManager.GetTypeArguments (p) [0];
3407 q = TypeManager.GetTypeArguments (q) [0];
3409 p = Delegate.GetInvokeMethod (null, p).ReturnType;
3410 q = Delegate.GetInvokeMethod (null, q).ReturnType;
3412 if (argument_type == p)
3415 if (argument_type == q)
3419 return BetterTypeConversion (ec, p, q);
3423 // 7.4.3.4 Better conversion from type
3425 public static int BetterTypeConversion (EmitContext ec, Type p, Type q)
3427 if (p == null || q == null)
3428 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3430 if (p == TypeManager.int32_type) {
3431 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3433 } else if (p == TypeManager.int64_type) {
3434 if (q == TypeManager.uint64_type)
3436 } else if (p == TypeManager.sbyte_type) {
3437 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3438 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3440 } else if (p == TypeManager.short_type) {
3441 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3442 q == TypeManager.uint64_type)
3446 if (q == TypeManager.int32_type) {
3447 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3449 } if (q == TypeManager.int64_type) {
3450 if (p == TypeManager.uint64_type)
3452 } else if (q == TypeManager.sbyte_type) {
3453 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3454 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3456 } if (q == TypeManager.short_type) {
3457 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3458 p == TypeManager.uint64_type)
3462 // TODO: this is expensive
3463 Expression p_tmp = new EmptyExpression (p);
3464 Expression q_tmp = new EmptyExpression (q);
3466 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3467 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3469 if (p_to_q && !q_to_p)
3472 if (q_to_p && !p_to_q)
3479 /// Determines "Better function" between candidate
3480 /// and the current best match
3483 /// Returns a boolean indicating :
3484 /// false if candidate ain't better
3485 /// true if candidate is better than the current best match
3487 static bool BetterFunction (EmitContext ec, ArrayList args, int argument_count,
3488 MethodBase candidate, bool candidate_params,
3489 MethodBase best, bool best_params)
3491 ParameterData candidate_pd = TypeManager.GetParameterData (candidate);
3492 ParameterData best_pd = TypeManager.GetParameterData (best);
3494 bool better_at_least_one = false;
3496 for (int j = 0, c_idx = 0, b_idx = 0; j < argument_count; ++j, ++c_idx, ++b_idx)
3498 Argument a = (Argument) args [j];
3500 Type ct = TypeManager.TypeToCoreType (candidate_pd.ParameterType (c_idx));
3501 Type bt = TypeManager.TypeToCoreType (best_pd.ParameterType (b_idx));
3503 if (candidate_params && candidate_pd.ParameterModifier (c_idx) == Parameter.Modifier.PARAMS)
3505 ct = TypeManager.GetElementType (ct);
3509 if (best_params && best_pd.ParameterModifier (b_idx) == Parameter.Modifier.PARAMS)
3511 bt = TypeManager.GetElementType (bt);
3519 int result = BetterExpressionConversion (ec, a, ct, bt);
3521 // for each argument, the conversion to 'ct' should be no worse than
3522 // the conversion to 'bt'.
3526 // for at least one argument, the conversion to 'ct' should be better than
3527 // the conversion to 'bt'.
3529 better_at_least_one = true;
3532 if (better_at_least_one)
3536 // This handles the case
3538 // Add (float f1, float f2, float f3);
3539 // Add (params decimal [] foo);
3541 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3542 // first candidate would've chosen as better.
3548 // The two methods have equal parameter types. Now apply tie-breaking rules
3550 if (TypeManager.IsGenericMethod (best) && !TypeManager.IsGenericMethod (candidate))
3552 if (!TypeManager.IsGenericMethod (best) && TypeManager.IsGenericMethod (candidate))
3556 // This handles the following cases:
3558 // Trim () is better than Trim (params char[] chars)
3559 // Concat (string s1, string s2, string s3) is better than
3560 // Concat (string s1, params string [] srest)
3561 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3563 if (!candidate_params && best_params)
3565 if (candidate_params && !best_params)
3568 int candidate_param_count = candidate_pd.Count;
3569 int best_param_count = best_pd.Count;
3571 if (candidate_param_count != best_param_count)
3572 // can only happen if (candidate_params && best_params)
3573 return candidate_param_count > best_param_count;
3576 // now, both methods have the same number of parameters, and the parameters have the same types
3577 // Pick the "more specific" signature
3580 MethodBase orig_candidate = TypeManager.DropGenericMethodArguments (candidate);
3581 MethodBase orig_best = TypeManager.DropGenericMethodArguments (best);
3583 ParameterData orig_candidate_pd = TypeManager.GetParameterData (orig_candidate);
3584 ParameterData orig_best_pd = TypeManager.GetParameterData (orig_best);
3586 bool specific_at_least_once = false;
3587 for (int j = 0; j < candidate_param_count; ++j)
3589 Type ct = TypeManager.TypeToCoreType (orig_candidate_pd.ParameterType (j));
3590 Type bt = TypeManager.TypeToCoreType (orig_best_pd.ParameterType (j));
3593 Type specific = MoreSpecific (ct, bt);
3597 specific_at_least_once = true;
3600 if (specific_at_least_once)
3603 // FIXME: handle lifted operators
3609 protected override MemberExpr ResolveExtensionMemberAccess (Expression left)
3612 return base.ResolveExtensionMemberAccess (left);
3615 // When left side is an expression and at least one candidate method is
3616 // static, it can be extension method
3618 InstanceExpression = left;
3622 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3623 SimpleName original)
3625 if (!(left is TypeExpr) &&
3626 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3627 IdenticalTypeName = true;
3629 return base.ResolveMemberAccess (ec, left, loc, original);
3632 public override Expression CreateExpressionTree (EmitContext ec)
3634 if (best_candidate.IsConstructor)
3635 return new TypeOfConstructorInfo (best_candidate, loc);
3637 return new TypeOfMethodInfo (best_candidate, loc);
3640 override public Expression DoResolve (EmitContext ec)
3642 if (InstanceExpression != null) {
3643 InstanceExpression = InstanceExpression.DoResolve (ec);
3644 if (InstanceExpression == null)
3651 public void ReportUsageError ()
3653 Report.Error (654, loc, "Method `" + DeclaringType + "." +
3654 Name + "()' is referenced without parentheses");
3657 override public void Emit (EmitContext ec)
3659 ReportUsageError ();
3662 public virtual void EmitArguments (EmitContext ec, ArrayList arguments)
3664 Invocation.EmitArguments (ec, arguments, false, null);
3667 public virtual void EmitCall (EmitContext ec, ArrayList arguments)
3669 Invocation.EmitCall (ec, IsBase, InstanceExpression, best_candidate, arguments, loc);
3672 protected virtual void Error_InvalidArguments (EmitContext ec, Location loc, int idx, MethodBase method,
3673 Argument a, ParameterData expected_par, Type paramType)
3675 if (a is CollectionElementInitializer.ElementInitializerArgument) {
3676 Report.SymbolRelatedToPreviousError (method);
3677 if ((expected_par.ParameterModifier (idx) & Parameter.Modifier.ISBYREF) != 0) {
3678 Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
3679 TypeManager.CSharpSignature (method));
3682 Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
3683 TypeManager.CSharpSignature (method));
3684 } else if (delegate_type == null) {
3685 Report.SymbolRelatedToPreviousError (method);
3686 Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
3687 TypeManager.CSharpSignature (method));
3689 Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
3690 TypeManager.CSharpName (delegate_type));
3692 Parameter.Modifier mod = expected_par.ParameterModifier (idx);
3694 string index = (idx + 1).ToString ();
3695 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
3696 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
3697 if ((mod & Parameter.Modifier.ISBYREF) == 0)
3698 Report.Error (1615, loc, "Argument `{0}' should not be passed with the `{1}' keyword",
3699 index, Parameter.GetModifierSignature (a.Modifier));
3701 Report.Error (1620, loc, "Argument `{0}' must be passed with the `{1}' keyword",
3702 index, Parameter.GetModifierSignature (mod));
3704 string p1 = a.GetSignatureForError ();
3705 string p2 = TypeManager.CSharpName (paramType);
3708 Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
3709 Report.SymbolRelatedToPreviousError (a.Expr.Type);
3710 Report.SymbolRelatedToPreviousError (paramType);
3712 Report.Error (1503, loc, "Argument {0}: Cannot convert type `{1}' to `{2}'", index, p1, p2);
3716 public override void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl)
3718 Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3719 Name, TypeManager.CSharpName (target));
3722 protected virtual int GetApplicableParametersCount (MethodBase method, ParameterData parameters)
3724 return parameters.Count;
3727 public static bool IsAncestralType (Type first_type, Type second_type)
3729 return first_type != second_type &&
3730 (TypeManager.IsSubclassOf (second_type, first_type) ||
3731 TypeManager.ImplementsInterface (second_type, first_type));
3735 /// Determines if the candidate method is applicable (section 14.4.2.1)
3736 /// to the given set of arguments
3737 /// A return value rates candidate method compatibility,
3738 /// 0 = the best, int.MaxValue = the worst
3740 public int IsApplicable (EmitContext ec,
3741 ArrayList arguments, int arg_count, ref MethodBase method, ref bool params_expanded_form)
3743 MethodBase candidate = method;
3745 ParameterData pd = TypeManager.GetParameterData (candidate);
3746 int param_count = GetApplicableParametersCount (candidate, pd);
3748 if (arg_count != param_count) {
3750 return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
3751 if (arg_count < param_count - 1)
3752 return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
3757 // 1. Handle generic method using type arguments when specified or type inference
3759 if (TypeManager.IsGenericMethod (candidate)) {
3760 if (type_arguments != null) {
3761 Type [] g_args = candidate.GetGenericArguments ();
3762 if (g_args.Length != type_arguments.Count)
3763 return int.MaxValue - 20000 + Math.Abs (type_arguments.Count - g_args.Length);
3765 // TODO: Don't create new method, create Parameters only
3766 method = ((MethodInfo) candidate).MakeGenericMethod (type_arguments.Arguments);
3768 pd = TypeManager.GetParameterData (candidate);
3770 int score = TypeManager.InferTypeArguments (ec, arguments, ref candidate);
3772 return score - 20000;
3774 if (TypeManager.IsGenericMethodDefinition (candidate))
3775 throw new InternalErrorException ("A generic method `{0}' definition took part in overload resolution",
3776 TypeManager.CSharpSignature (candidate));
3778 pd = TypeManager.GetParameterData (candidate);
3781 if (type_arguments != null)
3782 return int.MaxValue - 15000;
3787 // 2. Each argument has to be implicitly convertible to method parameter
3790 Parameter.Modifier p_mod = 0;
3792 for (int i = 0; i < arg_count; i++) {
3793 Argument a = (Argument) arguments [i];
3794 Parameter.Modifier a_mod = a.Modifier &
3795 ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3797 if (p_mod != Parameter.Modifier.PARAMS) {
3798 p_mod = pd.ParameterModifier (i) & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3800 if (p_mod == Parameter.Modifier.ARGLIST) {
3801 if (a.Type == TypeManager.runtime_argument_handle_type)
3807 pt = pd.ParameterType (i);
3809 params_expanded_form = true;
3813 if (!params_expanded_form)
3814 score = IsArgumentCompatible (ec, a_mod, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
3816 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0) {
3817 // It can be applicable in expanded form
3818 score = IsArgumentCompatible (ec, a_mod, a, 0, pt.GetElementType ());
3820 params_expanded_form = true;
3824 if (params_expanded_form)
3826 return (arg_count - i) * 2 + score;
3830 if (arg_count != param_count)
3831 params_expanded_form = true;
3836 int IsArgumentCompatible (EmitContext ec, Parameter.Modifier arg_mod, Argument argument, Parameter.Modifier param_mod, Type parameter)
3839 // Types have to be identical when ref or out modifer is used
3841 if (arg_mod != 0 || param_mod != 0) {
3842 if (TypeManager.HasElementType (parameter))
3843 parameter = parameter.GetElementType ();
3845 Type a_type = argument.Type;
3846 if (TypeManager.HasElementType (a_type))
3847 a_type = a_type.GetElementType ();
3849 if (a_type != parameter)
3855 // FIXME: Kill this abomination (EmitContext.TempEc)
3856 EmitContext prevec = EmitContext.TempEc;
3857 EmitContext.TempEc = ec;
3859 if (delegate_type != null ?
3860 !Delegate.IsTypeCovariant (argument.Expr, parameter) :
3861 !Convert.ImplicitConversionExists (ec, argument.Expr, parameter))
3864 if (arg_mod != param_mod)
3868 EmitContext.TempEc = prevec;
3874 public static bool IsOverride (MethodBase cand_method, MethodBase base_method)
3876 if (!IsAncestralType (base_method.DeclaringType, cand_method.DeclaringType))
3879 ParameterData cand_pd = TypeManager.GetParameterData (cand_method);
3880 ParameterData base_pd = TypeManager.GetParameterData (base_method);
3882 if (cand_pd.Count != base_pd.Count)
3885 for (int j = 0; j < cand_pd.Count; ++j)
3887 Parameter.Modifier cm = cand_pd.ParameterModifier (j);
3888 Parameter.Modifier bm = base_pd.ParameterModifier (j);
3889 Type ct = TypeManager.TypeToCoreType (cand_pd.ParameterType (j));
3890 Type bt = TypeManager.TypeToCoreType (base_pd.ParameterType (j));
3892 if (cm != bm || ct != bt)
3899 public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2, Location loc)
3901 MemberInfo [] miset;
3902 MethodGroupExpr union;
3907 return (MethodGroupExpr) mg2;
3910 return (MethodGroupExpr) mg1;
3913 MethodGroupExpr left_set = null, right_set = null;
3914 int length1 = 0, length2 = 0;
3916 left_set = (MethodGroupExpr) mg1;
3917 length1 = left_set.Methods.Length;
3919 right_set = (MethodGroupExpr) mg2;
3920 length2 = right_set.Methods.Length;
3922 ArrayList common = new ArrayList ();
3924 foreach (MethodBase r in right_set.Methods){
3925 if (TypeManager.ArrayContainsMethod (left_set.Methods, r))
3929 miset = new MemberInfo [length1 + length2 - common.Count];
3930 left_set.Methods.CopyTo (miset, 0);
3934 foreach (MethodBase r in right_set.Methods) {
3935 if (!common.Contains (r))
3939 union = new MethodGroupExpr (miset, mg1.Type, loc);
3944 static Type MoreSpecific (Type p, Type q)
3946 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
3948 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
3951 if (TypeManager.HasElementType (p))
3953 Type pe = TypeManager.GetElementType (p);
3954 Type qe = TypeManager.GetElementType (q);
3955 Type specific = MoreSpecific (pe, qe);
3961 else if (TypeManager.IsGenericType (p))
3963 Type[] pargs = TypeManager.GetTypeArguments (p);
3964 Type[] qargs = TypeManager.GetTypeArguments (q);
3966 bool p_specific_at_least_once = false;
3967 bool q_specific_at_least_once = false;
3969 for (int i = 0; i < pargs.Length; i++)
3971 Type specific = MoreSpecific (pargs [i], qargs [i]);
3972 if (specific == pargs [i])
3973 p_specific_at_least_once = true;
3974 if (specific == qargs [i])
3975 q_specific_at_least_once = true;
3978 if (p_specific_at_least_once && !q_specific_at_least_once)
3980 if (!p_specific_at_least_once && q_specific_at_least_once)
3988 /// Find the Applicable Function Members (7.4.2.1)
3990 /// me: Method Group expression with the members to select.
3991 /// it might contain constructors or methods (or anything
3992 /// that maps to a method).
3994 /// Arguments: ArrayList containing resolved Argument objects.
3996 /// loc: The location if we want an error to be reported, or a Null
3997 /// location for "probing" purposes.
3999 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4000 /// that is the best match of me on Arguments.
4003 public virtual MethodGroupExpr OverloadResolve (EmitContext ec, ref ArrayList Arguments,
4004 bool may_fail, Location loc)
4006 bool method_params = false;
4007 Type applicable_type = null;
4009 ArrayList candidates = new ArrayList (2);
4010 ArrayList candidate_overrides = null;
4013 // Used to keep a map between the candidate
4014 // and whether it is being considered in its
4015 // normal or expanded form
4017 // false is normal form, true is expanded form
4019 Hashtable candidate_to_form = null;
4021 if (Arguments != null)
4022 arg_count = Arguments.Count;
4024 if (RootContext.Version == LanguageVersion.ISO_1 && Name == "Invoke" && TypeManager.IsDelegateType (DeclaringType)) {
4026 Report.Error (1533, loc, "Invoke cannot be called directly on a delegate");
4030 int nmethods = Methods.Length;
4034 // Methods marked 'override' don't take part in 'applicable_type'
4035 // computation, nor in the actual overload resolution.
4036 // However, they still need to be emitted instead of a base virtual method.
4037 // So, we salt them away into the 'candidate_overrides' array.
4039 // In case of reflected methods, we replace each overriding method with
4040 // its corresponding base virtual method. This is to improve compatibility
4041 // with non-C# libraries which change the visibility of overrides (#75636)
4044 for (int i = 0; i < Methods.Length; ++i) {
4045 MethodBase m = Methods [i];
4046 if (TypeManager.IsOverride (m)) {
4047 if (candidate_overrides == null)
4048 candidate_overrides = new ArrayList ();
4049 candidate_overrides.Add (m);
4050 m = TypeManager.TryGetBaseDefinition (m);
4059 // Enable message recording, it's used mainly by lambda expressions
4061 Report.IMessageRecorder msg_recorder = new Report.MessageRecorder ();
4062 Report.IMessageRecorder prev_recorder = Report.SetMessageRecorder (msg_recorder);
4065 // First we construct the set of applicable methods
4067 bool is_sorted = true;
4068 int best_candidate_rate = int.MaxValue;
4069 for (int i = 0; i < nmethods; i++) {
4070 Type decl_type = Methods [i].DeclaringType;
4073 // If we have already found an applicable method
4074 // we eliminate all base types (Section 14.5.5.1)
4076 if (applicable_type != null && IsAncestralType (decl_type, applicable_type))
4080 // Check if candidate is applicable (section 14.4.2.1)
4082 bool params_expanded_form = false;
4083 int candidate_rate = IsApplicable (ec, Arguments, arg_count, ref Methods [i], ref params_expanded_form);
4085 if (candidate_rate < best_candidate_rate) {
4086 best_candidate_rate = candidate_rate;
4087 best_candidate = Methods [i];
4090 if (params_expanded_form) {
4091 if (candidate_to_form == null)
4092 candidate_to_form = new PtrHashtable ();
4093 MethodBase candidate = Methods [i];
4094 candidate_to_form [candidate] = candidate;
4097 if (candidate_rate != 0) {
4098 if (msg_recorder != null)
4099 msg_recorder.EndSession ();
4103 msg_recorder = null;
4104 candidates.Add (Methods [i]);
4106 if (applicable_type == null)
4107 applicable_type = decl_type;
4108 else if (applicable_type != decl_type) {
4110 if (IsAncestralType (applicable_type, decl_type))
4111 applicable_type = decl_type;
4115 Report.SetMessageRecorder (prev_recorder);
4116 if (msg_recorder != null && msg_recorder.PrintMessages ())
4119 int candidate_top = candidates.Count;
4121 if (applicable_type == null) {
4123 // When we found a top level method which does not match and it's
4124 // not an extension method. We start extension methods lookup from here
4126 if (InstanceExpression != null) {
4127 ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (type, Name, loc);
4128 if (ex_method_lookup != null) {
4129 ex_method_lookup.ExtensionExpression = InstanceExpression;
4130 ex_method_lookup.SetTypeArguments (type_arguments);
4131 return ex_method_lookup.OverloadResolve (ec, ref Arguments, may_fail, loc);
4139 // Okay so we have failed to find exact match so we
4140 // return error info about the closest match
4142 if (best_candidate != null) {
4143 if (CustomErrorHandler != null) {
4144 if (CustomErrorHandler.NoExactMatch (ec, best_candidate))
4148 ParameterData pd = TypeManager.GetParameterData (best_candidate);
4149 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4150 if (arg_count == pd.Count || pd.HasParams) {
4151 if (TypeManager.IsGenericMethodDefinition (best_candidate)) {
4152 if (type_arguments == null) {
4153 Report.Error (411, loc,
4154 "The type arguments for method `{0}' cannot be inferred from " +
4155 "the usage. Try specifying the type arguments explicitly",
4156 TypeManager.CSharpSignature (best_candidate));
4160 Type [] g_args = TypeManager.GetGenericArguments (best_candidate);
4161 if (type_arguments.Count != g_args.Length) {
4162 Report.SymbolRelatedToPreviousError (best_candidate);
4163 Report.Error (305, loc, "Using the generic method `{0}' requires `{1}' type argument(s)",
4164 TypeManager.CSharpSignature (best_candidate),
4165 g_args.Length.ToString ());
4169 if (type_arguments != null && !TypeManager.IsGenericMethod (best_candidate)) {
4170 Namespace.Error_TypeArgumentsCannotBeUsed (best_candidate, loc);
4175 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate, cand_params, may_fail, loc))
4180 if (almost_matched_members.Count != 0) {
4181 Error_MemberLookupFailed (ec.ContainerType, type, type, ".ctor",
4182 null, MemberTypes.Constructor, AllBindingFlags);
4187 // We failed to find any method with correct argument count
4189 if (Name == ConstructorInfo.ConstructorName) {
4190 Report.SymbolRelatedToPreviousError (type);
4191 Report.Error (1729, loc,
4192 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4193 TypeManager.CSharpName (type), arg_count);
4195 Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4196 Name, arg_count.ToString ());
4204 // At this point, applicable_type is _one_ of the most derived types
4205 // in the set of types containing the methods in this MethodGroup.
4206 // Filter the candidates so that they only contain methods from the
4207 // most derived types.
4210 int finalized = 0; // Number of finalized candidates
4213 // Invariant: applicable_type is a most derived type
4215 // We'll try to complete Section 14.5.5.1 for 'applicable_type' by
4216 // eliminating all it's base types. At the same time, we'll also move
4217 // every unrelated type to the end of the array, and pick the next
4218 // 'applicable_type'.
4220 Type next_applicable_type = null;
4221 int j = finalized; // where to put the next finalized candidate
4222 int k = finalized; // where to put the next undiscarded candidate
4223 for (int i = finalized; i < candidate_top; ++i) {
4224 MethodBase candidate = (MethodBase) candidates [i];
4225 Type decl_type = candidate.DeclaringType;
4227 if (decl_type == applicable_type) {
4228 candidates [k++] = candidates [j];
4229 candidates [j++] = candidates [i];
4233 if (IsAncestralType (decl_type, applicable_type))
4236 if (next_applicable_type != null &&
4237 IsAncestralType (decl_type, next_applicable_type))
4240 candidates [k++] = candidates [i];
4242 if (next_applicable_type == null ||
4243 IsAncestralType (next_applicable_type, decl_type))
4244 next_applicable_type = decl_type;
4247 applicable_type = next_applicable_type;
4250 } while (applicable_type != null);
4254 // Now we actually find the best method
4257 best_candidate = (MethodBase) candidates [0];
4258 if (delegate_type == null)
4259 method_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4261 for (int ix = 1; ix < candidate_top; ix++) {
4262 MethodBase candidate = (MethodBase) candidates [ix];
4264 if (candidate == best_candidate)
4267 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4269 if (BetterFunction (ec, Arguments, arg_count,
4270 candidate, cand_params,
4271 best_candidate, method_params)) {
4272 best_candidate = candidate;
4273 method_params = cand_params;
4277 // Now check that there are no ambiguities i.e the selected method
4278 // should be better than all the others
4280 MethodBase ambiguous = null;
4281 for (int ix = 1; ix < candidate_top; ix++) {
4282 MethodBase candidate = (MethodBase) candidates [ix];
4284 if (candidate == best_candidate)
4287 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4288 if (!BetterFunction (ec, Arguments, arg_count,
4289 best_candidate, method_params,
4290 candidate, cand_params))
4293 Report.SymbolRelatedToPreviousError (candidate);
4294 ambiguous = candidate;
4298 if (ambiguous != null) {
4299 Report.SymbolRelatedToPreviousError (best_candidate);
4300 Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4301 TypeManager.CSharpSignature (ambiguous), TypeManager.CSharpSignature (best_candidate));
4306 // If the method is a virtual function, pick an override closer to the LHS type.
4308 if (!IsBase && best_candidate.IsVirtual) {
4309 if (TypeManager.IsOverride (best_candidate))
4310 throw new InternalErrorException (
4311 "Should not happen. An 'override' method took part in overload resolution: " + best_candidate);
4313 if (candidate_overrides != null) {
4314 Type[] gen_args = null;
4315 bool gen_override = false;
4316 if (TypeManager.IsGenericMethod (best_candidate))
4317 gen_args = TypeManager.GetGenericArguments (best_candidate);
4319 foreach (MethodBase candidate in candidate_overrides) {
4320 if (TypeManager.IsGenericMethod (candidate)) {
4321 if (gen_args == null)
4324 if (gen_args.Length != TypeManager.GetGenericArguments (candidate).Length)
4327 if (gen_args != null)
4331 if (IsOverride (candidate, best_candidate)) {
4332 gen_override = true;
4333 best_candidate = candidate;
4337 if (gen_override && gen_args != null) {
4339 best_candidate = ((MethodInfo) best_candidate).MakeGenericMethod (gen_args);
4346 // And now check if the arguments are all
4347 // compatible, perform conversions if
4348 // necessary etc. and return if everything is
4351 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate,
4352 method_params, may_fail, loc))
4355 if (best_candidate == null)
4358 MethodBase the_method = TypeManager.DropGenericMethodArguments (best_candidate);
4360 if (the_method.IsGenericMethodDefinition &&
4361 !ConstraintChecker.CheckConstraints (ec, the_method, best_candidate, loc))
4365 IMethodData data = TypeManager.GetMethod (the_method);
4367 data.SetMemberIsUsed ();
4372 public override void SetTypeArguments (TypeArguments ta)
4374 type_arguments = ta;
4377 public bool VerifyArgumentsCompat (EmitContext ec, ref ArrayList arguments,
4378 int arg_count, MethodBase method,
4379 bool chose_params_expanded,
4380 bool may_fail, Location loc)
4382 ParameterData pd = TypeManager.GetParameterData (method);
4384 int errors = Report.Errors;
4385 Parameter.Modifier p_mod = 0;
4387 int a_idx = 0, a_pos = 0;
4389 ArrayList params_initializers = null;
4391 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4392 a = (Argument) arguments [a_idx];
4393 if (p_mod != Parameter.Modifier.PARAMS) {
4394 p_mod = pd.ParameterModifier (a_idx);
4395 pt = pd.ParameterType (a_idx);
4397 if (p_mod == Parameter.Modifier.ARGLIST) {
4398 if (a.Type != TypeManager.runtime_argument_handle_type)
4403 if (pt.IsPointer && !ec.InUnsafe) {
4410 if (p_mod == Parameter.Modifier.PARAMS) {
4411 if (chose_params_expanded) {
4412 params_initializers = new ArrayList (arg_count - a_idx);
4413 pt = TypeManager.GetElementType (pt);
4415 } else if (p_mod != 0) {
4416 pt = TypeManager.GetElementType (pt);
4421 // Types have to be identical when ref or out modifer is used
4423 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4424 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4427 if (!TypeManager.IsEqual (a.Expr.Type, pt))
4434 if (TypeManager.IsEqual (a.Type, pt)) {
4437 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4443 // Convert params arguments to an array initializer
4445 if (params_initializers != null) {
4446 // we choose to use 'a.Expr' rather than 'conv' so that
4447 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
4448 params_initializers.Add (a.Expr);
4449 arguments.RemoveAt (a_idx--);
4454 // Update the argument with the implicit conversion
4459 // Fill not provided arguments required by params modifier
4461 if (params_initializers == null && pd.HasParams && arg_count < pd.Count && a_idx + 1 == pd.Count) {
4462 if (arguments == null)
4463 arguments = new ArrayList (1);
4465 pt = pd.Types [GetApplicableParametersCount (method, pd) - 1];
4466 pt = TypeManager.GetElementType (pt);
4467 params_initializers = new ArrayList (0);
4470 if (a_idx == arg_count) {
4472 // Append an array argument with all params arguments
4474 if (params_initializers != null) {
4475 arguments.Add (new Argument (
4476 new ArrayCreation (new TypeExpression (pt, loc), "[]",
4477 params_initializers, loc).Resolve (ec)));
4482 if (!may_fail && Report.Errors == errors) {
4483 if (CustomErrorHandler != null)
4484 CustomErrorHandler.NoExactMatch (ec, best_candidate);
4486 Error_InvalidArguments (ec, loc, a_pos, method, a, pd, pt);
4492 public class ConstantExpr : MemberExpr
4496 public ConstantExpr (FieldInfo constant, Location loc)
4498 this.constant = constant;
4502 public override string Name {
4503 get { throw new NotImplementedException (); }
4506 public override bool IsInstance {
4507 get { return !IsStatic; }
4510 public override bool IsStatic {
4511 get { return constant.IsStatic; }
4514 public override Type DeclaringType {
4515 get { return constant.DeclaringType; }
4518 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc, SimpleName original)
4520 constant = TypeManager.GetGenericFieldDefinition (constant);
4522 IConstant ic = TypeManager.GetConstant (constant);
4524 if (constant.IsLiteral) {
4525 ic = new ExternalConstant (constant);
4527 ic = ExternalConstant.CreateDecimal (constant);
4528 // HACK: decimal field was not resolved as constant
4530 return new FieldExpr (constant, loc).ResolveMemberAccess (ec, left, loc, original);
4532 TypeManager.RegisterConstant (constant, ic);
4535 return base.ResolveMemberAccess (ec, left, loc, original);
4538 public override Expression CreateExpressionTree (EmitContext ec)
4540 throw new NotSupportedException ();
4543 public override Expression DoResolve (EmitContext ec)
4545 IConstant ic = TypeManager.GetConstant (constant);
4546 if (ic.ResolveValue ()) {
4547 if (!ec.IsInObsoleteScope)
4548 ic.CheckObsoleteness (loc);
4551 return ic.CreateConstantReference (loc);
4554 public override void Emit (EmitContext ec)
4556 throw new NotSupportedException ();
4559 public override string GetSignatureForError ()
4561 return TypeManager.GetFullNameSignature (constant);
4566 /// Fully resolved expression that evaluates to a Field
4568 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariable {
4569 public readonly FieldInfo FieldInfo;
4570 VariableInfo variable_info;
4572 LocalTemporary temp;
4574 bool in_initializer;
4576 public FieldExpr (FieldInfo fi, Location l, bool in_initializer):
4579 this.in_initializer = in_initializer;
4582 public FieldExpr (FieldInfo fi, Location l)
4585 eclass = ExprClass.Variable;
4586 type = TypeManager.TypeToCoreType (fi.FieldType);
4590 public override string Name {
4592 return FieldInfo.Name;
4596 public override bool IsInstance {
4598 return !FieldInfo.IsStatic;
4602 public override bool IsStatic {
4604 return FieldInfo.IsStatic;
4608 public override Type DeclaringType {
4610 return FieldInfo.DeclaringType;
4614 public override string GetSignatureForError ()
4616 return TypeManager.GetFullNameSignature (FieldInfo);
4619 public VariableInfo VariableInfo {
4621 return variable_info;
4625 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
4626 SimpleName original)
4628 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
4629 Type t = fi.FieldType;
4631 if (t.IsPointer && !ec.InUnsafe) {
4635 return base.ResolveMemberAccess (ec, left, loc, original);
4638 public override Expression CreateExpressionTree (EmitContext ec)
4640 Expression instance;
4641 if (InstanceExpression == null) {
4642 instance = new NullLiteral (loc);
4644 instance = InstanceExpression.CreateExpressionTree (ec);
4647 ArrayList args = new ArrayList (2);
4648 args.Add (new Argument (instance));
4649 args.Add (new Argument (CreateTypeOfExpression ()));
4650 return CreateExpressionFactoryCall ("Field", args);
4653 public Expression CreateTypeOfExpression ()
4655 return new TypeOfField (FieldInfo, loc);
4658 override public Expression DoResolve (EmitContext ec)
4660 return DoResolve (ec, false, false);
4663 Expression DoResolve (EmitContext ec, bool lvalue_instance, bool out_access)
4665 if (!FieldInfo.IsStatic){
4666 if (InstanceExpression == null){
4668 // This can happen when referencing an instance field using
4669 // a fully qualified type expression: TypeName.InstanceField = xxx
4671 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4675 // Resolve the field's instance expression while flow analysis is turned
4676 // off: when accessing a field "a.b", we must check whether the field
4677 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4679 if (lvalue_instance) {
4680 using (ec.With (EmitContext.Flags.DoFlowAnalysis, false)) {
4681 Expression right_side =
4682 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4683 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side, loc);
4686 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
4687 InstanceExpression = InstanceExpression.Resolve (ec, rf);
4690 if (InstanceExpression == null)
4693 using (ec.Set (EmitContext.Flags.OmitStructFlowAnalysis)) {
4694 InstanceExpression.CheckMarshalByRefAccess (ec);
4698 if (!in_initializer && !ec.IsInFieldInitializer) {
4699 ObsoleteAttribute oa;
4700 FieldBase f = TypeManager.GetField (FieldInfo);
4702 if (!ec.IsInObsoleteScope)
4703 f.CheckObsoleteness (loc);
4705 // To be sure that type is external because we do not register generated fields
4706 } else if (!(FieldInfo.DeclaringType is TypeBuilder)) {
4707 oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
4709 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
4713 AnonymousContainer am = ec.CurrentAnonymousMethod;
4715 if (!FieldInfo.IsStatic){
4716 if (!am.IsIterator && (ec.TypeContainer is Struct)){
4717 Report.Error (1673, loc,
4718 "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",
4725 IFixedBuffer fb = AttributeTester.GetFixedBuffer (FieldInfo);
4727 if (!ec.InFixedInitializer && ec.ContainerType.IsValueType) {
4728 Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4731 if (InstanceExpression.eclass != ExprClass.Variable) {
4732 Report.SymbolRelatedToPreviousError (FieldInfo);
4733 Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4734 TypeManager.GetFullNameSignature (FieldInfo));
4737 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4740 // If the instance expression is a local variable or parameter.
4741 IVariable var = InstanceExpression as IVariable;
4742 if ((var == null) || (var.VariableInfo == null))
4745 VariableInfo vi = var.VariableInfo;
4746 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
4749 variable_info = vi.GetSubStruct (FieldInfo.Name);
4753 static readonly int [] codes = {
4754 191, // instance, write access
4755 192, // instance, out access
4756 198, // static, write access
4757 199, // static, out access
4758 1648, // member of value instance, write access
4759 1649, // member of value instance, out access
4760 1650, // member of value static, write access
4761 1651 // member of value static, out access
4764 static readonly string [] msgs = {
4765 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4766 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4767 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4768 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4769 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4770 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4771 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4772 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4775 // The return value is always null. Returning a value simplifies calling code.
4776 Expression Report_AssignToReadonly (Expression right_side)
4779 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4783 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4785 Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4790 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4792 IVariable var = InstanceExpression as IVariable;
4793 if ((var != null) && (var.VariableInfo != null))
4794 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
4796 bool lvalue_instance = !FieldInfo.IsStatic && FieldInfo.DeclaringType.IsValueType;
4797 bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
4799 Expression e = DoResolve (ec, lvalue_instance, out_access);
4804 FieldBase fb = TypeManager.GetField (FieldInfo);
4808 if (FieldInfo.IsInitOnly) {
4809 // InitOnly fields can only be assigned in constructors or initializers
4810 if (!ec.IsInFieldInitializer && !ec.IsConstructor)
4811 return Report_AssignToReadonly (right_side);
4813 if (ec.IsConstructor) {
4814 Type ctype = ec.TypeContainer.CurrentType;
4816 ctype = ec.ContainerType;
4818 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4819 if (!TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
4820 return Report_AssignToReadonly (right_side);
4821 // static InitOnly fields cannot be assigned-to in an instance constructor
4822 if (IsStatic && !ec.IsStatic)
4823 return Report_AssignToReadonly (right_side);
4824 // instance constructors can't modify InitOnly fields of other instances of the same type
4825 if (!IsStatic && !(InstanceExpression is This))
4826 return Report_AssignToReadonly (right_side);
4830 if (right_side == EmptyExpression.OutAccess &&
4831 !IsStatic && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type)) {
4832 Report.SymbolRelatedToPreviousError (DeclaringType);
4833 Report.Warning (197, 1, loc,
4834 "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",
4835 GetSignatureForError ());
4841 bool is_marshal_by_ref ()
4843 return !IsStatic && Type.IsValueType && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type);
4846 public override void CheckMarshalByRefAccess (EmitContext ec)
4848 if (is_marshal_by_ref () && !(InstanceExpression is This)) {
4849 Report.SymbolRelatedToPreviousError (DeclaringType);
4850 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",
4851 GetSignatureForError ());
4855 public bool VerifyFixed ()
4857 IVariable variable = InstanceExpression as IVariable;
4858 // A variable of the form V.I is fixed when V is a fixed variable of a struct type.
4859 // We defer the InstanceExpression check after the variable check to avoid a
4860 // separate null check on InstanceExpression.
4861 return variable != null && InstanceExpression.Type.IsValueType && variable.VerifyFixed ();
4864 public override int GetHashCode ()
4866 return FieldInfo.GetHashCode ();
4869 public override bool Equals (object obj)
4871 FieldExpr fe = obj as FieldExpr;
4875 if (FieldInfo != fe.FieldInfo)
4878 if (InstanceExpression == null || fe.InstanceExpression == null)
4881 return InstanceExpression.Equals (fe.InstanceExpression);
4884 public void Emit (EmitContext ec, bool leave_copy)
4886 ILGenerator ig = ec.ig;
4887 bool is_volatile = false;
4889 FieldBase f = TypeManager.GetField (FieldInfo);
4891 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4894 f.SetMemberIsUsed ();
4897 if (FieldInfo.IsStatic){
4899 ig.Emit (OpCodes.Volatile);
4901 ig.Emit (OpCodes.Ldsfld, FieldInfo);
4904 EmitInstance (ec, false);
4906 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
4908 ig.Emit (OpCodes.Ldflda, FieldInfo);
4909 ig.Emit (OpCodes.Ldflda, ff.Element);
4912 ig.Emit (OpCodes.Volatile);
4914 ig.Emit (OpCodes.Ldfld, FieldInfo);
4919 ec.ig.Emit (OpCodes.Dup);
4920 if (!FieldInfo.IsStatic) {
4921 temp = new LocalTemporary (this.Type);
4927 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4929 FieldAttributes fa = FieldInfo.Attributes;
4930 bool is_static = (fa & FieldAttributes.Static) != 0;
4931 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
4932 ILGenerator ig = ec.ig;
4934 if (is_readonly && !ec.IsConstructor){
4935 Report_AssignToReadonly (source);
4939 prepared = prepare_for_load;
4940 EmitInstance (ec, prepared);
4944 ec.ig.Emit (OpCodes.Dup);
4945 if (!FieldInfo.IsStatic) {
4946 temp = new LocalTemporary (this.Type);
4951 FieldBase f = TypeManager.GetField (FieldInfo);
4953 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4954 ig.Emit (OpCodes.Volatile);
4960 ig.Emit (OpCodes.Stsfld, FieldInfo);
4962 ig.Emit (OpCodes.Stfld, FieldInfo);
4970 public override void Emit (EmitContext ec)
4975 public override void EmitSideEffect (EmitContext ec)
4977 FieldBase f = TypeManager.GetField (FieldInfo);
4978 bool is_volatile = f != null && (f.ModFlags & Modifiers.VOLATILE) != 0;
4980 if (is_volatile || is_marshal_by_ref ())
4981 base.EmitSideEffect (ec);
4984 public void AddressOf (EmitContext ec, AddressOp mode)
4986 ILGenerator ig = ec.ig;
4988 FieldBase f = TypeManager.GetField (FieldInfo);
4990 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
4991 Report.Warning (420, 1, loc, "`{0}': A volatile field references will not be treated as volatile",
4992 f.GetSignatureForError ());
4995 if ((mode & AddressOp.Store) != 0)
4997 if ((mode & AddressOp.Load) != 0)
4998 f.SetMemberIsUsed ();
5002 // Handle initonly fields specially: make a copy and then
5003 // get the address of the copy.
5006 if (FieldInfo.IsInitOnly){
5008 if (ec.IsConstructor){
5009 if (FieldInfo.IsStatic){
5021 local = ig.DeclareLocal (type);
5022 ig.Emit (OpCodes.Stloc, local);
5023 ig.Emit (OpCodes.Ldloca, local);
5028 if (FieldInfo.IsStatic){
5029 ig.Emit (OpCodes.Ldsflda, FieldInfo);
5032 EmitInstance (ec, false);
5033 ig.Emit (OpCodes.Ldflda, FieldInfo);
5040 /// Expression that evaluates to a Property. The Assign class
5041 /// might set the `Value' expression if we are in an assignment.
5043 /// This is not an LValue because we need to re-write the expression, we
5044 /// can not take data from the stack and store it.
5046 public class PropertyExpr : MemberExpr, IAssignMethod {
5047 public readonly PropertyInfo PropertyInfo;
5048 MethodInfo getter, setter;
5053 LocalTemporary temp;
5056 public PropertyExpr (Type container_type, PropertyInfo pi, Location l)
5059 eclass = ExprClass.PropertyAccess;
5063 type = TypeManager.TypeToCoreType (pi.PropertyType);
5065 ResolveAccessors (container_type);
5068 public override string Name {
5070 return PropertyInfo.Name;
5074 public override bool IsInstance {
5080 public override bool IsStatic {
5086 public override Expression CreateExpressionTree (EmitContext ec)
5088 if (IsSingleDimensionalArrayLength ()) {
5089 ArrayList args = new ArrayList (1);
5090 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5091 return CreateExpressionFactoryCall ("ArrayLength", args);
5094 // TODO: it's waiting for PropertyExpr refactoring
5095 //ArrayList args = new ArrayList (2);
5096 //args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5097 //args.Add (getter expression);
5098 //return CreateExpressionFactoryCall ("Property", args);
5099 return base.CreateExpressionTree (ec);
5102 public Expression CreateSetterTypeOfExpression ()
5104 return new TypeOfMethodInfo (setter, loc);
5107 public override Type DeclaringType {
5109 return PropertyInfo.DeclaringType;
5113 public override string GetSignatureForError ()
5115 return TypeManager.GetFullNameSignature (PropertyInfo);
5118 void FindAccessors (Type invocation_type)
5120 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
5121 BindingFlags.Static | BindingFlags.Instance |
5122 BindingFlags.DeclaredOnly;
5124 Type current = PropertyInfo.DeclaringType;
5125 for (; current != null; current = current.BaseType) {
5126 MemberInfo[] group = TypeManager.MemberLookup (
5127 invocation_type, invocation_type, current,
5128 MemberTypes.Property, flags, PropertyInfo.Name, null);
5133 if (group.Length != 1)
5134 // Oooops, can this ever happen ?
5137 PropertyInfo pi = (PropertyInfo) group [0];
5140 getter = pi.GetGetMethod (true);
5143 setter = pi.GetSetMethod (true);
5145 MethodInfo accessor = getter != null ? getter : setter;
5147 if (!accessor.IsVirtual)
5153 // We also perform the permission checking here, as the PropertyInfo does not
5154 // hold the information for the accessibility of its setter/getter
5156 // TODO: Refactor to use some kind of cache together with GetPropertyFromAccessor
5157 void ResolveAccessors (Type container_type)
5159 FindAccessors (container_type);
5161 if (getter != null) {
5162 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
5163 IMethodData md = TypeManager.GetMethod (the_getter);
5165 md.SetMemberIsUsed ();
5167 is_static = getter.IsStatic;
5170 if (setter != null) {
5171 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
5172 IMethodData md = TypeManager.GetMethod (the_setter);
5174 md.SetMemberIsUsed ();
5176 is_static = setter.IsStatic;
5180 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
5183 InstanceExpression = null;
5187 if (InstanceExpression == null) {
5188 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5192 InstanceExpression = InstanceExpression.DoResolve (ec);
5193 if (lvalue_instance && InstanceExpression != null)
5194 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
5196 if (InstanceExpression == null)
5199 InstanceExpression.CheckMarshalByRefAccess (ec);
5201 if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) &&
5202 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
5203 !TypeManager.IsNestedChildOf (ec.ContainerType, InstanceExpression.Type) &&
5204 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.ContainerType)) {
5205 Report.SymbolRelatedToPreviousError (PropertyInfo);
5206 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
5213 void Error_PropertyNotFound (MethodInfo mi, bool getter)
5215 // TODO: correctly we should compare arguments but it will lead to bigger changes
5216 if (mi is MethodBuilder) {
5217 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
5221 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
5223 ParameterData iparams = TypeManager.GetParameterData (mi);
5224 sig.Append (getter ? "get_" : "set_");
5226 sig.Append (iparams.GetSignatureForError ());
5228 Report.SymbolRelatedToPreviousError (mi);
5229 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
5230 Name, sig.ToString ());
5233 public bool IsAccessibleFrom (Type invocation_type, bool lvalue)
5236 MethodInfo accessor = lvalue ? setter : getter;
5237 if (accessor == null && lvalue)
5239 return accessor != null && IsAccessorAccessible (invocation_type, accessor, out dummy);
5242 bool IsSingleDimensionalArrayLength ()
5244 if (DeclaringType != TypeManager.array_type || getter == null || Name != "Length")
5247 string t_name = InstanceExpression.Type.Name;
5248 int t_name_len = t_name.Length;
5249 return t_name_len > 2 && t_name [t_name_len - 2] == '[' && t_name [t_name_len - 3] != ']';
5252 override public Expression DoResolve (EmitContext ec)
5257 if (getter != null){
5258 if (TypeManager.GetParameterData (getter).Count != 0){
5259 Error_PropertyNotFound (getter, true);
5264 if (getter == null){
5266 // The following condition happens if the PropertyExpr was
5267 // created, but is invalid (ie, the property is inaccessible),
5268 // and we did not want to embed the knowledge about this in
5269 // the caller routine. This only avoids double error reporting.
5274 if (InstanceExpression != EmptyExpression.Null) {
5275 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5276 TypeManager.GetFullNameSignature (PropertyInfo));
5281 bool must_do_cs1540_check = false;
5282 if (getter != null &&
5283 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
5284 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
5285 if (pm != null && pm.HasCustomAccessModifier) {
5286 Report.SymbolRelatedToPreviousError (pm);
5287 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5288 TypeManager.CSharpSignature (getter));
5291 Report.SymbolRelatedToPreviousError (getter);
5292 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
5297 if (!InstanceResolve (ec, false, must_do_cs1540_check))
5301 // Only base will allow this invocation to happen.
5303 if (IsBase && getter.IsAbstract) {
5304 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5308 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
5318 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
5320 if (right_side == EmptyExpression.OutAccess) {
5321 if (ec.CurrentBlock.Toplevel.GetTransparentIdentifier (PropertyInfo.Name) != null) {
5322 Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5325 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as `ref' or `out' parameter",
5326 GetSignatureForError ());
5331 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5332 Error_CannotModifyIntermediateExpressionValue (ec);
5335 if (setter == null){
5337 // The following condition happens if the PropertyExpr was
5338 // created, but is invalid (ie, the property is inaccessible),
5339 // and we did not want to embed the knowledge about this in
5340 // the caller routine. This only avoids double error reporting.
5344 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
5345 GetSignatureForError ());
5349 if (TypeManager.GetParameterData (setter).Count != 1){
5350 Error_PropertyNotFound (setter, false);
5354 bool must_do_cs1540_check;
5355 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
5356 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
5357 if (pm != null && pm.HasCustomAccessModifier) {
5358 Report.SymbolRelatedToPreviousError (pm);
5359 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5360 TypeManager.CSharpSignature (setter));
5363 Report.SymbolRelatedToPreviousError (setter);
5364 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
5369 if (!InstanceResolve (ec, PropertyInfo.DeclaringType.IsValueType, must_do_cs1540_check))
5373 // Only base will allow this invocation to happen.
5375 if (IsBase && setter.IsAbstract){
5376 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5383 public override void Emit (EmitContext ec)
5388 public void Emit (EmitContext ec, bool leave_copy)
5391 // Special case: length of single dimension array property is turned into ldlen
5393 if (IsSingleDimensionalArrayLength ()) {
5395 EmitInstance (ec, false);
5396 ec.ig.Emit (OpCodes.Ldlen);
5397 ec.ig.Emit (OpCodes.Conv_I4);
5401 Invocation.EmitCall (ec, IsBase, InstanceExpression, getter, null, loc, prepared, false);
5404 ec.ig.Emit (OpCodes.Dup);
5406 temp = new LocalTemporary (this.Type);
5413 // Implements the IAssignMethod interface for assignments
5415 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5417 Expression my_source = source;
5419 if (prepare_for_load) {
5424 ec.ig.Emit (OpCodes.Dup);
5426 temp = new LocalTemporary (this.Type);
5430 } else if (leave_copy) {
5432 temp = new LocalTemporary (this.Type);
5437 ArrayList args = new ArrayList (1);
5438 args.Add (new Argument (my_source, Argument.AType.Expression));
5440 Invocation.EmitCall (ec, IsBase, InstanceExpression, setter, args, loc, false, prepared);
5450 /// Fully resolved expression that evaluates to an Event
5452 public class EventExpr : MemberExpr {
5453 public readonly EventInfo EventInfo;
5456 MethodInfo add_accessor, remove_accessor;
5458 public EventExpr (EventInfo ei, Location loc)
5462 eclass = ExprClass.EventAccess;
5464 add_accessor = TypeManager.GetAddMethod (ei);
5465 remove_accessor = TypeManager.GetRemoveMethod (ei);
5466 if (add_accessor.IsStatic || remove_accessor.IsStatic)
5469 if (EventInfo is MyEventBuilder){
5470 MyEventBuilder eb = (MyEventBuilder) EventInfo;
5471 type = eb.EventType;
5474 type = EventInfo.EventHandlerType;
5477 public override string Name {
5479 return EventInfo.Name;
5483 public override bool IsInstance {
5489 public override bool IsStatic {
5495 public override Type DeclaringType {
5497 return EventInfo.DeclaringType;
5501 void Error_AssignmentEventOnly ()
5503 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5504 GetSignatureForError ());
5507 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
5508 SimpleName original)
5511 // If the event is local to this class, we transform ourselves into a FieldExpr
5514 if (EventInfo.DeclaringType == ec.ContainerType ||
5515 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
5516 EventField mi = TypeManager.GetEventField (EventInfo);
5519 if (!ec.IsInObsoleteScope)
5520 mi.CheckObsoleteness (loc);
5522 if ((mi.ModFlags & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0 && !ec.IsInCompoundAssignment)
5523 Error_AssignmentEventOnly ();
5525 FieldExpr ml = new FieldExpr (mi.FieldBuilder, loc);
5527 InstanceExpression = null;
5529 return ml.ResolveMemberAccess (ec, left, loc, original);
5533 if (left is This && !ec.IsInCompoundAssignment)
5534 Error_AssignmentEventOnly ();
5536 return base.ResolveMemberAccess (ec, left, loc, original);
5539 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
5542 InstanceExpression = null;
5546 if (InstanceExpression == null) {
5547 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5551 InstanceExpression = InstanceExpression.DoResolve (ec);
5552 if (InstanceExpression == null)
5555 if (IsBase && add_accessor.IsAbstract) {
5556 Error_CannotCallAbstractBase(TypeManager.CSharpSignature(add_accessor));
5561 // This is using the same mechanism as the CS1540 check in PropertyExpr.
5562 // However, in the Event case, we reported a CS0122 instead.
5564 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
5565 InstanceExpression.Type != ec.ContainerType &&
5566 TypeManager.IsSubclassOf (ec.ContainerType, InstanceExpression.Type)) {
5567 Report.SymbolRelatedToPreviousError (EventInfo);
5568 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5575 public bool IsAccessibleFrom (Type invocation_type)
5578 return IsAccessorAccessible (invocation_type, add_accessor, out dummy) &&
5579 IsAccessorAccessible (invocation_type, remove_accessor, out dummy);
5582 public override Expression CreateExpressionTree (EmitContext ec)
5584 throw new NotSupportedException ();
5587 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5589 // contexts where an LValue is valid have already devolved to FieldExprs
5590 Error_CannotAssign ();
5594 public override Expression DoResolve (EmitContext ec)
5596 bool must_do_cs1540_check;
5597 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
5598 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
5599 Report.SymbolRelatedToPreviousError (EventInfo);
5600 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5604 if (!InstanceResolve (ec, must_do_cs1540_check))
5607 if (!ec.IsInCompoundAssignment) {
5608 Error_CannotAssign ();
5615 public override void Emit (EmitContext ec)
5617 Error_CannotAssign ();
5620 public void Error_CannotAssign ()
5622 Report.Error (70, loc,
5623 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
5624 GetSignatureForError (), TypeManager.CSharpName (EventInfo.DeclaringType));
5627 public override string GetSignatureForError ()
5629 return TypeManager.CSharpSignature (EventInfo);
5632 public void EmitAddOrRemove (EmitContext ec, bool is_add, Expression source)
5634 ArrayList args = new ArrayList (1);
5635 args.Add (new Argument (source, Argument.AType.Expression));
5636 Invocation.EmitCall (ec, IsBase, InstanceExpression, is_add ? add_accessor : remove_accessor, args, loc);
5640 public class TemporaryVariable : Expression, IMemoryLocation
5645 public TemporaryVariable (Type type, Location loc)
5649 eclass = ExprClass.Value;
5652 public override Expression DoResolve (EmitContext ec)
5657 TypeExpr te = new TypeExpression (type, loc);
5658 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
5659 if (!li.Resolve (ec))
5662 if (ec.MustCaptureVariable (li)) {
5663 ScopeInfo scope = li.Block.CreateScopeInfo ();
5664 var = scope.AddLocal (li);
5671 public Variable Variable {
5672 get { return var != null ? var : li.Variable; }
5675 public override void Emit (EmitContext ec)
5677 Variable.EmitInstance (ec);
5681 public void EmitLoadAddress (EmitContext ec)
5683 Variable.EmitInstance (ec);
5684 Variable.EmitAddressOf (ec);
5687 public void Store (EmitContext ec, Expression right_side)
5689 Variable.EmitInstance (ec);
5690 right_side.Emit (ec);
5691 Variable.EmitAssign (ec);
5694 public void EmitThis (EmitContext ec)
5696 Variable.EmitInstance (ec);
5699 public void EmitStore (EmitContext ec)
5701 Variable.EmitAssign (ec);
5704 public void AddressOf (EmitContext ec, AddressOp mode)
5706 EmitLoadAddress (ec);
5711 /// Handles `var' contextual keyword; var becomes a keyword only
5712 /// if no type called var exists in a variable scope
5714 public class VarExpr : SimpleName
5716 // Used for error reporting only
5717 ArrayList initializer;
5719 public VarExpr (Location loc)
5724 public ArrayList VariableInitializer {
5726 this.initializer = value;
5730 public bool InferType (EmitContext ec, Expression right_side)
5733 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
5735 type = right_side.Type;
5736 if (type == TypeManager.null_type || type == TypeManager.void_type || type == TypeManager.anonymous_method_type) {
5737 Report.Error (815, loc, "An implicitly typed local variable declaration cannot be initialized with `{0}'",
5738 right_side.GetSignatureForError ());
5742 eclass = ExprClass.Variable;
5746 protected override void Error_TypeOrNamespaceNotFound (IResolveContext ec)
5748 Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");
5751 public override TypeExpr ResolveAsContextualType (IResolveContext rc, bool silent)
5753 TypeExpr te = base.ResolveAsContextualType (rc, true);
5757 if (initializer == null)
5760 if (initializer.Count > 1) {
5761 Location loc = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [1]).Location;
5762 Report.Error (819, loc, "An implicitly typed local variable declaration cannot include multiple declarators");
5767 Expression variable_initializer = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [0]).expression_or_array_initializer;
5768 if (variable_initializer == null) {
5769 Report.Error (818, loc, "An implicitly typed local variable declarator must include an initializer");