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 ();
917 protected void Error_PointerInsideExpressionTree ()
919 Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
923 /// Returns an expression that can be used to invoke operator true
924 /// on the expression if it exists.
926 static public Expression GetOperatorTrue (EmitContext ec, Expression e, Location loc)
928 return GetOperatorTrueOrFalse (ec, e, true, loc);
932 /// Returns an expression that can be used to invoke operator false
933 /// on the expression if it exists.
935 static public Expression GetOperatorFalse (EmitContext ec, Expression e, Location loc)
937 return GetOperatorTrueOrFalse (ec, e, false, loc);
940 static Expression GetOperatorTrueOrFalse (EmitContext ec, Expression e, bool is_true, Location loc)
942 MethodGroupExpr operator_group;
943 string mname = Operator.GetMetadataName (is_true ? Operator.OpType.True : Operator.OpType.False);
944 operator_group = MethodLookup (ec.ContainerType, e.Type, mname, loc) as MethodGroupExpr;
945 if (operator_group == null)
948 ArrayList arguments = new ArrayList (1);
949 arguments.Add (new Argument (e, Argument.AType.Expression));
950 operator_group = operator_group.OverloadResolve (
951 ec, ref arguments, false, loc);
953 if (operator_group == null)
956 return new UserOperatorCall (operator_group, arguments, null, loc);
960 /// Resolves the expression `e' into a boolean expression: either through
961 /// an implicit conversion, or through an `operator true' invocation
963 public static Expression ResolveBoolean (EmitContext ec, Expression e, Location loc)
969 if (e.Type == TypeManager.bool_type)
972 Expression converted = Convert.ImplicitConversion (ec, e, TypeManager.bool_type, Location.Null);
974 if (converted != null)
978 // If no implicit conversion to bool exists, try using `operator true'
980 converted = Expression.GetOperatorTrue (ec, e, loc);
981 if (converted == null){
982 e.Error_ValueCannotBeConverted (ec, loc, TypeManager.bool_type, false);
988 public virtual string ExprClassName
992 case ExprClass.Invalid:
994 case ExprClass.Value:
996 case ExprClass.Variable:
998 case ExprClass.Namespace:
1000 case ExprClass.Type:
1002 case ExprClass.MethodGroup:
1003 return "method group";
1004 case ExprClass.PropertyAccess:
1005 return "property access";
1006 case ExprClass.EventAccess:
1007 return "event access";
1008 case ExprClass.IndexerAccess:
1009 return "indexer access";
1010 case ExprClass.Nothing:
1013 throw new Exception ("Should not happen");
1018 /// Reports that we were expecting `expr' to be of class `expected'
1020 public void Error_UnexpectedKind (DeclSpace ds, string expected, Location loc)
1022 Error_UnexpectedKind (ds, expected, ExprClassName, loc);
1025 public void Error_UnexpectedKind (DeclSpace ds, string expected, string was, Location loc)
1027 string name = GetSignatureForError ();
1029 name = ds.GetSignatureForError () + '.' + name;
1031 Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
1032 name, was, expected);
1035 public void Error_UnexpectedKind (ResolveFlags flags, Location loc)
1037 string [] valid = new string [4];
1040 if ((flags & ResolveFlags.VariableOrValue) != 0) {
1041 valid [count++] = "variable";
1042 valid [count++] = "value";
1045 if ((flags & ResolveFlags.Type) != 0)
1046 valid [count++] = "type";
1048 if ((flags & ResolveFlags.MethodGroup) != 0)
1049 valid [count++] = "method group";
1052 valid [count++] = "unknown";
1054 StringBuilder sb = new StringBuilder (valid [0]);
1055 for (int i = 1; i < count - 1; i++) {
1057 sb.Append (valid [i]);
1060 sb.Append ("' or `");
1061 sb.Append (valid [count - 1]);
1064 Report.Error (119, loc,
1065 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1068 public static void UnsafeError (Location loc)
1070 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1074 // Load the object from the pointer.
1076 public static void LoadFromPtr (ILGenerator ig, Type t)
1078 if (t == TypeManager.int32_type)
1079 ig.Emit (OpCodes.Ldind_I4);
1080 else if (t == TypeManager.uint32_type)
1081 ig.Emit (OpCodes.Ldind_U4);
1082 else if (t == TypeManager.short_type)
1083 ig.Emit (OpCodes.Ldind_I2);
1084 else if (t == TypeManager.ushort_type)
1085 ig.Emit (OpCodes.Ldind_U2);
1086 else if (t == TypeManager.char_type)
1087 ig.Emit (OpCodes.Ldind_U2);
1088 else if (t == TypeManager.byte_type)
1089 ig.Emit (OpCodes.Ldind_U1);
1090 else if (t == TypeManager.sbyte_type)
1091 ig.Emit (OpCodes.Ldind_I1);
1092 else if (t == TypeManager.uint64_type)
1093 ig.Emit (OpCodes.Ldind_I8);
1094 else if (t == TypeManager.int64_type)
1095 ig.Emit (OpCodes.Ldind_I8);
1096 else if (t == TypeManager.float_type)
1097 ig.Emit (OpCodes.Ldind_R4);
1098 else if (t == TypeManager.double_type)
1099 ig.Emit (OpCodes.Ldind_R8);
1100 else if (t == TypeManager.bool_type)
1101 ig.Emit (OpCodes.Ldind_I1);
1102 else if (t == TypeManager.intptr_type)
1103 ig.Emit (OpCodes.Ldind_I);
1104 else if (TypeManager.IsEnumType (t)) {
1105 if (t == TypeManager.enum_type)
1106 ig.Emit (OpCodes.Ldind_Ref);
1108 LoadFromPtr (ig, TypeManager.GetEnumUnderlyingType (t));
1109 } else if (t.IsValueType || TypeManager.IsGenericParameter (t))
1110 ig.Emit (OpCodes.Ldobj, t);
1111 else if (t.IsPointer)
1112 ig.Emit (OpCodes.Ldind_I);
1114 ig.Emit (OpCodes.Ldind_Ref);
1118 // The stack contains the pointer and the value of type `type'
1120 public static void StoreFromPtr (ILGenerator ig, Type type)
1122 if (TypeManager.IsEnumType (type))
1123 type = TypeManager.GetEnumUnderlyingType (type);
1124 if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
1125 ig.Emit (OpCodes.Stind_I4);
1126 else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
1127 ig.Emit (OpCodes.Stind_I8);
1128 else if (type == TypeManager.char_type || type == TypeManager.short_type ||
1129 type == TypeManager.ushort_type)
1130 ig.Emit (OpCodes.Stind_I2);
1131 else if (type == TypeManager.float_type)
1132 ig.Emit (OpCodes.Stind_R4);
1133 else if (type == TypeManager.double_type)
1134 ig.Emit (OpCodes.Stind_R8);
1135 else if (type == TypeManager.byte_type || type == TypeManager.sbyte_type ||
1136 type == TypeManager.bool_type)
1137 ig.Emit (OpCodes.Stind_I1);
1138 else if (type == TypeManager.intptr_type)
1139 ig.Emit (OpCodes.Stind_I);
1140 else if (type.IsValueType || TypeManager.IsGenericParameter (type))
1141 ig.Emit (OpCodes.Stobj, type);
1143 ig.Emit (OpCodes.Stind_Ref);
1147 // Returns the size of type `t' if known, otherwise, 0
1149 public static int GetTypeSize (Type t)
1151 t = TypeManager.TypeToCoreType (t);
1152 if (t == TypeManager.int32_type ||
1153 t == TypeManager.uint32_type ||
1154 t == TypeManager.float_type)
1156 else if (t == TypeManager.int64_type ||
1157 t == TypeManager.uint64_type ||
1158 t == TypeManager.double_type)
1160 else if (t == TypeManager.byte_type ||
1161 t == TypeManager.sbyte_type ||
1162 t == TypeManager.bool_type)
1164 else if (t == TypeManager.short_type ||
1165 t == TypeManager.char_type ||
1166 t == TypeManager.ushort_type)
1168 else if (t == TypeManager.decimal_type)
1174 protected void Error_CannotCallAbstractBase (string name)
1176 Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
1179 protected void Error_CannotModifyIntermediateExpressionValue (EmitContext ec)
1181 Report.SymbolRelatedToPreviousError (type);
1182 if (ec.CurrentInitializerVariable != null) {
1183 Report.Error (1918, loc, "Members of a value type property `{0}' cannot be assigned with an object initializer",
1184 GetSignatureForError ());
1186 Report.Error (1612, loc, "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
1187 GetSignatureForError ());
1192 // Converts `source' to an int, uint, long or ulong.
1194 public Expression ConvertExpressionToArrayIndex (EmitContext ec, Expression source)
1196 Expression converted;
1198 using (ec.With (EmitContext.Flags.CheckState, true)) {
1199 converted = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, source.loc);
1200 if (converted == null)
1201 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, source.loc);
1202 if (converted == null)
1203 converted = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, source.loc);
1204 if (converted == null)
1205 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, source.loc);
1207 if (converted == null) {
1208 source.Error_ValueCannotBeConverted (ec, source.loc, TypeManager.int32_type, false);
1214 // Only positive constants are allowed at compile time
1216 Constant c = converted as Constant;
1219 Error_NegativeArrayIndex (source.loc);
1224 return new ArrayIndexCast (converted).Resolve (ec);
1228 // Derived classes implement this method by cloning the fields that
1229 // could become altered during the Resolve stage
1231 // Only expressions that are created for the parser need to implement
1234 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1236 throw new NotImplementedException (
1238 "CloneTo not implemented for expression {0}", this.GetType ()));
1242 // Clones an expression created by the parser.
1244 // We only support expressions created by the parser so far, not
1245 // expressions that have been resolved (many more classes would need
1246 // to implement CloneTo).
1248 // This infrastructure is here merely for Lambda expressions which
1249 // compile the same code using different type values for the same
1250 // arguments to find the correct overload
1252 public Expression Clone (CloneContext clonectx)
1254 Expression cloned = (Expression) MemberwiseClone ();
1255 CloneTo (clonectx, cloned);
1260 public virtual Expression CreateExpressionTree (EmitContext ec)
1262 throw new NotImplementedException (
1263 "Expression tree conversion not implemented for " + GetType ());
1266 protected Expression CreateExpressionFactoryCall (string name, ArrayList args)
1268 return CreateExpressionFactoryCall (name, null, args, loc);
1271 protected Expression CreateExpressionFactoryCall (string name, TypeArguments typeArguments, ArrayList args)
1273 return CreateExpressionFactoryCall (name, typeArguments, args, loc);
1276 public static Expression CreateExpressionFactoryCall (string name, TypeArguments typeArguments, ArrayList args, Location loc)
1278 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (loc), name, typeArguments, loc), args);
1281 protected static TypeExpr CreateExpressionTypeExpression (Location loc)
1283 TypeExpr texpr = TypeManager.expression_type_expr;
1284 if (texpr == null) {
1285 Type t = TypeManager.CoreLookupType ("System.Linq.Expressions", "Expression", Kind.Class, true);
1289 TypeManager.expression_type_expr = texpr = new TypeExpression (t, Location.Null);
1297 /// This is just a base class for expressions that can
1298 /// appear on statements (invocations, object creation,
1299 /// assignments, post/pre increment and decrement). The idea
1300 /// being that they would support an extra Emition interface that
1301 /// does not leave a result on the stack.
1303 public abstract class ExpressionStatement : Expression {
1305 public virtual ExpressionStatement ResolveStatement (EmitContext ec)
1307 Expression e = Resolve (ec);
1311 ExpressionStatement es = e as ExpressionStatement;
1313 Error_InvalidExpressionStatement ();
1319 /// Requests the expression to be emitted in a `statement'
1320 /// context. This means that no new value is left on the
1321 /// stack after invoking this method (constrasted with
1322 /// Emit that will always leave a value on the stack).
1324 public abstract void EmitStatement (EmitContext ec);
1326 public override void EmitSideEffect (EmitContext ec)
1333 /// This kind of cast is used to encapsulate the child
1334 /// whose type is child.Type into an expression that is
1335 /// reported to return "return_type". This is used to encapsulate
1336 /// expressions which have compatible types, but need to be dealt
1337 /// at higher levels with.
1339 /// For example, a "byte" expression could be encapsulated in one
1340 /// of these as an "unsigned int". The type for the expression
1341 /// would be "unsigned int".
1344 public abstract class TypeCast : Expression
1346 protected Expression child;
1348 protected TypeCast (Expression child, Type return_type)
1350 eclass = child.eclass;
1351 loc = child.Location;
1356 public override Expression CreateExpressionTree (EmitContext ec)
1358 ArrayList args = new ArrayList (2);
1359 args.Add (new Argument (child.CreateExpressionTree (ec)));
1360 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1362 if (type.IsPointer || child.Type.IsPointer)
1363 Error_PointerInsideExpressionTree ();
1365 return CreateExpressionFactoryCall (ec.CheckState ? "ConvertChecked" : "Convert", args);
1368 public override Expression DoResolve (EmitContext ec)
1370 // This should never be invoked, we are born in fully
1371 // initialized state.
1376 public override void Emit (EmitContext ec)
1381 public override bool GetAttributableValue (Type value_type, out object value)
1383 return child.GetAttributableValue (value_type, out value);
1386 protected override void CloneTo (CloneContext clonectx, Expression t)
1388 TypeCast target = (TypeCast) t;
1390 target.child = child.Clone (clonectx);
1393 public override bool IsNull {
1395 return child.IsNull;
1400 public class EmptyCast : TypeCast {
1401 EmptyCast (Expression child, Type target_type)
1402 : base (child, target_type)
1406 public static Expression Create (Expression child, Type type)
1408 Constant c = child as Constant;
1410 return new EmptyConstantCast (c, type);
1412 return new EmptyCast (child, type);
1415 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1417 child.EmitBranchable (ec, label, on_true);
1420 public override void EmitSideEffect (EmitContext ec)
1422 child.EmitSideEffect (ec);
1428 /// Performs a cast using an operator (op_Explicit or op_Implicit)
1430 public class OperatorCast : TypeCast {
1431 MethodInfo conversion_operator;
1434 public OperatorCast (Expression child, Type target_type) : this (child, target_type, false) {}
1436 public OperatorCast (Expression child, Type target_type, bool find_explicit)
1437 : base (child, target_type)
1439 this.find_explicit = find_explicit;
1442 // Returns the implicit operator that converts from
1443 // 'child.Type' to our target type (type)
1444 MethodInfo GetConversionOperator (bool find_explicit)
1446 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1450 mi = TypeManager.MemberLookup (child.Type, child.Type, child.Type, MemberTypes.Method,
1451 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1454 mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1455 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1458 foreach (MethodInfo oper in mi) {
1459 ParameterData pd = TypeManager.GetParameterData (oper);
1461 if (pd.ParameterType (0) == child.Type && TypeManager.TypeToCoreType (oper.ReturnType) == type)
1469 public override void Emit (EmitContext ec)
1471 ILGenerator ig = ec.ig;
1474 conversion_operator = GetConversionOperator (find_explicit);
1476 if (conversion_operator == null)
1477 throw new InternalErrorException ("Outer conversion routine is out of sync");
1479 ig.Emit (OpCodes.Call, conversion_operator);
1485 /// This is a numeric cast to a Decimal
1487 public class CastToDecimal : TypeCast {
1488 MethodInfo conversion_operator;
1490 public CastToDecimal (Expression child)
1491 : this (child, false)
1495 public CastToDecimal (Expression child, bool find_explicit)
1496 : base (child, TypeManager.decimal_type)
1498 conversion_operator = GetConversionOperator (find_explicit);
1500 if (conversion_operator == null)
1501 throw new InternalErrorException ("Outer conversion routine is out of sync");
1504 // Returns the implicit operator that converts from
1505 // 'child.Type' to System.Decimal.
1506 MethodInfo GetConversionOperator (bool find_explicit)
1508 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1510 MemberInfo [] mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1511 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1513 foreach (MethodInfo oper in mi) {
1514 ParameterData pd = TypeManager.GetParameterData (oper);
1516 if (pd.ParameterType (0) == child.Type && TypeManager.TypeToCoreType (oper.ReturnType) == type)
1522 public override void Emit (EmitContext ec)
1524 ILGenerator ig = ec.ig;
1527 ig.Emit (OpCodes.Call, conversion_operator);
1532 /// This is an explicit numeric cast from a Decimal
1534 public class CastFromDecimal : TypeCast
1536 static IDictionary operators;
1538 public CastFromDecimal (Expression child, Type return_type)
1539 : base (child, return_type)
1541 if (child.Type != TypeManager.decimal_type)
1542 throw new InternalErrorException (
1543 "The expected type is Decimal, instead it is " + child.Type.FullName);
1546 // Returns the explicit operator that converts from an
1547 // express of type System.Decimal to 'type'.
1548 public Expression Resolve ()
1550 if (operators == null) {
1551 MemberInfo[] all_oper = TypeManager.MemberLookup (TypeManager.decimal_type,
1552 TypeManager.decimal_type, TypeManager.decimal_type, MemberTypes.Method,
1553 BindingFlags.Static | BindingFlags.Public, "op_Explicit", null);
1555 operators = new System.Collections.Specialized.HybridDictionary ();
1556 foreach (MethodInfo oper in all_oper) {
1557 ParameterData pd = TypeManager.GetParameterData (oper);
1558 if (pd.ParameterType (0) == TypeManager.decimal_type)
1559 operators.Add (TypeManager.TypeToCoreType (oper.ReturnType), oper);
1563 return operators.Contains (type) ? this : null;
1566 public override void Emit (EmitContext ec)
1568 ILGenerator ig = ec.ig;
1571 ig.Emit (OpCodes.Call, (MethodInfo)operators [type]);
1577 // Constant specialization of EmptyCast.
1578 // We need to special case this since an empty cast of
1579 // a constant is still a constant.
1581 public class EmptyConstantCast : Constant
1583 public readonly Constant child;
1585 public EmptyConstantCast(Constant child, Type type)
1586 : base (child.Location)
1588 eclass = child.eclass;
1593 public override string AsString ()
1595 return child.AsString ();
1598 public override object GetValue ()
1600 return child.GetValue ();
1603 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
1605 // FIXME: check that 'type' can be converted to 'target_type' first
1606 return child.ConvertExplicitly (in_checked_context, target_type);
1609 public override Expression CreateExpressionTree (EmitContext ec)
1611 ArrayList args = new ArrayList (2);
1612 args.Add (new Argument (child.CreateExpressionTree (ec)));
1613 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1615 Error_PointerInsideExpressionTree ();
1617 return CreateExpressionFactoryCall ("Convert", args);
1620 public override Constant Increment ()
1622 return child.Increment ();
1625 public override bool IsDefaultValue {
1626 get { return child.IsDefaultValue; }
1629 public override bool IsNegative {
1630 get { return child.IsNegative; }
1633 public override bool IsNull {
1634 get { return child.IsNull; }
1637 public override bool IsZeroInteger {
1638 get { return child.IsZeroInteger; }
1641 public override void Emit (EmitContext ec)
1646 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1648 child.EmitBranchable (ec, label, on_true);
1651 public override void EmitSideEffect (EmitContext ec)
1653 child.EmitSideEffect (ec);
1656 public override Constant ConvertImplicitly (Type target_type)
1658 // FIXME: Do we need to check user conversions?
1659 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1661 return child.ConvertImplicitly (target_type);
1667 /// This class is used to wrap literals which belong inside Enums
1669 public class EnumConstant : Constant {
1670 public Constant Child;
1672 public EnumConstant (Constant child, Type enum_type):
1673 base (child.Location)
1675 eclass = child.eclass;
1680 public override Expression DoResolve (EmitContext ec)
1682 // This should never be invoked, we are born in fully
1683 // initialized state.
1688 public override void Emit (EmitContext ec)
1693 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1695 Child.EmitBranchable (ec, label, on_true);
1698 public override void EmitSideEffect (EmitContext ec)
1700 Child.EmitSideEffect (ec);
1703 public override bool GetAttributableValue (Type value_type, out object value)
1705 value = GetTypedValue ();
1709 public override string GetSignatureForError()
1711 return TypeManager.CSharpName (Type);
1714 public override object GetValue ()
1716 return Child.GetValue ();
1719 public override object GetTypedValue ()
1721 // FIXME: runtime is not ready to work with just emited enums
1722 if (!RootContext.StdLib) {
1723 return Child.GetValue ();
1726 return System.Enum.ToObject (type, Child.GetValue ());
1729 public override string AsString ()
1731 return TypeManager.CSharpEnumValue (type, Child.GetValue ());
1734 public override Constant Increment()
1736 return new EnumConstant (Child.Increment (), type);
1739 public override bool IsDefaultValue {
1741 return Child.IsDefaultValue;
1745 public override bool IsZeroInteger {
1746 get { return Child.IsZeroInteger; }
1749 public override bool IsNegative {
1751 return Child.IsNegative;
1755 public override Constant ConvertExplicitly(bool in_checked_context, Type target_type)
1757 if (Child.Type == target_type)
1760 return Child.ConvertExplicitly (in_checked_context, target_type);
1763 public override Constant ConvertImplicitly (Type type)
1765 Type this_type = TypeManager.DropGenericTypeArguments (Type);
1766 type = TypeManager.DropGenericTypeArguments (type);
1768 if (this_type == type) {
1769 // This is workaround of mono bug. It can be removed when the latest corlib spreads enough
1770 if (TypeManager.IsEnumType (type.UnderlyingSystemType))
1773 Type child_type = TypeManager.DropGenericTypeArguments (Child.Type);
1774 if (type.UnderlyingSystemType != child_type)
1775 Child = Child.ConvertImplicitly (type.UnderlyingSystemType);
1779 if (!Convert.ImplicitStandardConversionExists (this, type)){
1783 return Child.ConvertImplicitly(type);
1789 /// This kind of cast is used to encapsulate Value Types in objects.
1791 /// The effect of it is to box the value type emitted by the previous
1794 public class BoxedCast : TypeCast {
1796 public BoxedCast (Expression expr, Type target_type)
1797 : base (expr, target_type)
1799 eclass = ExprClass.Value;
1802 public override Expression DoResolve (EmitContext ec)
1804 // This should never be invoked, we are born in fully
1805 // initialized state.
1810 public override void Emit (EmitContext ec)
1814 ec.ig.Emit (OpCodes.Box, child.Type);
1817 public override void EmitSideEffect (EmitContext ec)
1819 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1820 // so, we need to emit the box+pop instructions in most cases
1821 if (child.Type.IsValueType &&
1822 (type == TypeManager.object_type || type == TypeManager.value_type))
1823 child.EmitSideEffect (ec);
1825 base.EmitSideEffect (ec);
1829 public class UnboxCast : TypeCast {
1830 public UnboxCast (Expression expr, Type return_type)
1831 : base (expr, return_type)
1835 public override Expression DoResolve (EmitContext ec)
1837 // This should never be invoked, we are born in fully
1838 // initialized state.
1843 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1845 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
1846 Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
1847 return base.DoResolveLValue (ec, right_side);
1850 public override void Emit (EmitContext ec)
1853 ILGenerator ig = ec.ig;
1857 if (t.IsGenericParameter || t.IsGenericType && t.IsValueType)
1858 ig.Emit (OpCodes.Unbox_Any, t);
1862 ig.Emit (OpCodes.Unbox, t);
1864 LoadFromPtr (ig, t);
1870 /// This is used to perform explicit numeric conversions.
1872 /// Explicit numeric conversions might trigger exceptions in a checked
1873 /// context, so they should generate the conv.ovf opcodes instead of
1876 public class ConvCast : TypeCast {
1877 public enum Mode : byte {
1878 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1880 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1881 U2_I1, U2_U1, U2_I2, U2_CH,
1882 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1883 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1884 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH,
1885 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH,
1886 CH_I1, CH_U1, CH_I2,
1887 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1888 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4
1893 public ConvCast (Expression child, Type return_type, Mode m)
1894 : base (child, return_type)
1899 public override Expression DoResolve (EmitContext ec)
1901 // This should never be invoked, we are born in fully
1902 // initialized state.
1907 public override string ToString ()
1909 return String.Format ("ConvCast ({0}, {1})", mode, child);
1912 public override void Emit (EmitContext ec)
1914 ILGenerator ig = ec.ig;
1920 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1921 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1922 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1923 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1924 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1926 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1927 case Mode.U1_CH: /* nothing */ break;
1929 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1930 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1931 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1932 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1933 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1934 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1936 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1937 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1938 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1939 case Mode.U2_CH: /* nothing */ break;
1941 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1942 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1943 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1944 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1945 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1946 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1947 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1949 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1950 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1951 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1952 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1953 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1954 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1956 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1957 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1958 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1959 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1960 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1961 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1962 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1963 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1965 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1966 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1967 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1968 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1969 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1970 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1971 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1972 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1974 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1975 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1976 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1978 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1979 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1980 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1981 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1982 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1983 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1984 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1985 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1986 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1988 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1989 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1990 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1991 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1992 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1993 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1994 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1995 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1996 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1997 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
2001 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
2002 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
2003 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
2004 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
2005 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
2007 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
2008 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
2010 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
2011 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
2012 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
2013 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
2014 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
2015 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
2017 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
2018 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
2019 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
2020 case Mode.U2_CH: /* nothing */ break;
2022 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
2023 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
2024 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
2025 case Mode.I4_U4: /* nothing */ break;
2026 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
2027 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
2028 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
2030 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
2031 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
2032 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
2033 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
2034 case Mode.U4_I4: /* nothing */ break;
2035 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
2037 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
2038 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
2039 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
2040 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
2041 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
2042 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
2043 case Mode.I8_U8: /* nothing */ break;
2044 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
2046 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
2047 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
2048 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
2049 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
2050 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
2051 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
2052 case Mode.U8_I8: /* nothing */ break;
2053 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
2055 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
2056 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
2057 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
2059 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
2060 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
2061 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
2062 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
2063 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
2064 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
2065 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
2066 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
2067 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
2069 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
2070 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
2071 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
2072 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
2073 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
2074 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
2075 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
2076 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
2077 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
2078 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
2084 public class OpcodeCast : TypeCast {
2088 public OpcodeCast (Expression child, Type return_type, OpCode op)
2089 : base (child, return_type)
2093 second_valid = false;
2096 public OpcodeCast (Expression child, Type return_type, OpCode op, OpCode op2)
2097 : base (child, return_type)
2102 second_valid = true;
2105 public override Expression DoResolve (EmitContext ec)
2107 // This should never be invoked, we are born in fully
2108 // initialized state.
2113 public override void Emit (EmitContext ec)
2122 public Type UnderlyingType {
2123 get { return child.Type; }
2128 /// This kind of cast is used to encapsulate a child and cast it
2129 /// to the class requested
2131 public class ClassCast : TypeCast {
2132 public ClassCast (Expression child, Type return_type)
2133 : base (child, return_type)
2138 public override Expression DoResolve (EmitContext ec)
2140 // This should never be invoked, we are born in fully
2141 // initialized state.
2146 public override void Emit (EmitContext ec)
2150 if (TypeManager.IsGenericParameter (child.Type))
2151 ec.ig.Emit (OpCodes.Box, child.Type);
2154 if (type.IsGenericParameter)
2155 ec.ig.Emit (OpCodes.Unbox_Any, type);
2158 ec.ig.Emit (OpCodes.Castclass, type);
2163 // Used when resolved expression has different representations for
2164 // expression trees and emit phase
2166 public class ReducedExpression : Expression
2168 class ReducedConstantExpression : Constant
2170 readonly Constant expr;
2171 readonly Expression orig_expr;
2173 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2174 : base (expr.Location)
2177 this.orig_expr = orig_expr;
2178 eclass = expr.eclass;
2182 public override string AsString ()
2184 return expr.AsString ();
2187 public override Expression CreateExpressionTree (EmitContext ec)
2189 return orig_expr.CreateExpressionTree (ec);
2192 public override object GetValue ()
2194 return expr.GetValue ();
2197 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
2199 throw new NotImplementedException ();
2202 public override Expression DoResolve (EmitContext ec)
2207 public override Constant Increment ()
2209 throw new NotImplementedException ();
2212 public override bool IsDefaultValue {
2214 return expr.IsDefaultValue;
2218 public override bool IsNegative {
2220 return expr.IsNegative;
2224 public override void Emit (EmitContext ec)
2230 readonly Expression expr, orig_expr;
2232 private ReducedExpression (Expression expr, Expression orig_expr)
2235 this.orig_expr = orig_expr;
2236 this.loc = orig_expr.Location;
2239 public static Expression Create (Constant expr, Expression original_expr)
2241 return new ReducedConstantExpression (expr, original_expr);
2244 public static Expression Create (Expression expr, Expression original_expr)
2246 Constant c = expr as Constant;
2248 return Create (c, original_expr);
2250 return new ReducedExpression (expr, original_expr);
2253 public override Expression CreateExpressionTree (EmitContext ec)
2255 return orig_expr.CreateExpressionTree (ec);
2258 public override Expression DoResolve (EmitContext ec)
2260 eclass = expr.eclass;
2265 public override void Emit (EmitContext ec)
2270 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2272 expr.EmitBranchable (ec, target, on_true);
2277 // Unresolved type name expressions
2279 public abstract class ATypeNameExpression : FullNamedExpression
2281 public readonly string Name;
2282 protected TypeArguments targs;
2284 protected ATypeNameExpression (string name, Location l)
2290 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2297 public bool HasTypeArguments {
2299 return targs != null;
2303 public override string GetSignatureForError ()
2305 if (targs != null) {
2306 return TypeManager.RemoveGenericArity (Name) + "<" +
2307 targs.GetSignatureForError () + ">";
2315 /// SimpleName expressions are formed of a single word and only happen at the beginning
2316 /// of a dotted-name.
2318 public class SimpleName : ATypeNameExpression {
2321 public SimpleName (string name, Location l)
2326 public SimpleName (string name, TypeArguments args, Location l)
2327 : base (name, args, l)
2331 public SimpleName (string name, TypeParameter[] type_params, Location l)
2334 targs = new TypeArguments (l);
2335 foreach (TypeParameter type_param in type_params)
2336 targs.Add (new TypeParameterExpr (type_param, l));
2339 public static string RemoveGenericArity (string name)
2342 StringBuilder sb = null;
2344 int pos = name.IndexOf ('`', start);
2349 sb.Append (name.Substring (start));
2354 sb = new StringBuilder ();
2355 sb.Append (name.Substring (start, pos-start));
2358 while ((pos < name.Length) && Char.IsNumber (name [pos]))
2362 } while (start < name.Length);
2364 return sb.ToString ();
2367 public SimpleName GetMethodGroup ()
2369 return new SimpleName (RemoveGenericArity (Name), targs, loc);
2372 public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
2374 if (ec.IsInFieldInitializer)
2375 Report.Error (236, l,
2376 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2380 120, l, "`{0}': An object reference is required for the nonstatic field, method or property",
2384 public bool IdenticalNameAndTypeName (EmitContext ec, Expression resolved_to, Location loc)
2386 return resolved_to != null && resolved_to.Type != null &&
2387 resolved_to.Type.Name == Name &&
2388 (ec.DeclContainer.LookupNamespaceOrType (Name, loc, /* ignore_cs0104 = */ true) != null);
2391 public override Expression DoResolve (EmitContext ec)
2393 return SimpleNameResolve (ec, null, false);
2396 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
2398 return SimpleNameResolve (ec, right_side, false);
2402 public Expression DoResolve (EmitContext ec, bool intermediate)
2404 return SimpleNameResolve (ec, null, intermediate);
2407 static bool IsNestedChild (Type t, Type parent)
2409 while (parent != null) {
2410 if (TypeManager.IsNestedChildOf (t, TypeManager.DropGenericTypeArguments (parent)))
2413 parent = parent.BaseType;
2419 FullNamedExpression ResolveNested (IResolveContext ec, Type t)
2421 if (!TypeManager.IsGenericTypeDefinition (t) && !TypeManager.IsGenericType (t))
2424 DeclSpace ds = ec.DeclContainer;
2425 while (ds != null && !IsNestedChild (t, ds.TypeBuilder))
2431 Type[] gen_params = TypeManager.GetTypeArguments (t);
2433 int arg_count = targs != null ? targs.Count : 0;
2435 for (; (ds != null) && ds.IsGeneric; ds = ds.Parent) {
2436 if (arg_count + ds.CountTypeParameters == gen_params.Length) {
2437 TypeArguments new_args = new TypeArguments (loc);
2438 foreach (TypeParameter param in ds.TypeParameters)
2439 new_args.Add (new TypeParameterExpr (param, loc));
2442 new_args.Add (targs);
2444 return new ConstructedType (t, new_args, loc);
2451 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2453 FullNamedExpression fne = ec.GenericDeclContainer.LookupGeneric (Name, loc);
2455 return fne.ResolveAsTypeStep (ec, silent);
2457 int errors = Report.Errors;
2458 fne = ec.DeclContainer.LookupNamespaceOrType (Name, loc, /*ignore_cs0104=*/ false);
2461 if (fne.Type == null)
2464 FullNamedExpression nested = ResolveNested (ec, fne.Type);
2466 return nested.ResolveAsTypeStep (ec, false);
2468 if (targs != null) {
2469 ConstructedType ct = new ConstructedType (fne, targs, loc);
2470 return ct.ResolveAsTypeStep (ec, false);
2476 if (silent || errors != Report.Errors)
2479 Error_TypeOrNamespaceNotFound (ec);
2483 protected virtual void Error_TypeOrNamespaceNotFound (IResolveContext ec)
2485 MemberCore mc = ec.DeclContainer.GetDefinition (Name);
2487 Error_UnexpectedKind (ec.DeclContainer, "type", GetMemberType (mc), loc);
2491 string ns = ec.DeclContainer.NamespaceEntry.NS.Name;
2492 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2493 foreach (Assembly a in RootNamespace.Global.Assemblies) {
2494 Type type = a.GetType (fullname);
2496 Report.SymbolRelatedToPreviousError (type);
2497 Expression.ErrorIsInaccesible (loc, TypeManager.CSharpName (type));
2502 Type t = ec.DeclContainer.LookupAnyGeneric (Name);
2504 Namespace.Error_InvalidNumberOfTypeArguments (t, loc);
2508 if (targs != null) {
2509 FullNamedExpression retval = ec.DeclContainer.LookupNamespaceOrType (SimpleName.RemoveGenericArity (Name), loc, true);
2510 if (retval != null) {
2511 Namespace.Error_TypeArgumentsCannotBeUsed (retval.Type, loc);
2516 NamespaceEntry.Error_NamespaceNotFound (loc, Name);
2519 // TODO: I am still not convinced about this. If someone else will need it
2520 // implement this as virtual property in MemberCore hierarchy
2521 public static string GetMemberType (MemberCore mc)
2527 if (mc is FieldBase)
2529 if (mc is MethodCore)
2531 if (mc is EnumMember)
2539 Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2545 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2551 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2558 /// 7.5.2: Simple Names.
2560 /// Local Variables and Parameters are handled at
2561 /// parse time, so they never occur as SimpleNames.
2563 /// The `intermediate' flag is used by MemberAccess only
2564 /// and it is used to inform us that it is ok for us to
2565 /// avoid the static check, because MemberAccess might end
2566 /// up resolving the Name as a Type name and the access as
2567 /// a static type access.
2569 /// ie: Type Type; .... { Type.GetType (""); }
2571 /// Type is both an instance variable and a Type; Type.GetType
2572 /// is the static method not an instance method of type.
2574 Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2576 Expression e = null;
2579 // Stage 1: Performed by the parser (binding to locals or parameters).
2581 Block current_block = ec.CurrentBlock;
2582 if (current_block != null){
2583 LocalInfo vi = current_block.GetLocalInfo (Name);
2585 if (targs != null) {
2586 Report.Error (307, loc,
2587 "The variable `{0}' cannot be used with type arguments",
2592 LocalVariableReference var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2593 if (right_side != null) {
2594 return var.ResolveLValue (ec, right_side, loc);
2596 ResolveFlags rf = ResolveFlags.VariableOrValue;
2598 rf |= ResolveFlags.DisableFlowAnalysis;
2599 return var.Resolve (ec, rf);
2603 ParameterReference pref = current_block.Toplevel.GetParameterReference (Name, loc);
2605 if (targs != null) {
2606 Report.Error (307, loc,
2607 "The variable `{0}' cannot be used with type arguments",
2612 if (right_side != null)
2613 return pref.ResolveLValue (ec, right_side, loc);
2615 return pref.Resolve (ec);
2618 Expression expr = current_block.Toplevel.GetTransparentIdentifier (Name);
2620 if (right_side != null)
2621 return expr.ResolveLValue (ec, right_side, loc);
2622 return expr.Resolve (ec);
2627 // Stage 2: Lookup members
2630 Type almost_matched_type = null;
2631 ArrayList almost_matched = null;
2632 for (DeclSpace lookup_ds = ec.DeclContainer; lookup_ds != null; lookup_ds = lookup_ds.Parent) {
2633 // either RootDeclSpace or GenericMethod
2634 if (lookup_ds.TypeBuilder == null)
2637 e = MemberLookup (ec.ContainerType, lookup_ds.TypeBuilder, Name, loc);
2639 if (e is PropertyExpr) {
2640 // since TypeManager.MemberLookup doesn't know if we're doing a lvalue access or not,
2641 // it doesn't know which accessor to check permissions against
2642 if (((PropertyExpr) e).IsAccessibleFrom (ec.ContainerType, right_side != null))
2644 } else if (e is EventExpr) {
2645 if (((EventExpr) e).IsAccessibleFrom (ec.ContainerType))
2653 if (almost_matched == null && almost_matched_members.Count > 0) {
2654 almost_matched_type = lookup_ds.TypeBuilder;
2655 almost_matched = (ArrayList) almost_matched_members.Clone ();
2660 if (almost_matched == null && almost_matched_members.Count > 0) {
2661 almost_matched_type = ec.ContainerType;
2662 almost_matched = (ArrayList) almost_matched_members.Clone ();
2664 e = ResolveAsTypeStep (ec, true);
2668 if (current_block != null) {
2669 IKnownVariable ikv = current_block.Explicit.GetKnownVariable (Name);
2671 LocalInfo li = ikv as LocalInfo;
2672 // Supress CS0219 warning
2676 Error_VariableIsUsedBeforeItIsDeclared (Name);
2681 if (almost_matched != null)
2682 almost_matched_members = almost_matched;
2683 if (almost_matched_type == null)
2684 almost_matched_type = ec.ContainerType;
2685 Error_MemberLookupFailed (ec.ContainerType, null, almost_matched_type, Name,
2686 ec.DeclContainer.Name, AllMemberTypes, AllBindingFlags);
2690 if (e is TypeExpr) {
2694 ConstructedType ct = new ConstructedType (
2695 e.Type, targs, loc);
2696 return ct.ResolveAsTypeStep (ec, false);
2699 if (e is MemberExpr) {
2700 MemberExpr me = (MemberExpr) e;
2703 if (me.IsInstance) {
2704 if (ec.IsStatic || ec.IsInFieldInitializer) {
2706 // Note that an MemberExpr can be both IsInstance and IsStatic.
2707 // An unresolved MethodGroupExpr can contain both kinds of methods
2708 // and each predicate is true if the MethodGroupExpr contains
2709 // at least one of that kind of method.
2713 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2714 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2719 // Pass the buck to MemberAccess and Invocation.
2721 left = EmptyExpression.Null;
2723 left = ec.GetThis (loc);
2726 left = new TypeExpression (ec.ContainerType, loc);
2729 me = me.ResolveMemberAccess (ec, left, loc, null);
2733 if (targs != null) {
2735 me.SetTypeArguments (targs);
2738 if (!me.IsStatic && (me.InstanceExpression != null) &&
2739 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2740 me.InstanceExpression.Type != me.DeclaringType &&
2741 !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2742 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2743 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2744 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2748 return (right_side != null)
2749 ? me.DoResolveLValue (ec, right_side)
2750 : me.DoResolve (ec);
2756 protected override void CloneTo (CloneContext clonectx, Expression target)
2758 // CloneTo: Nothing, we do not keep any state on this expression
2763 /// Represents a namespace or a type. The name of the class was inspired by
2764 /// section 10.8.1 (Fully Qualified Names).
2766 public abstract class FullNamedExpression : Expression {
2768 public override Expression CreateExpressionTree (EmitContext ec)
2770 throw new NotSupportedException ("ET");
2773 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2778 public override void Emit (EmitContext ec)
2780 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2781 GetSignatureForError ());
2786 /// Expression that evaluates to a type
2788 public abstract class TypeExpr : FullNamedExpression {
2789 override public FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2791 TypeExpr t = DoResolveAsTypeStep (ec);
2795 eclass = ExprClass.Type;
2799 override public Expression DoResolve (EmitContext ec)
2801 return ResolveAsTypeTerminal (ec, false);
2804 public virtual bool CheckAccessLevel (DeclSpace ds)
2806 return ds.CheckAccessLevel (Type);
2809 public virtual bool AsAccessible (DeclSpace ds)
2811 return ds.IsAccessibleAs (Type);
2814 public virtual bool IsClass {
2815 get { return Type.IsClass; }
2818 public virtual bool IsValueType {
2819 get { return Type.IsValueType; }
2822 public virtual bool IsInterface {
2823 get { return Type.IsInterface; }
2826 public virtual bool IsSealed {
2827 get { return Type.IsSealed; }
2830 public virtual bool CanInheritFrom ()
2832 if (Type == TypeManager.enum_type ||
2833 (Type == TypeManager.value_type && RootContext.StdLib) ||
2834 Type == TypeManager.multicast_delegate_type ||
2835 Type == TypeManager.delegate_type ||
2836 Type == TypeManager.array_type)
2842 protected abstract TypeExpr DoResolveAsTypeStep (IResolveContext ec);
2844 public override bool Equals (object obj)
2846 TypeExpr tobj = obj as TypeExpr;
2850 return Type == tobj.Type;
2853 public override int GetHashCode ()
2855 return Type.GetHashCode ();
2860 /// Fully resolved Expression that already evaluated to a type
2862 public class TypeExpression : TypeExpr {
2863 public TypeExpression (Type t, Location l)
2866 eclass = ExprClass.Type;
2870 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2875 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2882 /// Used to create types from a fully qualified name. These are just used
2883 /// by the parser to setup the core types. A TypeLookupExpression is always
2884 /// classified as a type.
2886 public sealed class TypeLookupExpression : TypeExpr {
2887 readonly string name;
2889 public TypeLookupExpression (string name)
2892 eclass = ExprClass.Type;
2895 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2897 // It's null for corlib compilation only
2899 return DoResolveAsTypeStep (ec);
2904 private class UnexpectedType
2908 // This performes recursive type lookup, providing support for generic types.
2909 // For example, given the type:
2911 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]]
2913 // The types will be checked in the following order:
2916 // System.Collections |
2917 // System.Collections.Generic |
2919 // System | recursive call 1 |
2920 // System.Int32 _| | main method call
2922 // System | recursive call 2 |
2923 // System.String _| |
2925 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]] _|
2927 private Type TypeLookup (IResolveContext ec, string name)
2932 FullNamedExpression resolved = null;
2934 Type recursive_type = null;
2935 while (index < name.Length) {
2936 if (name[index] == '[') {
2941 if (name[index] == '[')
2943 else if (name[index] == ']')
2945 } while (braces > 0);
2946 recursive_type = TypeLookup (ec, name.Substring (open + 1, index - open - 1));
2947 if (recursive_type == null || (recursive_type == typeof(UnexpectedType)))
2948 return recursive_type;
2951 if (name[index] == ',')
2953 else if ((name[index] == '.' && !done) || (index == name.Length && name[0] != '[')) {
2954 string substring = name.Substring(dot, index - dot);
2956 if (resolved == null)
2957 resolved = RootNamespace.Global.Lookup (ec.DeclContainer, substring, Location.Null);
2958 else if (resolved is Namespace)
2959 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
2960 else if (type != null)
2961 type = TypeManager.GetNestedType (type, substring);
2965 if (resolved == null)
2967 else if (type == null && resolved is TypeExpr)
2968 type = resolved.Type;
2975 if (name[0] != '[') {
2976 string substring = name.Substring(dot, index - dot);
2979 return TypeManager.GetNestedType (type, substring);
2981 if (resolved != null) {
2982 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
2983 if (resolved is TypeExpr)
2984 return resolved.Type;
2986 if (resolved == null)
2989 resolved.Error_UnexpectedKind (ec.DeclContainer, "type", loc);
2990 return typeof (UnexpectedType);
2996 return recursive_type;
2999 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
3001 Type t = TypeLookup (ec, name);
3003 NamespaceEntry.Error_NamespaceNotFound (loc, name);
3006 if (t == typeof(UnexpectedType))
3012 protected override void CloneTo (CloneContext clonectx, Expression target)
3014 // CloneTo: Nothing, we do not keep any state on this expression
3017 public override string GetSignatureForError ()
3020 return TypeManager.CSharpName (name);
3022 return base.GetSignatureForError ();
3027 /// Represents an "unbound generic type", ie. typeof (Foo<>).
3030 public class UnboundTypeExpression : TypeExpr
3034 public UnboundTypeExpression (MemberName name, Location l)
3040 protected override void CloneTo (CloneContext clonectx, Expression target)
3045 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
3048 if (name.Left != null) {
3049 Expression lexpr = name.Left.GetTypeExpression ();
3050 expr = new MemberAccess (lexpr, name.Basename);
3052 expr = new SimpleName (name.Basename, loc);
3055 FullNamedExpression fne = expr.ResolveAsTypeStep (ec, false);
3060 return new TypeExpression (type, loc);
3065 /// This class denotes an expression which evaluates to a member
3066 /// of a struct or a class.
3068 public abstract class MemberExpr : Expression
3070 protected bool is_base;
3073 /// The name of this member.
3075 public abstract string Name {
3080 // When base.member is used
3082 public bool IsBase {
3083 get { return is_base; }
3084 set { is_base = value; }
3088 /// Whether this is an instance member.
3090 public abstract bool IsInstance {
3095 /// Whether this is a static member.
3097 public abstract bool IsStatic {
3102 /// The type which declares this member.
3104 public abstract Type DeclaringType {
3109 /// The instance expression associated with this member, if it's a
3110 /// non-static member.
3112 public Expression InstanceExpression;
3114 public static void error176 (Location loc, string name)
3116 Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
3117 "with an instance reference, qualify it with a type name instead", name);
3120 // TODO: possible optimalization
3121 // Cache resolved constant result in FieldBuilder <-> expression map
3122 public virtual MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3123 SimpleName original)
3127 // original == null || original.Resolve (...) ==> left
3130 if (left is TypeExpr) {
3131 left = left.ResolveAsTypeTerminal (ec, true);
3136 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3144 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3147 return ResolveExtensionMemberAccess (left);
3150 InstanceExpression = left;
3154 protected virtual MemberExpr ResolveExtensionMemberAccess (Expression left)
3156 error176 (loc, GetSignatureForError ());
3160 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3165 if (InstanceExpression == EmptyExpression.Null) {
3166 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3170 if (InstanceExpression.Type.IsValueType) {
3171 if (InstanceExpression is IMemoryLocation) {
3172 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
3174 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
3175 InstanceExpression.Emit (ec);
3177 t.AddressOf (ec, AddressOp.Store);
3180 InstanceExpression.Emit (ec);
3182 if (prepare_for_load)
3183 ec.ig.Emit (OpCodes.Dup);
3186 public virtual void SetTypeArguments (TypeArguments ta)
3188 // TODO: need to get correct member type
3189 Report.Error (307, loc, "The property `{0}' cannot be used with type arguments",
3190 GetSignatureForError ());
3195 /// Represents group of extension methods
3197 public class ExtensionMethodGroupExpr : MethodGroupExpr
3199 readonly NamespaceEntry namespace_entry;
3200 public Expression ExtensionExpression;
3201 Argument extension_argument;
3203 public ExtensionMethodGroupExpr (ArrayList list, NamespaceEntry n, Type extensionType, Location l)
3204 : base (list, extensionType, l)
3206 this.namespace_entry = n;
3209 public override bool IsStatic {
3210 get { return true; }
3213 public bool IsTopLevel {
3214 get { return namespace_entry == null; }
3217 public override void EmitArguments (EmitContext ec, ArrayList arguments)
3219 if (arguments == null)
3220 arguments = new ArrayList (1);
3221 arguments.Insert (0, extension_argument);
3222 base.EmitArguments (ec, arguments);
3225 public override void EmitCall (EmitContext ec, ArrayList arguments)
3227 if (arguments == null)
3228 arguments = new ArrayList (1);
3229 arguments.Insert (0, extension_argument);
3230 base.EmitCall (ec, arguments);
3233 public override MethodGroupExpr OverloadResolve (EmitContext ec, ref ArrayList arguments, bool may_fail, Location loc)
3235 if (arguments == null)
3236 arguments = new ArrayList (1);
3238 arguments.Insert (0, new Argument (ExtensionExpression));
3239 MethodGroupExpr mg = ResolveOverloadExtensions (ec, arguments, namespace_entry, loc);
3241 // Store resolved argument and restore original arguments
3243 ((ExtensionMethodGroupExpr)mg).extension_argument = (Argument)arguments [0];
3244 arguments.RemoveAt (0);
3249 MethodGroupExpr ResolveOverloadExtensions (EmitContext ec, ArrayList arguments, NamespaceEntry ns, Location loc)
3251 // Use normal resolve rules
3252 MethodGroupExpr mg = base.OverloadResolve (ec, ref arguments, ns != null, loc);
3260 ExtensionMethodGroupExpr e = ns.LookupExtensionMethod (type, null, Name, loc);
3262 return base.OverloadResolve (ec, ref arguments, false, loc);
3264 e.ExtensionExpression = ExtensionExpression;
3265 return e.ResolveOverloadExtensions (ec, arguments, e.namespace_entry, loc);
3270 /// MethodGroupExpr represents a group of method candidates which
3271 /// can be resolved to the best method overload
3273 public class MethodGroupExpr : MemberExpr
3275 public interface IErrorHandler
3277 bool NoExactMatch (EmitContext ec, MethodBase method);
3280 public IErrorHandler CustomErrorHandler;
3281 public MethodBase [] Methods;
3282 MethodBase best_candidate;
3283 // TODO: make private
3284 public TypeArguments type_arguments;
3285 bool identical_type_name;
3288 public MethodGroupExpr (MemberInfo [] mi, Type type, Location l)
3291 Methods = new MethodBase [mi.Length];
3292 mi.CopyTo (Methods, 0);
3295 public MethodGroupExpr (ArrayList list, Type type, Location l)
3299 Methods = (MethodBase[])list.ToArray (typeof (MethodBase));
3301 foreach (MemberInfo m in list){
3302 if (!(m is MethodBase)){
3303 Console.WriteLine ("Name " + m.Name);
3304 Console.WriteLine ("Found a: " + m.GetType ().FullName);
3313 protected MethodGroupExpr (Type type, Location loc)
3316 eclass = ExprClass.MethodGroup;
3320 public override Type DeclaringType {
3323 // We assume that the top-level type is in the end
3325 return Methods [Methods.Length - 1].DeclaringType;
3326 //return Methods [0].DeclaringType;
3330 public Type DelegateType {
3332 delegate_type = value;
3336 public bool IdenticalTypeName {
3338 return identical_type_name;
3342 identical_type_name = value;
3346 public override string GetSignatureForError ()
3348 if (best_candidate != null)
3349 return TypeManager.CSharpSignature (best_candidate);
3351 return TypeManager.CSharpSignature (Methods [0]);
3354 public override string Name {
3356 return Methods [0].Name;
3360 public override bool IsInstance {
3362 if (best_candidate != null)
3363 return !best_candidate.IsStatic;
3365 foreach (MethodBase mb in Methods)
3373 public override bool IsStatic {
3375 if (best_candidate != null)
3376 return best_candidate.IsStatic;
3378 foreach (MethodBase mb in Methods)
3386 public static explicit operator ConstructorInfo (MethodGroupExpr mg)
3388 return (ConstructorInfo)mg.best_candidate;
3391 public static explicit operator MethodInfo (MethodGroupExpr mg)
3393 return (MethodInfo)mg.best_candidate;
3397 // 7.4.3.3 Better conversion from expression
3398 // Returns : 1 if a->p is better,
3399 // 2 if a->q is better,
3400 // 0 if neither is better
3402 static int BetterExpressionConversion (EmitContext ec, Argument a, Type p, Type q)
3404 Type argument_type = TypeManager.TypeToCoreType (a.Type);
3405 if (argument_type == TypeManager.anonymous_method_type && RootContext.Version > LanguageVersion.ISO_2) {
3407 // Uwrap delegate from Expression<T>
3409 if (TypeManager.DropGenericTypeArguments (p) == TypeManager.expression_type) {
3410 p = TypeManager.GetTypeArguments (p) [0];
3411 q = TypeManager.GetTypeArguments (q) [0];
3413 p = Delegate.GetInvokeMethod (null, p).ReturnType;
3414 q = Delegate.GetInvokeMethod (null, q).ReturnType;
3416 if (argument_type == p)
3419 if (argument_type == q)
3423 return BetterTypeConversion (ec, p, q);
3427 // 7.4.3.4 Better conversion from type
3429 public static int BetterTypeConversion (EmitContext ec, Type p, Type q)
3431 if (p == null || q == null)
3432 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3434 if (p == TypeManager.int32_type) {
3435 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3437 } else if (p == TypeManager.int64_type) {
3438 if (q == TypeManager.uint64_type)
3440 } else if (p == TypeManager.sbyte_type) {
3441 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3442 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3444 } else if (p == TypeManager.short_type) {
3445 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3446 q == TypeManager.uint64_type)
3450 if (q == TypeManager.int32_type) {
3451 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3453 } if (q == TypeManager.int64_type) {
3454 if (p == TypeManager.uint64_type)
3456 } else if (q == TypeManager.sbyte_type) {
3457 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3458 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3460 } if (q == TypeManager.short_type) {
3461 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3462 p == TypeManager.uint64_type)
3466 // TODO: this is expensive
3467 Expression p_tmp = new EmptyExpression (p);
3468 Expression q_tmp = new EmptyExpression (q);
3470 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3471 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3473 if (p_to_q && !q_to_p)
3476 if (q_to_p && !p_to_q)
3483 /// Determines "Better function" between candidate
3484 /// and the current best match
3487 /// Returns a boolean indicating :
3488 /// false if candidate ain't better
3489 /// true if candidate is better than the current best match
3491 static bool BetterFunction (EmitContext ec, ArrayList args, int argument_count,
3492 MethodBase candidate, bool candidate_params,
3493 MethodBase best, bool best_params)
3495 ParameterData candidate_pd = TypeManager.GetParameterData (candidate);
3496 ParameterData best_pd = TypeManager.GetParameterData (best);
3498 bool better_at_least_one = false;
3500 for (int j = 0, c_idx = 0, b_idx = 0; j < argument_count; ++j, ++c_idx, ++b_idx)
3502 Argument a = (Argument) args [j];
3504 Type ct = TypeManager.TypeToCoreType (candidate_pd.ParameterType (c_idx));
3505 Type bt = TypeManager.TypeToCoreType (best_pd.ParameterType (b_idx));
3507 if (candidate_params && candidate_pd.ParameterModifier (c_idx) == Parameter.Modifier.PARAMS)
3509 ct = TypeManager.GetElementType (ct);
3513 if (best_params && best_pd.ParameterModifier (b_idx) == Parameter.Modifier.PARAMS)
3515 bt = TypeManager.GetElementType (bt);
3523 int result = BetterExpressionConversion (ec, a, ct, bt);
3525 // for each argument, the conversion to 'ct' should be no worse than
3526 // the conversion to 'bt'.
3530 // for at least one argument, the conversion to 'ct' should be better than
3531 // the conversion to 'bt'.
3533 better_at_least_one = true;
3536 if (better_at_least_one)
3540 // This handles the case
3542 // Add (float f1, float f2, float f3);
3543 // Add (params decimal [] foo);
3545 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3546 // first candidate would've chosen as better.
3552 // The two methods have equal parameter types. Now apply tie-breaking rules
3554 if (TypeManager.IsGenericMethod (best) && !TypeManager.IsGenericMethod (candidate))
3556 if (!TypeManager.IsGenericMethod (best) && TypeManager.IsGenericMethod (candidate))
3560 // This handles the following cases:
3562 // Trim () is better than Trim (params char[] chars)
3563 // Concat (string s1, string s2, string s3) is better than
3564 // Concat (string s1, params string [] srest)
3565 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3567 if (!candidate_params && best_params)
3569 if (candidate_params && !best_params)
3572 int candidate_param_count = candidate_pd.Count;
3573 int best_param_count = best_pd.Count;
3575 if (candidate_param_count != best_param_count)
3576 // can only happen if (candidate_params && best_params)
3577 return candidate_param_count > best_param_count;
3580 // now, both methods have the same number of parameters, and the parameters have the same types
3581 // Pick the "more specific" signature
3584 MethodBase orig_candidate = TypeManager.DropGenericMethodArguments (candidate);
3585 MethodBase orig_best = TypeManager.DropGenericMethodArguments (best);
3587 ParameterData orig_candidate_pd = TypeManager.GetParameterData (orig_candidate);
3588 ParameterData orig_best_pd = TypeManager.GetParameterData (orig_best);
3590 bool specific_at_least_once = false;
3591 for (int j = 0; j < candidate_param_count; ++j)
3593 Type ct = TypeManager.TypeToCoreType (orig_candidate_pd.ParameterType (j));
3594 Type bt = TypeManager.TypeToCoreType (orig_best_pd.ParameterType (j));
3597 Type specific = MoreSpecific (ct, bt);
3601 specific_at_least_once = true;
3604 if (specific_at_least_once)
3607 // FIXME: handle lifted operators
3613 protected override MemberExpr ResolveExtensionMemberAccess (Expression left)
3616 return base.ResolveExtensionMemberAccess (left);
3619 // When left side is an expression and at least one candidate method is
3620 // static, it can be extension method
3622 InstanceExpression = left;
3626 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3627 SimpleName original)
3629 if (!(left is TypeExpr) &&
3630 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3631 IdenticalTypeName = true;
3633 return base.ResolveMemberAccess (ec, left, loc, original);
3636 public override Expression CreateExpressionTree (EmitContext ec)
3638 if (best_candidate.IsConstructor)
3639 return new TypeOfConstructorInfo (best_candidate, loc);
3641 return new TypeOfMethodInfo (best_candidate, loc);
3644 override public Expression DoResolve (EmitContext ec)
3646 if (InstanceExpression != null) {
3647 InstanceExpression = InstanceExpression.DoResolve (ec);
3648 if (InstanceExpression == null)
3655 public void ReportUsageError ()
3657 Report.Error (654, loc, "Method `" + DeclaringType + "." +
3658 Name + "()' is referenced without parentheses");
3661 override public void Emit (EmitContext ec)
3663 ReportUsageError ();
3666 public virtual void EmitArguments (EmitContext ec, ArrayList arguments)
3668 Invocation.EmitArguments (ec, arguments, false, null);
3671 public virtual void EmitCall (EmitContext ec, ArrayList arguments)
3673 Invocation.EmitCall (ec, IsBase, InstanceExpression, best_candidate, arguments, loc);
3676 protected virtual void Error_InvalidArguments (EmitContext ec, Location loc, int idx, MethodBase method,
3677 Argument a, ParameterData expected_par, Type paramType)
3679 if (a is CollectionElementInitializer.ElementInitializerArgument) {
3680 Report.SymbolRelatedToPreviousError (method);
3681 if ((expected_par.ParameterModifier (idx) & Parameter.Modifier.ISBYREF) != 0) {
3682 Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
3683 TypeManager.CSharpSignature (method));
3686 Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
3687 TypeManager.CSharpSignature (method));
3688 } else if (delegate_type == null) {
3689 Report.SymbolRelatedToPreviousError (method);
3690 Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
3691 TypeManager.CSharpSignature (method));
3693 Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
3694 TypeManager.CSharpName (delegate_type));
3696 Parameter.Modifier mod = expected_par.ParameterModifier (idx);
3698 string index = (idx + 1).ToString ();
3699 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
3700 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
3701 if ((mod & Parameter.Modifier.ISBYREF) == 0)
3702 Report.Error (1615, loc, "Argument `{0}' should not be passed with the `{1}' keyword",
3703 index, Parameter.GetModifierSignature (a.Modifier));
3705 Report.Error (1620, loc, "Argument `{0}' must be passed with the `{1}' keyword",
3706 index, Parameter.GetModifierSignature (mod));
3708 string p1 = a.GetSignatureForError ();
3709 string p2 = TypeManager.CSharpName (paramType);
3712 Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
3713 Report.SymbolRelatedToPreviousError (a.Expr.Type);
3714 Report.SymbolRelatedToPreviousError (paramType);
3716 Report.Error (1503, loc, "Argument {0}: Cannot convert type `{1}' to `{2}'", index, p1, p2);
3720 public override void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl)
3722 Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3723 Name, TypeManager.CSharpName (target));
3726 protected virtual int GetApplicableParametersCount (MethodBase method, ParameterData parameters)
3728 return parameters.Count;
3731 public static bool IsAncestralType (Type first_type, Type second_type)
3733 return first_type != second_type &&
3734 (TypeManager.IsSubclassOf (second_type, first_type) ||
3735 TypeManager.ImplementsInterface (second_type, first_type));
3739 /// Determines if the candidate method is applicable (section 14.4.2.1)
3740 /// to the given set of arguments
3741 /// A return value rates candidate method compatibility,
3742 /// 0 = the best, int.MaxValue = the worst
3744 public int IsApplicable (EmitContext ec,
3745 ArrayList arguments, int arg_count, ref MethodBase method, ref bool params_expanded_form)
3747 MethodBase candidate = method;
3749 ParameterData pd = TypeManager.GetParameterData (candidate);
3750 int param_count = GetApplicableParametersCount (candidate, pd);
3752 if (arg_count != param_count) {
3754 return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
3755 if (arg_count < param_count - 1)
3756 return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
3761 // 1. Handle generic method using type arguments when specified or type inference
3763 if (TypeManager.IsGenericMethod (candidate)) {
3764 if (type_arguments != null) {
3765 Type [] g_args = candidate.GetGenericArguments ();
3766 if (g_args.Length != type_arguments.Count)
3767 return int.MaxValue - 20000 + Math.Abs (type_arguments.Count - g_args.Length);
3769 // TODO: Don't create new method, create Parameters only
3770 method = ((MethodInfo) candidate).MakeGenericMethod (type_arguments.Arguments);
3772 pd = TypeManager.GetParameterData (candidate);
3774 int score = TypeManager.InferTypeArguments (ec, arguments, ref candidate);
3776 return score - 20000;
3778 if (TypeManager.IsGenericMethodDefinition (candidate))
3779 throw new InternalErrorException ("A generic method `{0}' definition took part in overload resolution",
3780 TypeManager.CSharpSignature (candidate));
3782 pd = TypeManager.GetParameterData (candidate);
3785 if (type_arguments != null)
3786 return int.MaxValue - 15000;
3791 // 2. Each argument has to be implicitly convertible to method parameter
3794 Parameter.Modifier p_mod = 0;
3796 for (int i = 0; i < arg_count; i++) {
3797 Argument a = (Argument) arguments [i];
3798 Parameter.Modifier a_mod = a.Modifier &
3799 ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3801 if (p_mod != Parameter.Modifier.PARAMS) {
3802 p_mod = pd.ParameterModifier (i) & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3804 if (p_mod == Parameter.Modifier.ARGLIST) {
3805 if (a.Type == TypeManager.runtime_argument_handle_type)
3811 pt = pd.ParameterType (i);
3813 params_expanded_form = true;
3817 if (!params_expanded_form)
3818 score = IsArgumentCompatible (ec, a_mod, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
3820 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0) {
3821 // It can be applicable in expanded form
3822 score = IsArgumentCompatible (ec, a_mod, a, 0, pt.GetElementType ());
3824 params_expanded_form = true;
3828 if (params_expanded_form)
3830 return (arg_count - i) * 2 + score;
3834 if (arg_count != param_count)
3835 params_expanded_form = true;
3840 int IsArgumentCompatible (EmitContext ec, Parameter.Modifier arg_mod, Argument argument, Parameter.Modifier param_mod, Type parameter)
3843 // Types have to be identical when ref or out modifer is used
3845 if (arg_mod != 0 || param_mod != 0) {
3846 if (TypeManager.HasElementType (parameter))
3847 parameter = parameter.GetElementType ();
3849 Type a_type = argument.Type;
3850 if (TypeManager.HasElementType (a_type))
3851 a_type = a_type.GetElementType ();
3853 if (a_type != parameter)
3859 // FIXME: Kill this abomination (EmitContext.TempEc)
3860 EmitContext prevec = EmitContext.TempEc;
3861 EmitContext.TempEc = ec;
3863 if (delegate_type != null ?
3864 !Delegate.IsTypeCovariant (argument.Expr, parameter) :
3865 !Convert.ImplicitConversionExists (ec, argument.Expr, parameter))
3868 if (arg_mod != param_mod)
3872 EmitContext.TempEc = prevec;
3878 public static bool IsOverride (MethodBase cand_method, MethodBase base_method)
3880 if (!IsAncestralType (base_method.DeclaringType, cand_method.DeclaringType))
3883 ParameterData cand_pd = TypeManager.GetParameterData (cand_method);
3884 ParameterData base_pd = TypeManager.GetParameterData (base_method);
3886 if (cand_pd.Count != base_pd.Count)
3889 for (int j = 0; j < cand_pd.Count; ++j)
3891 Parameter.Modifier cm = cand_pd.ParameterModifier (j);
3892 Parameter.Modifier bm = base_pd.ParameterModifier (j);
3893 Type ct = TypeManager.TypeToCoreType (cand_pd.ParameterType (j));
3894 Type bt = TypeManager.TypeToCoreType (base_pd.ParameterType (j));
3896 if (cm != bm || ct != bt)
3903 public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2, Location loc)
3905 MemberInfo [] miset;
3906 MethodGroupExpr union;
3911 return (MethodGroupExpr) mg2;
3914 return (MethodGroupExpr) mg1;
3917 MethodGroupExpr left_set = null, right_set = null;
3918 int length1 = 0, length2 = 0;
3920 left_set = (MethodGroupExpr) mg1;
3921 length1 = left_set.Methods.Length;
3923 right_set = (MethodGroupExpr) mg2;
3924 length2 = right_set.Methods.Length;
3926 ArrayList common = new ArrayList ();
3928 foreach (MethodBase r in right_set.Methods){
3929 if (TypeManager.ArrayContainsMethod (left_set.Methods, r))
3933 miset = new MemberInfo [length1 + length2 - common.Count];
3934 left_set.Methods.CopyTo (miset, 0);
3938 foreach (MethodBase r in right_set.Methods) {
3939 if (!common.Contains (r))
3943 union = new MethodGroupExpr (miset, mg1.Type, loc);
3948 static Type MoreSpecific (Type p, Type q)
3950 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
3952 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
3955 if (TypeManager.HasElementType (p))
3957 Type pe = TypeManager.GetElementType (p);
3958 Type qe = TypeManager.GetElementType (q);
3959 Type specific = MoreSpecific (pe, qe);
3965 else if (TypeManager.IsGenericType (p))
3967 Type[] pargs = TypeManager.GetTypeArguments (p);
3968 Type[] qargs = TypeManager.GetTypeArguments (q);
3970 bool p_specific_at_least_once = false;
3971 bool q_specific_at_least_once = false;
3973 for (int i = 0; i < pargs.Length; i++)
3975 Type specific = MoreSpecific (pargs [i], qargs [i]);
3976 if (specific == pargs [i])
3977 p_specific_at_least_once = true;
3978 if (specific == qargs [i])
3979 q_specific_at_least_once = true;
3982 if (p_specific_at_least_once && !q_specific_at_least_once)
3984 if (!p_specific_at_least_once && q_specific_at_least_once)
3992 /// Find the Applicable Function Members (7.4.2.1)
3994 /// me: Method Group expression with the members to select.
3995 /// it might contain constructors or methods (or anything
3996 /// that maps to a method).
3998 /// Arguments: ArrayList containing resolved Argument objects.
4000 /// loc: The location if we want an error to be reported, or a Null
4001 /// location for "probing" purposes.
4003 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4004 /// that is the best match of me on Arguments.
4007 public virtual MethodGroupExpr OverloadResolve (EmitContext ec, ref ArrayList Arguments,
4008 bool may_fail, Location loc)
4010 bool method_params = false;
4011 Type applicable_type = null;
4013 ArrayList candidates = new ArrayList (2);
4014 ArrayList candidate_overrides = null;
4017 // Used to keep a map between the candidate
4018 // and whether it is being considered in its
4019 // normal or expanded form
4021 // false is normal form, true is expanded form
4023 Hashtable candidate_to_form = null;
4025 if (Arguments != null)
4026 arg_count = Arguments.Count;
4028 if (RootContext.Version == LanguageVersion.ISO_1 && Name == "Invoke" && TypeManager.IsDelegateType (DeclaringType)) {
4030 Report.Error (1533, loc, "Invoke cannot be called directly on a delegate");
4034 int nmethods = Methods.Length;
4038 // Methods marked 'override' don't take part in 'applicable_type'
4039 // computation, nor in the actual overload resolution.
4040 // However, they still need to be emitted instead of a base virtual method.
4041 // So, we salt them away into the 'candidate_overrides' array.
4043 // In case of reflected methods, we replace each overriding method with
4044 // its corresponding base virtual method. This is to improve compatibility
4045 // with non-C# libraries which change the visibility of overrides (#75636)
4048 for (int i = 0; i < Methods.Length; ++i) {
4049 MethodBase m = Methods [i];
4050 if (TypeManager.IsOverride (m)) {
4051 if (candidate_overrides == null)
4052 candidate_overrides = new ArrayList ();
4053 candidate_overrides.Add (m);
4054 m = TypeManager.TryGetBaseDefinition (m);
4063 // Enable message recording, it's used mainly by lambda expressions
4065 Report.IMessageRecorder msg_recorder = new Report.MessageRecorder ();
4066 Report.IMessageRecorder prev_recorder = Report.SetMessageRecorder (msg_recorder);
4069 // First we construct the set of applicable methods
4071 bool is_sorted = true;
4072 int best_candidate_rate = int.MaxValue;
4073 for (int i = 0; i < nmethods; i++) {
4074 Type decl_type = Methods [i].DeclaringType;
4077 // If we have already found an applicable method
4078 // we eliminate all base types (Section 14.5.5.1)
4080 if (applicable_type != null && IsAncestralType (decl_type, applicable_type))
4084 // Check if candidate is applicable (section 14.4.2.1)
4086 bool params_expanded_form = false;
4087 int candidate_rate = IsApplicable (ec, Arguments, arg_count, ref Methods [i], ref params_expanded_form);
4089 if (candidate_rate < best_candidate_rate) {
4090 best_candidate_rate = candidate_rate;
4091 best_candidate = Methods [i];
4094 if (params_expanded_form) {
4095 if (candidate_to_form == null)
4096 candidate_to_form = new PtrHashtable ();
4097 MethodBase candidate = Methods [i];
4098 candidate_to_form [candidate] = candidate;
4101 if (candidate_rate != 0) {
4102 if (msg_recorder != null)
4103 msg_recorder.EndSession ();
4107 msg_recorder = null;
4108 candidates.Add (Methods [i]);
4110 if (applicable_type == null)
4111 applicable_type = decl_type;
4112 else if (applicable_type != decl_type) {
4114 if (IsAncestralType (applicable_type, decl_type))
4115 applicable_type = decl_type;
4119 Report.SetMessageRecorder (prev_recorder);
4120 if (msg_recorder != null && msg_recorder.PrintMessages ())
4123 int candidate_top = candidates.Count;
4125 if (applicable_type == null) {
4127 // When we found a top level method which does not match and it's
4128 // not an extension method. We start extension methods lookup from here
4130 if (InstanceExpression != null) {
4131 ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (type, Name, loc);
4132 if (ex_method_lookup != null) {
4133 ex_method_lookup.ExtensionExpression = InstanceExpression;
4134 ex_method_lookup.SetTypeArguments (type_arguments);
4135 return ex_method_lookup.OverloadResolve (ec, ref Arguments, may_fail, loc);
4143 // Okay so we have failed to find exact match so we
4144 // return error info about the closest match
4146 if (best_candidate != null) {
4147 if (CustomErrorHandler != null) {
4148 if (CustomErrorHandler.NoExactMatch (ec, best_candidate))
4152 ParameterData pd = TypeManager.GetParameterData (best_candidate);
4153 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4154 if (arg_count == pd.Count || pd.HasParams) {
4155 if (TypeManager.IsGenericMethodDefinition (best_candidate)) {
4156 if (type_arguments == null) {
4157 Report.Error (411, loc,
4158 "The type arguments for method `{0}' cannot be inferred from " +
4159 "the usage. Try specifying the type arguments explicitly",
4160 TypeManager.CSharpSignature (best_candidate));
4164 Type [] g_args = TypeManager.GetGenericArguments (best_candidate);
4165 if (type_arguments.Count != g_args.Length) {
4166 Report.SymbolRelatedToPreviousError (best_candidate);
4167 Report.Error (305, loc, "Using the generic method `{0}' requires `{1}' type argument(s)",
4168 TypeManager.CSharpSignature (best_candidate),
4169 g_args.Length.ToString ());
4173 if (type_arguments != null && !TypeManager.IsGenericMethod (best_candidate)) {
4174 Namespace.Error_TypeArgumentsCannotBeUsed (best_candidate, loc);
4179 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate, cand_params, may_fail, loc))
4184 if (almost_matched_members.Count != 0) {
4185 Error_MemberLookupFailed (ec.ContainerType, type, type, ".ctor",
4186 null, MemberTypes.Constructor, AllBindingFlags);
4191 // We failed to find any method with correct argument count
4193 if (Name == ConstructorInfo.ConstructorName) {
4194 Report.SymbolRelatedToPreviousError (type);
4195 Report.Error (1729, loc,
4196 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4197 TypeManager.CSharpName (type), arg_count);
4199 Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4200 Name, arg_count.ToString ());
4208 // At this point, applicable_type is _one_ of the most derived types
4209 // in the set of types containing the methods in this MethodGroup.
4210 // Filter the candidates so that they only contain methods from the
4211 // most derived types.
4214 int finalized = 0; // Number of finalized candidates
4217 // Invariant: applicable_type is a most derived type
4219 // We'll try to complete Section 14.5.5.1 for 'applicable_type' by
4220 // eliminating all it's base types. At the same time, we'll also move
4221 // every unrelated type to the end of the array, and pick the next
4222 // 'applicable_type'.
4224 Type next_applicable_type = null;
4225 int j = finalized; // where to put the next finalized candidate
4226 int k = finalized; // where to put the next undiscarded candidate
4227 for (int i = finalized; i < candidate_top; ++i) {
4228 MethodBase candidate = (MethodBase) candidates [i];
4229 Type decl_type = candidate.DeclaringType;
4231 if (decl_type == applicable_type) {
4232 candidates [k++] = candidates [j];
4233 candidates [j++] = candidates [i];
4237 if (IsAncestralType (decl_type, applicable_type))
4240 if (next_applicable_type != null &&
4241 IsAncestralType (decl_type, next_applicable_type))
4244 candidates [k++] = candidates [i];
4246 if (next_applicable_type == null ||
4247 IsAncestralType (next_applicable_type, decl_type))
4248 next_applicable_type = decl_type;
4251 applicable_type = next_applicable_type;
4254 } while (applicable_type != null);
4258 // Now we actually find the best method
4261 best_candidate = (MethodBase) candidates [0];
4262 if (delegate_type == null)
4263 method_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4265 for (int ix = 1; ix < candidate_top; ix++) {
4266 MethodBase candidate = (MethodBase) candidates [ix];
4268 if (candidate == best_candidate)
4271 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4273 if (BetterFunction (ec, Arguments, arg_count,
4274 candidate, cand_params,
4275 best_candidate, method_params)) {
4276 best_candidate = candidate;
4277 method_params = cand_params;
4281 // Now check that there are no ambiguities i.e the selected method
4282 // should be better than all the others
4284 MethodBase ambiguous = null;
4285 for (int ix = 1; ix < candidate_top; ix++) {
4286 MethodBase candidate = (MethodBase) candidates [ix];
4288 if (candidate == best_candidate)
4291 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4292 if (!BetterFunction (ec, Arguments, arg_count,
4293 best_candidate, method_params,
4294 candidate, cand_params))
4297 Report.SymbolRelatedToPreviousError (candidate);
4298 ambiguous = candidate;
4302 if (ambiguous != null) {
4303 Report.SymbolRelatedToPreviousError (best_candidate);
4304 Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4305 TypeManager.CSharpSignature (ambiguous), TypeManager.CSharpSignature (best_candidate));
4310 // If the method is a virtual function, pick an override closer to the LHS type.
4312 if (!IsBase && best_candidate.IsVirtual) {
4313 if (TypeManager.IsOverride (best_candidate))
4314 throw new InternalErrorException (
4315 "Should not happen. An 'override' method took part in overload resolution: " + best_candidate);
4317 if (candidate_overrides != null) {
4318 Type[] gen_args = null;
4319 bool gen_override = false;
4320 if (TypeManager.IsGenericMethod (best_candidate))
4321 gen_args = TypeManager.GetGenericArguments (best_candidate);
4323 foreach (MethodBase candidate in candidate_overrides) {
4324 if (TypeManager.IsGenericMethod (candidate)) {
4325 if (gen_args == null)
4328 if (gen_args.Length != TypeManager.GetGenericArguments (candidate).Length)
4331 if (gen_args != null)
4335 if (IsOverride (candidate, best_candidate)) {
4336 gen_override = true;
4337 best_candidate = candidate;
4341 if (gen_override && gen_args != null) {
4343 best_candidate = ((MethodInfo) best_candidate).MakeGenericMethod (gen_args);
4350 // And now check if the arguments are all
4351 // compatible, perform conversions if
4352 // necessary etc. and return if everything is
4355 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate,
4356 method_params, may_fail, loc))
4359 if (best_candidate == null)
4362 MethodBase the_method = TypeManager.DropGenericMethodArguments (best_candidate);
4364 if (the_method.IsGenericMethodDefinition &&
4365 !ConstraintChecker.CheckConstraints (ec, the_method, best_candidate, loc))
4369 IMethodData data = TypeManager.GetMethod (the_method);
4371 data.SetMemberIsUsed ();
4376 public override void SetTypeArguments (TypeArguments ta)
4378 type_arguments = ta;
4381 public bool VerifyArgumentsCompat (EmitContext ec, ref ArrayList arguments,
4382 int arg_count, MethodBase method,
4383 bool chose_params_expanded,
4384 bool may_fail, Location loc)
4386 ParameterData pd = TypeManager.GetParameterData (method);
4388 int errors = Report.Errors;
4389 Parameter.Modifier p_mod = 0;
4391 int a_idx = 0, a_pos = 0;
4393 ArrayList params_initializers = null;
4395 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4396 a = (Argument) arguments [a_idx];
4397 if (p_mod != Parameter.Modifier.PARAMS) {
4398 p_mod = pd.ParameterModifier (a_idx);
4399 pt = pd.ParameterType (a_idx);
4401 if (p_mod == Parameter.Modifier.ARGLIST) {
4402 if (a.Type != TypeManager.runtime_argument_handle_type)
4407 if (pt.IsPointer && !ec.InUnsafe) {
4414 if (p_mod == Parameter.Modifier.PARAMS) {
4415 if (chose_params_expanded) {
4416 params_initializers = new ArrayList (arg_count - a_idx);
4417 pt = TypeManager.GetElementType (pt);
4419 } else if (p_mod != 0) {
4420 pt = TypeManager.GetElementType (pt);
4425 // Types have to be identical when ref or out modifer is used
4427 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4428 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4431 if (!TypeManager.IsEqual (a.Expr.Type, pt))
4438 if (TypeManager.IsEqual (a.Type, pt)) {
4441 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4447 // Convert params arguments to an array initializer
4449 if (params_initializers != null) {
4450 // we choose to use 'a.Expr' rather than 'conv' so that
4451 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
4452 params_initializers.Add (a.Expr);
4453 arguments.RemoveAt (a_idx--);
4458 // Update the argument with the implicit conversion
4463 // Fill not provided arguments required by params modifier
4465 if (params_initializers == null && pd.HasParams && arg_count < pd.Count && a_idx + 1 == pd.Count) {
4466 if (arguments == null)
4467 arguments = new ArrayList (1);
4469 pt = pd.Types [GetApplicableParametersCount (method, pd) - 1];
4470 pt = TypeManager.GetElementType (pt);
4471 params_initializers = new ArrayList (0);
4474 if (a_idx == arg_count) {
4476 // Append an array argument with all params arguments
4478 if (params_initializers != null) {
4479 arguments.Add (new Argument (
4480 new ArrayCreation (new TypeExpression (pt, loc), "[]",
4481 params_initializers, loc).Resolve (ec)));
4486 if (!may_fail && Report.Errors == errors) {
4487 if (CustomErrorHandler != null)
4488 CustomErrorHandler.NoExactMatch (ec, best_candidate);
4490 Error_InvalidArguments (ec, loc, a_pos, method, a, pd, pt);
4496 public class ConstantExpr : MemberExpr
4500 public ConstantExpr (FieldInfo constant, Location loc)
4502 this.constant = constant;
4506 public override string Name {
4507 get { throw new NotImplementedException (); }
4510 public override bool IsInstance {
4511 get { return !IsStatic; }
4514 public override bool IsStatic {
4515 get { return constant.IsStatic; }
4518 public override Type DeclaringType {
4519 get { return constant.DeclaringType; }
4522 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc, SimpleName original)
4524 constant = TypeManager.GetGenericFieldDefinition (constant);
4526 IConstant ic = TypeManager.GetConstant (constant);
4528 if (constant.IsLiteral) {
4529 ic = new ExternalConstant (constant);
4531 ic = ExternalConstant.CreateDecimal (constant);
4532 // HACK: decimal field was not resolved as constant
4534 return new FieldExpr (constant, loc).ResolveMemberAccess (ec, left, loc, original);
4536 TypeManager.RegisterConstant (constant, ic);
4539 return base.ResolveMemberAccess (ec, left, loc, original);
4542 public override Expression CreateExpressionTree (EmitContext ec)
4544 throw new NotSupportedException ("ET");
4547 public override Expression DoResolve (EmitContext ec)
4549 IConstant ic = TypeManager.GetConstant (constant);
4550 if (ic.ResolveValue ()) {
4551 if (!ec.IsInObsoleteScope)
4552 ic.CheckObsoleteness (loc);
4555 return ic.CreateConstantReference (loc);
4558 public override void Emit (EmitContext ec)
4560 throw new NotSupportedException ();
4563 public override string GetSignatureForError ()
4565 return TypeManager.GetFullNameSignature (constant);
4570 /// Fully resolved expression that evaluates to a Field
4572 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariable {
4573 public readonly FieldInfo FieldInfo;
4574 VariableInfo variable_info;
4576 LocalTemporary temp;
4578 bool in_initializer;
4580 public FieldExpr (FieldInfo fi, Location l, bool in_initializer):
4583 this.in_initializer = in_initializer;
4586 public FieldExpr (FieldInfo fi, Location l)
4589 eclass = ExprClass.Variable;
4590 type = TypeManager.TypeToCoreType (fi.FieldType);
4594 public override string Name {
4596 return FieldInfo.Name;
4600 public override bool IsInstance {
4602 return !FieldInfo.IsStatic;
4606 public override bool IsStatic {
4608 return FieldInfo.IsStatic;
4612 public override Type DeclaringType {
4614 return FieldInfo.DeclaringType;
4618 public override string GetSignatureForError ()
4620 return TypeManager.GetFullNameSignature (FieldInfo);
4623 public VariableInfo VariableInfo {
4625 return variable_info;
4629 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
4630 SimpleName original)
4632 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
4633 Type t = fi.FieldType;
4635 if (t.IsPointer && !ec.InUnsafe) {
4639 return base.ResolveMemberAccess (ec, left, loc, original);
4642 public override Expression CreateExpressionTree (EmitContext ec)
4644 Expression instance;
4645 if (InstanceExpression == null) {
4646 instance = new NullLiteral (loc);
4648 instance = InstanceExpression.CreateExpressionTree (ec);
4651 ArrayList args = new ArrayList (2);
4652 args.Add (new Argument (instance));
4653 args.Add (new Argument (CreateTypeOfExpression ()));
4654 return CreateExpressionFactoryCall ("Field", args);
4657 public Expression CreateTypeOfExpression ()
4659 return new TypeOfField (FieldInfo, loc);
4662 override public Expression DoResolve (EmitContext ec)
4664 return DoResolve (ec, false, false);
4667 Expression DoResolve (EmitContext ec, bool lvalue_instance, bool out_access)
4669 if (!FieldInfo.IsStatic){
4670 if (InstanceExpression == null){
4672 // This can happen when referencing an instance field using
4673 // a fully qualified type expression: TypeName.InstanceField = xxx
4675 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4679 // Resolve the field's instance expression while flow analysis is turned
4680 // off: when accessing a field "a.b", we must check whether the field
4681 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4683 if (lvalue_instance) {
4684 using (ec.With (EmitContext.Flags.DoFlowAnalysis, false)) {
4685 Expression right_side =
4686 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4687 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side, loc);
4690 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
4691 InstanceExpression = InstanceExpression.Resolve (ec, rf);
4694 if (InstanceExpression == null)
4697 using (ec.Set (EmitContext.Flags.OmitStructFlowAnalysis)) {
4698 InstanceExpression.CheckMarshalByRefAccess (ec);
4702 if (!in_initializer && !ec.IsInFieldInitializer) {
4703 ObsoleteAttribute oa;
4704 FieldBase f = TypeManager.GetField (FieldInfo);
4706 if (!ec.IsInObsoleteScope)
4707 f.CheckObsoleteness (loc);
4709 // To be sure that type is external because we do not register generated fields
4710 } else if (!(FieldInfo.DeclaringType is TypeBuilder)) {
4711 oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
4713 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
4717 AnonymousContainer am = ec.CurrentAnonymousMethod;
4719 if (!FieldInfo.IsStatic){
4720 if (!am.IsIterator && (ec.TypeContainer is Struct)){
4721 Report.Error (1673, loc,
4722 "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",
4729 IFixedBuffer fb = AttributeTester.GetFixedBuffer (FieldInfo);
4731 if (!ec.InFixedInitializer && ec.ContainerType.IsValueType) {
4732 Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4735 if (InstanceExpression.eclass != ExprClass.Variable) {
4736 Report.SymbolRelatedToPreviousError (FieldInfo);
4737 Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4738 TypeManager.GetFullNameSignature (FieldInfo));
4741 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4744 // If the instance expression is a local variable or parameter.
4745 IVariable var = InstanceExpression as IVariable;
4746 if ((var == null) || (var.VariableInfo == null))
4749 VariableInfo vi = var.VariableInfo;
4750 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
4753 variable_info = vi.GetSubStruct (FieldInfo.Name);
4757 static readonly int [] codes = {
4758 191, // instance, write access
4759 192, // instance, out access
4760 198, // static, write access
4761 199, // static, out access
4762 1648, // member of value instance, write access
4763 1649, // member of value instance, out access
4764 1650, // member of value static, write access
4765 1651 // member of value static, out access
4768 static readonly string [] msgs = {
4769 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4770 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4771 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4772 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4773 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4774 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4775 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4776 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4779 // The return value is always null. Returning a value simplifies calling code.
4780 Expression Report_AssignToReadonly (Expression right_side)
4783 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4787 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4789 Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4794 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4796 IVariable var = InstanceExpression as IVariable;
4797 if ((var != null) && (var.VariableInfo != null))
4798 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
4800 bool lvalue_instance = !FieldInfo.IsStatic && FieldInfo.DeclaringType.IsValueType;
4801 bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
4803 Expression e = DoResolve (ec, lvalue_instance, out_access);
4808 FieldBase fb = TypeManager.GetField (FieldInfo);
4812 if (FieldInfo.IsInitOnly) {
4813 // InitOnly fields can only be assigned in constructors or initializers
4814 if (!ec.IsInFieldInitializer && !ec.IsConstructor)
4815 return Report_AssignToReadonly (right_side);
4817 if (ec.IsConstructor) {
4818 Type ctype = ec.TypeContainer.CurrentType;
4820 ctype = ec.ContainerType;
4822 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4823 if (!TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
4824 return Report_AssignToReadonly (right_side);
4825 // static InitOnly fields cannot be assigned-to in an instance constructor
4826 if (IsStatic && !ec.IsStatic)
4827 return Report_AssignToReadonly (right_side);
4828 // instance constructors can't modify InitOnly fields of other instances of the same type
4829 if (!IsStatic && !(InstanceExpression is This))
4830 return Report_AssignToReadonly (right_side);
4834 if (right_side == EmptyExpression.OutAccess &&
4835 !IsStatic && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type)) {
4836 Report.SymbolRelatedToPreviousError (DeclaringType);
4837 Report.Warning (197, 1, loc,
4838 "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",
4839 GetSignatureForError ());
4845 bool is_marshal_by_ref ()
4847 return !IsStatic && Type.IsValueType && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type);
4850 public override void CheckMarshalByRefAccess (EmitContext ec)
4852 if (is_marshal_by_ref () && !(InstanceExpression is This)) {
4853 Report.SymbolRelatedToPreviousError (DeclaringType);
4854 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",
4855 GetSignatureForError ());
4859 public bool VerifyFixed ()
4861 IVariable variable = InstanceExpression as IVariable;
4862 // A variable of the form V.I is fixed when V is a fixed variable of a struct type.
4863 // We defer the InstanceExpression check after the variable check to avoid a
4864 // separate null check on InstanceExpression.
4865 return variable != null && InstanceExpression.Type.IsValueType && variable.VerifyFixed ();
4868 public override int GetHashCode ()
4870 return FieldInfo.GetHashCode ();
4873 public override bool Equals (object obj)
4875 FieldExpr fe = obj as FieldExpr;
4879 if (FieldInfo != fe.FieldInfo)
4882 if (InstanceExpression == null || fe.InstanceExpression == null)
4885 return InstanceExpression.Equals (fe.InstanceExpression);
4888 public void Emit (EmitContext ec, bool leave_copy)
4890 ILGenerator ig = ec.ig;
4891 bool is_volatile = false;
4893 FieldBase f = TypeManager.GetField (FieldInfo);
4895 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4898 f.SetMemberIsUsed ();
4901 if (FieldInfo.IsStatic){
4903 ig.Emit (OpCodes.Volatile);
4905 ig.Emit (OpCodes.Ldsfld, FieldInfo);
4908 EmitInstance (ec, false);
4910 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
4912 ig.Emit (OpCodes.Ldflda, FieldInfo);
4913 ig.Emit (OpCodes.Ldflda, ff.Element);
4916 ig.Emit (OpCodes.Volatile);
4918 ig.Emit (OpCodes.Ldfld, FieldInfo);
4923 ec.ig.Emit (OpCodes.Dup);
4924 if (!FieldInfo.IsStatic) {
4925 temp = new LocalTemporary (this.Type);
4931 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4933 FieldAttributes fa = FieldInfo.Attributes;
4934 bool is_static = (fa & FieldAttributes.Static) != 0;
4935 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
4936 ILGenerator ig = ec.ig;
4938 if (is_readonly && !ec.IsConstructor){
4939 Report_AssignToReadonly (source);
4943 prepared = prepare_for_load;
4944 EmitInstance (ec, prepared);
4948 ec.ig.Emit (OpCodes.Dup);
4949 if (!FieldInfo.IsStatic) {
4950 temp = new LocalTemporary (this.Type);
4955 FieldBase f = TypeManager.GetField (FieldInfo);
4957 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4958 ig.Emit (OpCodes.Volatile);
4964 ig.Emit (OpCodes.Stsfld, FieldInfo);
4966 ig.Emit (OpCodes.Stfld, FieldInfo);
4974 public override void Emit (EmitContext ec)
4979 public override void EmitSideEffect (EmitContext ec)
4981 FieldBase f = TypeManager.GetField (FieldInfo);
4982 bool is_volatile = f != null && (f.ModFlags & Modifiers.VOLATILE) != 0;
4984 if (is_volatile || is_marshal_by_ref ())
4985 base.EmitSideEffect (ec);
4988 public void AddressOf (EmitContext ec, AddressOp mode)
4990 ILGenerator ig = ec.ig;
4992 FieldBase f = TypeManager.GetField (FieldInfo);
4994 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
4995 Report.Warning (420, 1, loc, "`{0}': A volatile field references will not be treated as volatile",
4996 f.GetSignatureForError ());
4999 if ((mode & AddressOp.Store) != 0)
5001 if ((mode & AddressOp.Load) != 0)
5002 f.SetMemberIsUsed ();
5006 // Handle initonly fields specially: make a copy and then
5007 // get the address of the copy.
5010 if (FieldInfo.IsInitOnly){
5012 if (ec.IsConstructor){
5013 if (FieldInfo.IsStatic){
5025 local = ig.DeclareLocal (type);
5026 ig.Emit (OpCodes.Stloc, local);
5027 ig.Emit (OpCodes.Ldloca, local);
5032 if (FieldInfo.IsStatic){
5033 ig.Emit (OpCodes.Ldsflda, FieldInfo);
5036 EmitInstance (ec, false);
5037 ig.Emit (OpCodes.Ldflda, FieldInfo);
5044 /// Expression that evaluates to a Property. The Assign class
5045 /// might set the `Value' expression if we are in an assignment.
5047 /// This is not an LValue because we need to re-write the expression, we
5048 /// can not take data from the stack and store it.
5050 public class PropertyExpr : MemberExpr, IAssignMethod {
5051 public readonly PropertyInfo PropertyInfo;
5052 MethodInfo getter, setter;
5057 LocalTemporary temp;
5060 public PropertyExpr (Type container_type, PropertyInfo pi, Location l)
5063 eclass = ExprClass.PropertyAccess;
5067 type = TypeManager.TypeToCoreType (pi.PropertyType);
5069 ResolveAccessors (container_type);
5072 public override string Name {
5074 return PropertyInfo.Name;
5078 public override bool IsInstance {
5084 public override bool IsStatic {
5090 public override Expression CreateExpressionTree (EmitContext ec)
5092 if (IsSingleDimensionalArrayLength ()) {
5093 ArrayList args = new ArrayList (1);
5094 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5095 return CreateExpressionFactoryCall ("ArrayLength", args);
5098 // TODO: it's waiting for PropertyExpr refactoring
5099 //ArrayList args = new ArrayList (2);
5100 //args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5101 //args.Add (getter expression);
5102 //return CreateExpressionFactoryCall ("Property", args);
5103 return base.CreateExpressionTree (ec);
5106 public Expression CreateSetterTypeOfExpression ()
5108 return new TypeOfMethodInfo (setter, loc);
5111 public override Type DeclaringType {
5113 return PropertyInfo.DeclaringType;
5117 public override string GetSignatureForError ()
5119 return TypeManager.GetFullNameSignature (PropertyInfo);
5122 void FindAccessors (Type invocation_type)
5124 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
5125 BindingFlags.Static | BindingFlags.Instance |
5126 BindingFlags.DeclaredOnly;
5128 Type current = PropertyInfo.DeclaringType;
5129 for (; current != null; current = current.BaseType) {
5130 MemberInfo[] group = TypeManager.MemberLookup (
5131 invocation_type, invocation_type, current,
5132 MemberTypes.Property, flags, PropertyInfo.Name, null);
5137 if (group.Length != 1)
5138 // Oooops, can this ever happen ?
5141 PropertyInfo pi = (PropertyInfo) group [0];
5144 getter = pi.GetGetMethod (true);
5147 setter = pi.GetSetMethod (true);
5149 MethodInfo accessor = getter != null ? getter : setter;
5151 if (!accessor.IsVirtual)
5157 // We also perform the permission checking here, as the PropertyInfo does not
5158 // hold the information for the accessibility of its setter/getter
5160 // TODO: Refactor to use some kind of cache together with GetPropertyFromAccessor
5161 void ResolveAccessors (Type container_type)
5163 FindAccessors (container_type);
5165 if (getter != null) {
5166 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
5167 IMethodData md = TypeManager.GetMethod (the_getter);
5169 md.SetMemberIsUsed ();
5171 is_static = getter.IsStatic;
5174 if (setter != null) {
5175 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
5176 IMethodData md = TypeManager.GetMethod (the_setter);
5178 md.SetMemberIsUsed ();
5180 is_static = setter.IsStatic;
5184 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
5187 InstanceExpression = null;
5191 if (InstanceExpression == null) {
5192 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5196 InstanceExpression = InstanceExpression.DoResolve (ec);
5197 if (lvalue_instance && InstanceExpression != null)
5198 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
5200 if (InstanceExpression == null)
5203 InstanceExpression.CheckMarshalByRefAccess (ec);
5205 if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) &&
5206 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
5207 !TypeManager.IsNestedChildOf (ec.ContainerType, InstanceExpression.Type) &&
5208 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.ContainerType)) {
5209 Report.SymbolRelatedToPreviousError (PropertyInfo);
5210 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
5217 void Error_PropertyNotFound (MethodInfo mi, bool getter)
5219 // TODO: correctly we should compare arguments but it will lead to bigger changes
5220 if (mi is MethodBuilder) {
5221 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
5225 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
5227 ParameterData iparams = TypeManager.GetParameterData (mi);
5228 sig.Append (getter ? "get_" : "set_");
5230 sig.Append (iparams.GetSignatureForError ());
5232 Report.SymbolRelatedToPreviousError (mi);
5233 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
5234 Name, sig.ToString ());
5237 public bool IsAccessibleFrom (Type invocation_type, bool lvalue)
5240 MethodInfo accessor = lvalue ? setter : getter;
5241 if (accessor == null && lvalue)
5243 return accessor != null && IsAccessorAccessible (invocation_type, accessor, out dummy);
5246 bool IsSingleDimensionalArrayLength ()
5248 if (DeclaringType != TypeManager.array_type || getter == null || Name != "Length")
5251 string t_name = InstanceExpression.Type.Name;
5252 int t_name_len = t_name.Length;
5253 return t_name_len > 2 && t_name [t_name_len - 2] == '[' && t_name [t_name_len - 3] != ']';
5256 override public Expression DoResolve (EmitContext ec)
5261 if (getter != null){
5262 if (TypeManager.GetParameterData (getter).Count != 0){
5263 Error_PropertyNotFound (getter, true);
5268 if (getter == null){
5270 // The following condition happens if the PropertyExpr was
5271 // created, but is invalid (ie, the property is inaccessible),
5272 // and we did not want to embed the knowledge about this in
5273 // the caller routine. This only avoids double error reporting.
5278 if (InstanceExpression != EmptyExpression.Null) {
5279 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5280 TypeManager.GetFullNameSignature (PropertyInfo));
5285 bool must_do_cs1540_check = false;
5286 if (getter != null &&
5287 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
5288 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
5289 if (pm != null && pm.HasCustomAccessModifier) {
5290 Report.SymbolRelatedToPreviousError (pm);
5291 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5292 TypeManager.CSharpSignature (getter));
5295 Report.SymbolRelatedToPreviousError (getter);
5296 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
5301 if (!InstanceResolve (ec, false, must_do_cs1540_check))
5305 // Only base will allow this invocation to happen.
5307 if (IsBase && getter.IsAbstract) {
5308 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5312 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
5322 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
5324 if (right_side == EmptyExpression.OutAccess) {
5325 if (ec.CurrentBlock.Toplevel.GetTransparentIdentifier (PropertyInfo.Name) != null) {
5326 Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5329 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as `ref' or `out' parameter",
5330 GetSignatureForError ());
5335 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5336 Error_CannotModifyIntermediateExpressionValue (ec);
5339 if (setter == null){
5341 // The following condition happens if the PropertyExpr was
5342 // created, but is invalid (ie, the property is inaccessible),
5343 // and we did not want to embed the knowledge about this in
5344 // the caller routine. This only avoids double error reporting.
5348 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
5349 GetSignatureForError ());
5353 if (TypeManager.GetParameterData (setter).Count != 1){
5354 Error_PropertyNotFound (setter, false);
5358 bool must_do_cs1540_check;
5359 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
5360 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
5361 if (pm != null && pm.HasCustomAccessModifier) {
5362 Report.SymbolRelatedToPreviousError (pm);
5363 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5364 TypeManager.CSharpSignature (setter));
5367 Report.SymbolRelatedToPreviousError (setter);
5368 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
5373 if (!InstanceResolve (ec, PropertyInfo.DeclaringType.IsValueType, must_do_cs1540_check))
5377 // Only base will allow this invocation to happen.
5379 if (IsBase && setter.IsAbstract){
5380 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5387 public override void Emit (EmitContext ec)
5392 public void Emit (EmitContext ec, bool leave_copy)
5395 // Special case: length of single dimension array property is turned into ldlen
5397 if (IsSingleDimensionalArrayLength ()) {
5399 EmitInstance (ec, false);
5400 ec.ig.Emit (OpCodes.Ldlen);
5401 ec.ig.Emit (OpCodes.Conv_I4);
5405 Invocation.EmitCall (ec, IsBase, InstanceExpression, getter, null, loc, prepared, false);
5408 ec.ig.Emit (OpCodes.Dup);
5410 temp = new LocalTemporary (this.Type);
5417 // Implements the IAssignMethod interface for assignments
5419 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5421 Expression my_source = source;
5423 if (prepare_for_load) {
5428 ec.ig.Emit (OpCodes.Dup);
5430 temp = new LocalTemporary (this.Type);
5434 } else if (leave_copy) {
5436 temp = new LocalTemporary (this.Type);
5441 ArrayList args = new ArrayList (1);
5442 args.Add (new Argument (my_source, Argument.AType.Expression));
5444 Invocation.EmitCall (ec, IsBase, InstanceExpression, setter, args, loc, false, prepared);
5454 /// Fully resolved expression that evaluates to an Event
5456 public class EventExpr : MemberExpr {
5457 public readonly EventInfo EventInfo;
5460 MethodInfo add_accessor, remove_accessor;
5462 public EventExpr (EventInfo ei, Location loc)
5466 eclass = ExprClass.EventAccess;
5468 add_accessor = TypeManager.GetAddMethod (ei);
5469 remove_accessor = TypeManager.GetRemoveMethod (ei);
5470 if (add_accessor.IsStatic || remove_accessor.IsStatic)
5473 if (EventInfo is MyEventBuilder){
5474 MyEventBuilder eb = (MyEventBuilder) EventInfo;
5475 type = eb.EventType;
5478 type = EventInfo.EventHandlerType;
5481 public override string Name {
5483 return EventInfo.Name;
5487 public override bool IsInstance {
5493 public override bool IsStatic {
5499 public override Type DeclaringType {
5501 return EventInfo.DeclaringType;
5505 void Error_AssignmentEventOnly ()
5507 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5508 GetSignatureForError ());
5511 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
5512 SimpleName original)
5515 // If the event is local to this class, we transform ourselves into a FieldExpr
5518 if (EventInfo.DeclaringType == ec.ContainerType ||
5519 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
5520 EventField mi = TypeManager.GetEventField (EventInfo);
5523 if (!ec.IsInObsoleteScope)
5524 mi.CheckObsoleteness (loc);
5526 if ((mi.ModFlags & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0 && !ec.IsInCompoundAssignment)
5527 Error_AssignmentEventOnly ();
5529 FieldExpr ml = new FieldExpr (mi.FieldBuilder, loc);
5531 InstanceExpression = null;
5533 return ml.ResolveMemberAccess (ec, left, loc, original);
5537 if (left is This && !ec.IsInCompoundAssignment)
5538 Error_AssignmentEventOnly ();
5540 return base.ResolveMemberAccess (ec, left, loc, original);
5543 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
5546 InstanceExpression = null;
5550 if (InstanceExpression == null) {
5551 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5555 InstanceExpression = InstanceExpression.DoResolve (ec);
5556 if (InstanceExpression == null)
5559 if (IsBase && add_accessor.IsAbstract) {
5560 Error_CannotCallAbstractBase(TypeManager.CSharpSignature(add_accessor));
5565 // This is using the same mechanism as the CS1540 check in PropertyExpr.
5566 // However, in the Event case, we reported a CS0122 instead.
5568 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
5569 InstanceExpression.Type != ec.ContainerType &&
5570 TypeManager.IsSubclassOf (ec.ContainerType, InstanceExpression.Type)) {
5571 Report.SymbolRelatedToPreviousError (EventInfo);
5572 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5579 public bool IsAccessibleFrom (Type invocation_type)
5582 return IsAccessorAccessible (invocation_type, add_accessor, out dummy) &&
5583 IsAccessorAccessible (invocation_type, remove_accessor, out dummy);
5586 public override Expression CreateExpressionTree (EmitContext ec)
5588 throw new NotSupportedException ("ET");
5591 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5593 // contexts where an LValue is valid have already devolved to FieldExprs
5594 Error_CannotAssign ();
5598 public override Expression DoResolve (EmitContext ec)
5600 bool must_do_cs1540_check;
5601 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
5602 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
5603 Report.SymbolRelatedToPreviousError (EventInfo);
5604 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5608 if (!InstanceResolve (ec, must_do_cs1540_check))
5611 if (!ec.IsInCompoundAssignment) {
5612 Error_CannotAssign ();
5619 public override void Emit (EmitContext ec)
5621 Error_CannotAssign ();
5624 public void Error_CannotAssign ()
5626 Report.Error (70, loc,
5627 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
5628 GetSignatureForError (), TypeManager.CSharpName (EventInfo.DeclaringType));
5631 public override string GetSignatureForError ()
5633 return TypeManager.CSharpSignature (EventInfo);
5636 public void EmitAddOrRemove (EmitContext ec, bool is_add, Expression source)
5638 ArrayList args = new ArrayList (1);
5639 args.Add (new Argument (source, Argument.AType.Expression));
5640 Invocation.EmitCall (ec, IsBase, InstanceExpression, is_add ? add_accessor : remove_accessor, args, loc);
5644 public class TemporaryVariable : Expression, IMemoryLocation
5649 public TemporaryVariable (Type type, Location loc)
5653 eclass = ExprClass.Value;
5656 public override Expression CreateExpressionTree (EmitContext ec)
5658 throw new NotSupportedException ("ET");
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");