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 params_initializers.Add (conv);
4447 arguments.RemoveAt (a_idx--);
4452 // Update the argument with the implicit conversion
4457 // Fill not provided arguments required by params modifier
4459 if (params_initializers == null && pd.HasParams && arg_count < pd.Count && a_idx + 1 == pd.Count) {
4460 if (arguments == null)
4461 arguments = new ArrayList (1);
4463 pt = pd.Types [GetApplicableParametersCount (method, pd) - 1];
4464 pt = TypeManager.GetElementType (pt);
4465 params_initializers = new ArrayList (0);
4468 if (a_idx == arg_count) {
4470 // Append an array argument with all params arguments
4472 if (params_initializers != null) {
4473 arguments.Add (new Argument (
4474 new ArrayCreation (new TypeExpression (pt, loc), "[]",
4475 params_initializers, loc).Resolve (ec)));
4480 if (!may_fail && Report.Errors == errors) {
4481 if (CustomErrorHandler != null)
4482 CustomErrorHandler.NoExactMatch (ec, best_candidate);
4484 Error_InvalidArguments (ec, loc, a_pos, method, a, pd, pt);
4490 public class ConstantExpr : MemberExpr
4494 public ConstantExpr (FieldInfo constant, Location loc)
4496 this.constant = constant;
4500 public override string Name {
4501 get { throw new NotImplementedException (); }
4504 public override bool IsInstance {
4505 get { return !IsStatic; }
4508 public override bool IsStatic {
4509 get { return constant.IsStatic; }
4512 public override Type DeclaringType {
4513 get { return constant.DeclaringType; }
4516 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc, SimpleName original)
4518 constant = TypeManager.GetGenericFieldDefinition (constant);
4520 IConstant ic = TypeManager.GetConstant (constant);
4522 if (constant.IsLiteral) {
4523 ic = new ExternalConstant (constant);
4525 ic = ExternalConstant.CreateDecimal (constant);
4526 // HACK: decimal field was not resolved as constant
4528 return new FieldExpr (constant, loc).ResolveMemberAccess (ec, left, loc, original);
4530 TypeManager.RegisterConstant (constant, ic);
4533 return base.ResolveMemberAccess (ec, left, loc, original);
4536 public override Expression CreateExpressionTree (EmitContext ec)
4538 throw new NotSupportedException ();
4541 public override Expression DoResolve (EmitContext ec)
4543 IConstant ic = TypeManager.GetConstant (constant);
4544 if (ic.ResolveValue ()) {
4545 if (!ec.IsInObsoleteScope)
4546 ic.CheckObsoleteness (loc);
4549 return ic.CreateConstantReference (loc);
4552 public override void Emit (EmitContext ec)
4554 throw new NotSupportedException ();
4557 public override string GetSignatureForError ()
4559 return TypeManager.GetFullNameSignature (constant);
4564 /// Fully resolved expression that evaluates to a Field
4566 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariable {
4567 public readonly FieldInfo FieldInfo;
4568 VariableInfo variable_info;
4570 LocalTemporary temp;
4572 bool in_initializer;
4574 public FieldExpr (FieldInfo fi, Location l, bool in_initializer):
4577 this.in_initializer = in_initializer;
4580 public FieldExpr (FieldInfo fi, Location l)
4583 eclass = ExprClass.Variable;
4584 type = TypeManager.TypeToCoreType (fi.FieldType);
4588 public override string Name {
4590 return FieldInfo.Name;
4594 public override bool IsInstance {
4596 return !FieldInfo.IsStatic;
4600 public override bool IsStatic {
4602 return FieldInfo.IsStatic;
4606 public override Type DeclaringType {
4608 return FieldInfo.DeclaringType;
4612 public override string GetSignatureForError ()
4614 return TypeManager.GetFullNameSignature (FieldInfo);
4617 public VariableInfo VariableInfo {
4619 return variable_info;
4623 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
4624 SimpleName original)
4626 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
4627 Type t = fi.FieldType;
4629 if (t.IsPointer && !ec.InUnsafe) {
4633 return base.ResolveMemberAccess (ec, left, loc, original);
4636 public override Expression CreateExpressionTree (EmitContext ec)
4638 Expression instance;
4639 if (InstanceExpression == null) {
4640 instance = new NullLiteral (loc);
4642 instance = InstanceExpression.CreateExpressionTree (ec);
4645 ArrayList args = new ArrayList (2);
4646 args.Add (new Argument (instance));
4647 args.Add (new Argument (CreateTypeOfExpression ()));
4648 return CreateExpressionFactoryCall ("Field", args);
4651 public Expression CreateTypeOfExpression ()
4653 return new TypeOfField (FieldInfo, loc);
4656 override public Expression DoResolve (EmitContext ec)
4658 return DoResolve (ec, false, false);
4661 Expression DoResolve (EmitContext ec, bool lvalue_instance, bool out_access)
4663 if (!FieldInfo.IsStatic){
4664 if (InstanceExpression == null){
4666 // This can happen when referencing an instance field using
4667 // a fully qualified type expression: TypeName.InstanceField = xxx
4669 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4673 // Resolve the field's instance expression while flow analysis is turned
4674 // off: when accessing a field "a.b", we must check whether the field
4675 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4677 if (lvalue_instance) {
4678 using (ec.With (EmitContext.Flags.DoFlowAnalysis, false)) {
4679 Expression right_side =
4680 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4681 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side, loc);
4684 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
4685 InstanceExpression = InstanceExpression.Resolve (ec, rf);
4688 if (InstanceExpression == null)
4691 using (ec.Set (EmitContext.Flags.OmitStructFlowAnalysis)) {
4692 InstanceExpression.CheckMarshalByRefAccess (ec);
4696 if (!in_initializer && !ec.IsInFieldInitializer) {
4697 ObsoleteAttribute oa;
4698 FieldBase f = TypeManager.GetField (FieldInfo);
4700 if (!ec.IsInObsoleteScope)
4701 f.CheckObsoleteness (loc);
4703 // To be sure that type is external because we do not register generated fields
4704 } else if (!(FieldInfo.DeclaringType is TypeBuilder)) {
4705 oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
4707 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
4711 AnonymousContainer am = ec.CurrentAnonymousMethod;
4713 if (!FieldInfo.IsStatic){
4714 if (!am.IsIterator && (ec.TypeContainer is Struct)){
4715 Report.Error (1673, loc,
4716 "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",
4723 IFixedBuffer fb = AttributeTester.GetFixedBuffer (FieldInfo);
4725 if (!ec.InFixedInitializer && ec.ContainerType.IsValueType) {
4726 Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4729 if (InstanceExpression.eclass != ExprClass.Variable) {
4730 Report.SymbolRelatedToPreviousError (FieldInfo);
4731 Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4732 TypeManager.GetFullNameSignature (FieldInfo));
4735 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4738 // If the instance expression is a local variable or parameter.
4739 IVariable var = InstanceExpression as IVariable;
4740 if ((var == null) || (var.VariableInfo == null))
4743 VariableInfo vi = var.VariableInfo;
4744 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
4747 variable_info = vi.GetSubStruct (FieldInfo.Name);
4751 static readonly int [] codes = {
4752 191, // instance, write access
4753 192, // instance, out access
4754 198, // static, write access
4755 199, // static, out access
4756 1648, // member of value instance, write access
4757 1649, // member of value instance, out access
4758 1650, // member of value static, write access
4759 1651 // member of value static, out access
4762 static readonly string [] msgs = {
4763 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4764 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4765 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4766 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4767 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4768 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4769 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4770 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4773 // The return value is always null. Returning a value simplifies calling code.
4774 Expression Report_AssignToReadonly (Expression right_side)
4777 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4781 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4783 Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4788 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4790 IVariable var = InstanceExpression as IVariable;
4791 if ((var != null) && (var.VariableInfo != null))
4792 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
4794 bool lvalue_instance = !FieldInfo.IsStatic && FieldInfo.DeclaringType.IsValueType;
4795 bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
4797 Expression e = DoResolve (ec, lvalue_instance, out_access);
4802 FieldBase fb = TypeManager.GetField (FieldInfo);
4806 if (FieldInfo.IsInitOnly) {
4807 // InitOnly fields can only be assigned in constructors or initializers
4808 if (!ec.IsInFieldInitializer && !ec.IsConstructor)
4809 return Report_AssignToReadonly (right_side);
4811 if (ec.IsConstructor) {
4812 Type ctype = ec.TypeContainer.CurrentType;
4814 ctype = ec.ContainerType;
4816 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4817 if (!TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
4818 return Report_AssignToReadonly (right_side);
4819 // static InitOnly fields cannot be assigned-to in an instance constructor
4820 if (IsStatic && !ec.IsStatic)
4821 return Report_AssignToReadonly (right_side);
4822 // instance constructors can't modify InitOnly fields of other instances of the same type
4823 if (!IsStatic && !(InstanceExpression is This))
4824 return Report_AssignToReadonly (right_side);
4828 if (right_side == EmptyExpression.OutAccess &&
4829 !IsStatic && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type)) {
4830 Report.SymbolRelatedToPreviousError (DeclaringType);
4831 Report.Warning (197, 1, loc,
4832 "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",
4833 GetSignatureForError ());
4839 bool is_marshal_by_ref ()
4841 return !IsStatic && Type.IsValueType && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type);
4844 public override void CheckMarshalByRefAccess (EmitContext ec)
4846 if (is_marshal_by_ref () && !(InstanceExpression is This)) {
4847 Report.SymbolRelatedToPreviousError (DeclaringType);
4848 Report.Warning (1690, 1, loc, "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
4849 GetSignatureForError ());
4853 public bool VerifyFixed ()
4855 IVariable variable = InstanceExpression as IVariable;
4856 // A variable of the form V.I is fixed when V is a fixed variable of a struct type.
4857 // We defer the InstanceExpression check after the variable check to avoid a
4858 // separate null check on InstanceExpression.
4859 return variable != null && InstanceExpression.Type.IsValueType && variable.VerifyFixed ();
4862 public override int GetHashCode ()
4864 return FieldInfo.GetHashCode ();
4867 public override bool Equals (object obj)
4869 FieldExpr fe = obj as FieldExpr;
4873 if (FieldInfo != fe.FieldInfo)
4876 if (InstanceExpression == null || fe.InstanceExpression == null)
4879 return InstanceExpression.Equals (fe.InstanceExpression);
4882 public void Emit (EmitContext ec, bool leave_copy)
4884 ILGenerator ig = ec.ig;
4885 bool is_volatile = false;
4887 FieldBase f = TypeManager.GetField (FieldInfo);
4889 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4892 f.SetMemberIsUsed ();
4895 if (FieldInfo.IsStatic){
4897 ig.Emit (OpCodes.Volatile);
4899 ig.Emit (OpCodes.Ldsfld, FieldInfo);
4902 EmitInstance (ec, false);
4904 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
4906 ig.Emit (OpCodes.Ldflda, FieldInfo);
4907 ig.Emit (OpCodes.Ldflda, ff.Element);
4910 ig.Emit (OpCodes.Volatile);
4912 ig.Emit (OpCodes.Ldfld, FieldInfo);
4917 ec.ig.Emit (OpCodes.Dup);
4918 if (!FieldInfo.IsStatic) {
4919 temp = new LocalTemporary (this.Type);
4925 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4927 FieldAttributes fa = FieldInfo.Attributes;
4928 bool is_static = (fa & FieldAttributes.Static) != 0;
4929 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
4930 ILGenerator ig = ec.ig;
4932 if (is_readonly && !ec.IsConstructor){
4933 Report_AssignToReadonly (source);
4938 // String concatenation creates a new string instance
4940 prepared = prepare_for_load && !(source is StringConcat);
4941 EmitInstance (ec, prepared);
4945 ec.ig.Emit (OpCodes.Dup);
4946 if (!FieldInfo.IsStatic) {
4947 temp = new LocalTemporary (this.Type);
4952 FieldBase f = TypeManager.GetField (FieldInfo);
4954 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4955 ig.Emit (OpCodes.Volatile);
4961 ig.Emit (OpCodes.Stsfld, FieldInfo);
4963 ig.Emit (OpCodes.Stfld, FieldInfo);
4971 public override void Emit (EmitContext ec)
4976 public override void EmitSideEffect (EmitContext ec)
4978 FieldBase f = TypeManager.GetField (FieldInfo);
4979 bool is_volatile = f != null && (f.ModFlags & Modifiers.VOLATILE) != 0;
4981 if (is_volatile || is_marshal_by_ref ())
4982 base.EmitSideEffect (ec);
4985 public void AddressOf (EmitContext ec, AddressOp mode)
4987 ILGenerator ig = ec.ig;
4989 FieldBase f = TypeManager.GetField (FieldInfo);
4991 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
4992 Report.Warning (420, 1, loc, "`{0}': A volatile field references will not be treated as volatile",
4993 f.GetSignatureForError ());
4996 if ((mode & AddressOp.Store) != 0)
4998 if ((mode & AddressOp.Load) != 0)
4999 f.SetMemberIsUsed ();
5003 // Handle initonly fields specially: make a copy and then
5004 // get the address of the copy.
5007 if (FieldInfo.IsInitOnly){
5009 if (ec.IsConstructor){
5010 if (FieldInfo.IsStatic){
5022 local = ig.DeclareLocal (type);
5023 ig.Emit (OpCodes.Stloc, local);
5024 ig.Emit (OpCodes.Ldloca, local);
5029 if (FieldInfo.IsStatic){
5030 ig.Emit (OpCodes.Ldsflda, FieldInfo);
5033 EmitInstance (ec, false);
5034 ig.Emit (OpCodes.Ldflda, FieldInfo);
5041 /// Expression that evaluates to a Property. The Assign class
5042 /// might set the `Value' expression if we are in an assignment.
5044 /// This is not an LValue because we need to re-write the expression, we
5045 /// can not take data from the stack and store it.
5047 public class PropertyExpr : MemberExpr, IAssignMethod {
5048 public readonly PropertyInfo PropertyInfo;
5049 MethodInfo getter, setter;
5054 LocalTemporary temp;
5057 public PropertyExpr (Type container_type, PropertyInfo pi, Location l)
5060 eclass = ExprClass.PropertyAccess;
5064 type = TypeManager.TypeToCoreType (pi.PropertyType);
5066 ResolveAccessors (container_type);
5069 public override string Name {
5071 return PropertyInfo.Name;
5075 public override bool IsInstance {
5081 public override bool IsStatic {
5087 public override Expression CreateExpressionTree (EmitContext ec)
5089 if (IsSingleDimensionalArrayLength ()) {
5090 ArrayList args = new ArrayList (1);
5091 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5092 return CreateExpressionFactoryCall ("ArrayLength", args);
5095 // TODO: it's waiting for PropertyExpr refactoring
5096 //ArrayList args = new ArrayList (2);
5097 //args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5098 //args.Add (getter expression);
5099 //return CreateExpressionFactoryCall ("Property", args);
5100 return base.CreateExpressionTree (ec);
5103 public Expression CreateSetterTypeOfExpression ()
5105 return new TypeOfMethodInfo (setter, loc);
5108 public override Type DeclaringType {
5110 return PropertyInfo.DeclaringType;
5114 public override string GetSignatureForError ()
5116 return TypeManager.GetFullNameSignature (PropertyInfo);
5119 void FindAccessors (Type invocation_type)
5121 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
5122 BindingFlags.Static | BindingFlags.Instance |
5123 BindingFlags.DeclaredOnly;
5125 Type current = PropertyInfo.DeclaringType;
5126 for (; current != null; current = current.BaseType) {
5127 MemberInfo[] group = TypeManager.MemberLookup (
5128 invocation_type, invocation_type, current,
5129 MemberTypes.Property, flags, PropertyInfo.Name, null);
5134 if (group.Length != 1)
5135 // Oooops, can this ever happen ?
5138 PropertyInfo pi = (PropertyInfo) group [0];
5141 getter = pi.GetGetMethod (true);
5144 setter = pi.GetSetMethod (true);
5146 MethodInfo accessor = getter != null ? getter : setter;
5148 if (!accessor.IsVirtual)
5154 // We also perform the permission checking here, as the PropertyInfo does not
5155 // hold the information for the accessibility of its setter/getter
5157 // TODO: Refactor to use some kind of cache together with GetPropertyFromAccessor
5158 void ResolveAccessors (Type container_type)
5160 FindAccessors (container_type);
5162 if (getter != null) {
5163 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
5164 IMethodData md = TypeManager.GetMethod (the_getter);
5166 md.SetMemberIsUsed ();
5168 is_static = getter.IsStatic;
5171 if (setter != null) {
5172 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
5173 IMethodData md = TypeManager.GetMethod (the_setter);
5175 md.SetMemberIsUsed ();
5177 is_static = setter.IsStatic;
5181 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
5184 InstanceExpression = null;
5188 if (InstanceExpression == null) {
5189 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5193 InstanceExpression = InstanceExpression.DoResolve (ec);
5194 if (lvalue_instance && InstanceExpression != null)
5195 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
5197 if (InstanceExpression == null)
5200 InstanceExpression.CheckMarshalByRefAccess (ec);
5202 if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) &&
5203 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
5204 !TypeManager.IsNestedChildOf (ec.ContainerType, InstanceExpression.Type) &&
5205 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.ContainerType)) {
5206 Report.SymbolRelatedToPreviousError (PropertyInfo);
5207 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
5214 void Error_PropertyNotFound (MethodInfo mi, bool getter)
5216 // TODO: correctly we should compare arguments but it will lead to bigger changes
5217 if (mi is MethodBuilder) {
5218 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
5222 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
5224 ParameterData iparams = TypeManager.GetParameterData (mi);
5225 sig.Append (getter ? "get_" : "set_");
5227 sig.Append (iparams.GetSignatureForError ());
5229 Report.SymbolRelatedToPreviousError (mi);
5230 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
5231 Name, sig.ToString ());
5234 public bool IsAccessibleFrom (Type invocation_type, bool lvalue)
5237 MethodInfo accessor = lvalue ? setter : getter;
5238 if (accessor == null && lvalue)
5240 return accessor != null && IsAccessorAccessible (invocation_type, accessor, out dummy);
5243 bool IsSingleDimensionalArrayLength ()
5245 if (DeclaringType != TypeManager.array_type || getter == null || Name != "Length")
5248 string t_name = InstanceExpression.Type.Name;
5249 int t_name_len = t_name.Length;
5250 return t_name_len > 2 && t_name [t_name_len - 2] == '[' && t_name [t_name_len - 3] != ']';
5253 override public Expression DoResolve (EmitContext ec)
5258 if (getter != null){
5259 if (TypeManager.GetParameterData (getter).Count != 0){
5260 Error_PropertyNotFound (getter, true);
5265 if (getter == null){
5267 // The following condition happens if the PropertyExpr was
5268 // created, but is invalid (ie, the property is inaccessible),
5269 // and we did not want to embed the knowledge about this in
5270 // the caller routine. This only avoids double error reporting.
5275 if (InstanceExpression != EmptyExpression.Null) {
5276 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5277 TypeManager.GetFullNameSignature (PropertyInfo));
5282 bool must_do_cs1540_check = false;
5283 if (getter != null &&
5284 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
5285 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
5286 if (pm != null && pm.HasCustomAccessModifier) {
5287 Report.SymbolRelatedToPreviousError (pm);
5288 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5289 TypeManager.CSharpSignature (getter));
5292 Report.SymbolRelatedToPreviousError (getter);
5293 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
5298 if (!InstanceResolve (ec, false, must_do_cs1540_check))
5302 // Only base will allow this invocation to happen.
5304 if (IsBase && getter.IsAbstract) {
5305 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5309 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
5319 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
5321 if (right_side == EmptyExpression.OutAccess) {
5322 if (ec.CurrentBlock.Toplevel.GetTransparentIdentifier (PropertyInfo.Name) != null) {
5323 Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5326 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as `ref' or `out' parameter",
5327 GetSignatureForError ());
5332 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5333 Error_CannotModifyIntermediateExpressionValue (ec);
5336 if (setter == null){
5338 // The following condition happens if the PropertyExpr was
5339 // created, but is invalid (ie, the property is inaccessible),
5340 // and we did not want to embed the knowledge about this in
5341 // the caller routine. This only avoids double error reporting.
5345 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
5346 GetSignatureForError ());
5350 if (TypeManager.GetParameterData (setter).Count != 1){
5351 Error_PropertyNotFound (setter, false);
5355 bool must_do_cs1540_check;
5356 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
5357 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
5358 if (pm != null && pm.HasCustomAccessModifier) {
5359 Report.SymbolRelatedToPreviousError (pm);
5360 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5361 TypeManager.CSharpSignature (setter));
5364 Report.SymbolRelatedToPreviousError (setter);
5365 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
5370 if (!InstanceResolve (ec, PropertyInfo.DeclaringType.IsValueType, must_do_cs1540_check))
5374 // Only base will allow this invocation to happen.
5376 if (IsBase && setter.IsAbstract){
5377 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5384 public override void Emit (EmitContext ec)
5389 public void Emit (EmitContext ec, bool leave_copy)
5392 // Special case: length of single dimension array property is turned into ldlen
5394 if (IsSingleDimensionalArrayLength ()) {
5396 EmitInstance (ec, false);
5397 ec.ig.Emit (OpCodes.Ldlen);
5398 ec.ig.Emit (OpCodes.Conv_I4);
5402 Invocation.EmitCall (ec, IsBase, InstanceExpression, getter, null, loc, prepared, false);
5405 ec.ig.Emit (OpCodes.Dup);
5407 temp = new LocalTemporary (this.Type);
5414 // Implements the IAssignMethod interface for assignments
5416 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5418 Expression my_source = source;
5420 if (prepare_for_load) {
5421 if (source is StringConcat)
5422 EmitInstance (ec, false);
5430 ec.ig.Emit (OpCodes.Dup);
5432 temp = new LocalTemporary (this.Type);
5436 } else if (leave_copy) {
5438 temp = new LocalTemporary (this.Type);
5443 ArrayList args = new ArrayList (1);
5444 args.Add (new Argument (my_source, Argument.AType.Expression));
5446 Invocation.EmitCall (ec, IsBase, InstanceExpression, setter, args, loc, false, prepared);
5456 /// Fully resolved expression that evaluates to an Event
5458 public class EventExpr : MemberExpr {
5459 public readonly EventInfo EventInfo;
5462 MethodInfo add_accessor, remove_accessor;
5464 public EventExpr (EventInfo ei, Location loc)
5468 eclass = ExprClass.EventAccess;
5470 add_accessor = TypeManager.GetAddMethod (ei);
5471 remove_accessor = TypeManager.GetRemoveMethod (ei);
5472 if (add_accessor.IsStatic || remove_accessor.IsStatic)
5475 if (EventInfo is MyEventBuilder){
5476 MyEventBuilder eb = (MyEventBuilder) EventInfo;
5477 type = eb.EventType;
5480 type = EventInfo.EventHandlerType;
5483 public override string Name {
5485 return EventInfo.Name;
5489 public override bool IsInstance {
5495 public override bool IsStatic {
5501 public override Type DeclaringType {
5503 return EventInfo.DeclaringType;
5507 void Error_AssignmentEventOnly ()
5509 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5510 GetSignatureForError ());
5513 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
5514 SimpleName original)
5517 // If the event is local to this class, we transform ourselves into a FieldExpr
5520 if (EventInfo.DeclaringType == ec.ContainerType ||
5521 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
5522 EventField mi = TypeManager.GetEventField (EventInfo);
5525 if (!ec.IsInObsoleteScope)
5526 mi.CheckObsoleteness (loc);
5528 if ((mi.ModFlags & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0 && !ec.IsInCompoundAssignment)
5529 Error_AssignmentEventOnly ();
5531 FieldExpr ml = new FieldExpr (mi.FieldBuilder, loc);
5533 InstanceExpression = null;
5535 return ml.ResolveMemberAccess (ec, left, loc, original);
5539 if (left is This && !ec.IsInCompoundAssignment)
5540 Error_AssignmentEventOnly ();
5542 return base.ResolveMemberAccess (ec, left, loc, original);
5546 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
5549 InstanceExpression = null;
5553 if (InstanceExpression == null) {
5554 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5558 InstanceExpression = InstanceExpression.DoResolve (ec);
5559 if (InstanceExpression == null)
5562 if (IsBase && add_accessor.IsAbstract) {
5563 Error_CannotCallAbstractBase(TypeManager.CSharpSignature(add_accessor));
5568 // This is using the same mechanism as the CS1540 check in PropertyExpr.
5569 // However, in the Event case, we reported a CS0122 instead.
5571 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
5572 InstanceExpression.Type != ec.ContainerType &&
5573 TypeManager.IsSubclassOf (ec.ContainerType, InstanceExpression.Type)) {
5574 Report.SymbolRelatedToPreviousError (EventInfo);
5575 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5582 public bool IsAccessibleFrom (Type invocation_type)
5585 return IsAccessorAccessible (invocation_type, add_accessor, out dummy) &&
5586 IsAccessorAccessible (invocation_type, remove_accessor, out dummy);
5589 public override Expression CreateExpressionTree (EmitContext ec)
5591 throw new NotSupportedException ();
5594 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5596 return DoResolve (ec);
5599 public override Expression DoResolve (EmitContext ec)
5601 bool must_do_cs1540_check;
5602 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
5603 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
5604 Report.SymbolRelatedToPreviousError (EventInfo);
5605 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5609 if (!InstanceResolve (ec, must_do_cs1540_check))
5615 public override void Emit (EmitContext ec)
5617 Report.Error (70, loc, "The event `{0}' can only appear on the left hand side of += or -= "+
5618 "(except on the defining type)", GetSignatureForError ());
5621 public override string GetSignatureForError ()
5623 return TypeManager.CSharpSignature (EventInfo);
5626 public void EmitAddOrRemove (EmitContext ec, Expression source)
5628 BinaryDelegate source_del = source as BinaryDelegate;
5629 if (source_del == null) {
5633 Expression handler = source_del.Right;
5635 Argument arg = new Argument (handler, Argument.AType.Expression);
5636 ArrayList args = new ArrayList ();
5640 if (source_del.IsAddition)
5641 Invocation.EmitCall (
5642 ec, IsBase, InstanceExpression, add_accessor, args, loc);
5644 Invocation.EmitCall (
5645 ec, IsBase, InstanceExpression, remove_accessor, args, loc);
5649 public class TemporaryVariable : Expression, IMemoryLocation
5654 public TemporaryVariable (Type type, Location loc)
5658 eclass = ExprClass.Value;
5661 public override Expression DoResolve (EmitContext ec)
5666 TypeExpr te = new TypeExpression (type, loc);
5667 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
5668 if (!li.Resolve (ec))
5671 if (ec.MustCaptureVariable (li)) {
5672 ScopeInfo scope = li.Block.CreateScopeInfo ();
5673 var = scope.AddLocal (li);
5680 public Variable Variable {
5681 get { return var != null ? var : li.Variable; }
5684 public override void Emit (EmitContext ec)
5686 Variable.EmitInstance (ec);
5690 public void EmitLoadAddress (EmitContext ec)
5692 Variable.EmitInstance (ec);
5693 Variable.EmitAddressOf (ec);
5696 public void Store (EmitContext ec, Expression right_side)
5698 Variable.EmitInstance (ec);
5699 right_side.Emit (ec);
5700 Variable.EmitAssign (ec);
5703 public void EmitThis (EmitContext ec)
5705 Variable.EmitInstance (ec);
5708 public void EmitStore (EmitContext ec)
5710 Variable.EmitAssign (ec);
5713 public void AddressOf (EmitContext ec, AddressOp mode)
5715 EmitLoadAddress (ec);
5720 /// Handles `var' contextual keyword; var becomes a keyword only
5721 /// if no type called var exists in a variable scope
5723 public class VarExpr : SimpleName
5725 // Used for error reporting only
5726 ArrayList initializer;
5728 public VarExpr (Location loc)
5733 public ArrayList VariableInitializer {
5735 this.initializer = value;
5739 public bool InferType (EmitContext ec, Expression right_side)
5742 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
5744 type = right_side.Type;
5745 if (type == TypeManager.null_type || type == TypeManager.void_type || type == TypeManager.anonymous_method_type) {
5746 Report.Error (815, loc, "An implicitly typed local variable declaration cannot be initialized with `{0}'",
5747 right_side.GetSignatureForError ());
5751 eclass = ExprClass.Variable;
5755 protected override void Error_TypeOrNamespaceNotFound (IResolveContext ec)
5757 Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");
5760 public override TypeExpr ResolveAsContextualType (IResolveContext rc, bool silent)
5762 TypeExpr te = base.ResolveAsContextualType (rc, true);
5766 if (initializer == null)
5769 if (initializer.Count > 1) {
5770 Location loc = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [1]).Location;
5771 Report.Error (819, loc, "An implicitly typed local variable declaration cannot include multiple declarators");
5776 Expression variable_initializer = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [0]).expression_or_array_initializer;
5777 if (variable_initializer == null) {
5778 Report.Error (818, loc, "An implicitly typed local variable declarator must include an initializer");