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 // An expressions resolved as a direct variable reference
103 public interface IVariableReference {
104 bool IsFixedVariable { get; }
105 bool IsHoisted { get; }
107 VariableInfo VariableInfo { get; }
109 void SetHasAddressTaken ();
113 /// Base class for expressions
115 public abstract class Expression {
116 public ExprClass eclass;
118 protected Location loc;
122 set { type = value; }
125 public virtual Location Location {
130 /// Utility wrapper routine for Error, just to beautify the code
132 public void Error (int error, string s)
134 Report.Error (error, loc, s);
137 // Not nice but we have broken hierarchy.
138 public virtual void CheckMarshalByRefAccess (EmitContext ec)
142 public virtual bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
144 Attribute.Error_AttributeArgumentNotValid (loc);
149 public virtual string GetSignatureForError ()
151 return TypeManager.CSharpName (type);
154 public static bool IsAccessorAccessible (Type invocation_type, MethodInfo mi, out bool must_do_cs1540_check)
156 MethodAttributes ma = mi.Attributes & MethodAttributes.MemberAccessMask;
158 must_do_cs1540_check = false; // by default we do not check for this
160 if (ma == MethodAttributes.Public)
164 // If only accessible to the current class or children
166 if (ma == MethodAttributes.Private)
167 return TypeManager.IsPrivateAccessible (invocation_type, mi.DeclaringType) ||
168 TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType);
170 if (TypeManager.IsThisOrFriendAssembly (mi.DeclaringType.Assembly)) {
171 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamORAssem)
174 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamANDAssem)
178 // Family and FamANDAssem require that we derive.
179 // FamORAssem requires that we derive if in different assemblies.
180 if (!TypeManager.IsNestedFamilyAccessible (invocation_type, mi.DeclaringType))
183 if (!TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType))
184 must_do_cs1540_check = true;
189 public virtual bool IsNull {
196 /// Performs semantic analysis on the Expression
200 /// The Resolve method is invoked to perform the semantic analysis
203 /// The return value is an expression (it can be the
204 /// same expression in some cases) or a new
205 /// expression that better represents this node.
207 /// For example, optimizations of Unary (LiteralInt)
208 /// would return a new LiteralInt with a negated
211 /// If there is an error during semantic analysis,
212 /// then an error should be reported (using Report)
213 /// and a null value should be returned.
215 /// There are two side effects expected from calling
216 /// Resolve(): the the field variable "eclass" should
217 /// be set to any value of the enumeration
218 /// `ExprClass' and the type variable should be set
219 /// to a valid type (this is the type of the
222 public abstract Expression DoResolve (EmitContext ec);
224 public virtual Expression DoResolveLValue (EmitContext ec, Expression right_side)
230 // This is used if the expression should be resolved as a type or namespace name.
231 // the default implementation fails.
233 public virtual FullNamedExpression ResolveAsTypeStep (IResolveContext rc, bool silent)
237 EmitContext ec = rc as EmitContext;
241 e.Error_UnexpectedKind (ResolveFlags.Type, loc);
247 // C# 3.0 introduced contextual keywords (var) which behaves like a type if type with
248 // same name exists or as a keyword when no type was found
250 public virtual TypeExpr ResolveAsContextualType (IResolveContext rc, bool silent)
252 return ResolveAsTypeTerminal (rc, silent);
256 // This is used to resolve the expression as a type, a null
257 // value will be returned if the expression is not a type
260 public virtual TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
262 TypeExpr te = ResolveAsBaseTerminal (ec, silent);
266 if (!silent) { // && !(te is TypeParameterExpr)) {
267 ObsoleteAttribute obsolete_attr = AttributeTester.GetObsoleteAttribute (te.Type);
268 if (obsolete_attr != null && !ec.IsInObsoleteScope) {
269 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location);
273 ConstructedType ct = te as ConstructedType;
275 // Skip constrains check for overrides and explicit implementations
276 // TODO: they should use different overload
277 GenericMethod gm = ec.GenericDeclContainer as GenericMethod;
278 if (gm != null && ((gm.ModFlags & Modifiers.OVERRIDE) != 0 || gm.MemberName.Left != null)) {
283 // TODO: silent flag is ignored
284 ct.CheckConstraints (ec);
290 public TypeExpr ResolveAsBaseTerminal (IResolveContext ec, bool silent)
292 int errors = Report.Errors;
294 FullNamedExpression fne = ResolveAsTypeStep (ec, silent);
299 if (fne.eclass != ExprClass.Type) {
300 if (!silent && errors == Report.Errors)
301 fne.Error_UnexpectedKind (null, "type", loc);
305 TypeExpr te = fne as TypeExpr;
307 if (!te.CheckAccessLevel (ec.GenericDeclContainer)) {
308 Report.SymbolRelatedToPreviousError (te.Type);
309 ErrorIsInaccesible (loc, TypeManager.CSharpName (te.Type));
317 public static void ErrorIsInaccesible (Location loc, string name)
319 Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", name);
322 protected static void Error_CannotAccessProtected (Location loc, MemberInfo m, Type qualifier, Type container)
324 Report.Error (1540, loc, "Cannot access protected member `{0}' via a qualifier of type `{1}'."
325 + " The qualifier must be of type `{2}' or derived from it",
326 TypeManager.GetFullNameSignature (m),
327 TypeManager.CSharpName (qualifier),
328 TypeManager.CSharpName (container));
332 public static void Error_InvalidExpressionStatement (Location loc)
334 Report.Error (201, loc, "Only assignment, call, increment, decrement, and new object " +
335 "expressions can be used as a statement");
338 public void Error_InvalidExpressionStatement ()
340 Error_InvalidExpressionStatement (loc);
343 protected void Error_CannotAssign (string to, string roContext)
345 Report.Error (1656, loc, "Cannot assign to `{0}' because it is a `{1}'",
349 public static void Error_VoidInvalidInTheContext (Location loc)
351 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
354 public virtual void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl)
356 // The error was already reported as CS1660
357 if (type == TypeManager.anonymous_method_type)
360 if (TypeManager.IsGenericParameter (Type) && TypeManager.IsGenericParameter (target) && type.Name == target.Name) {
362 string sig1 = type.DeclaringMethod == null ?
363 TypeManager.CSharpName (type.DeclaringType) :
364 TypeManager.CSharpSignature (type.DeclaringMethod);
365 string sig2 = target.DeclaringMethod == null ?
366 TypeManager.CSharpName (target.DeclaringType) :
367 TypeManager.CSharpSignature (target.DeclaringMethod);
368 Report.ExtraInformation (loc,
370 "The generic parameter `{0}' of `{1}' cannot be converted to the generic parameter `{0}' of `{2}' (in the previous ",
371 Type.Name, sig1, sig2));
373 } else if (Type.FullName == target.FullName){
374 Report.ExtraInformation (loc,
376 "The type `{0}' has two conflicting definitions, one comes from `{1}' and the other from `{2}' (in the previous ",
377 Type.FullName, Type.Assembly.FullName, target.Assembly.FullName));
381 Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
382 TypeManager.CSharpName (type), TypeManager.CSharpName (target));
386 Report.DisableReporting ();
387 bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null;
388 Report.EnableReporting ();
391 Report.Error (266, loc, "Cannot implicitly convert type `{0}' to `{1}'. " +
392 "An explicit conversion exists (are you missing a cast?)",
393 TypeManager.CSharpName (Type), TypeManager.CSharpName (target));
397 Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
398 TypeManager.CSharpName (type),
399 TypeManager.CSharpName (target));
402 public virtual void Error_VariableIsUsedBeforeItIsDeclared (string name)
404 Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", name);
407 protected virtual void Error_TypeDoesNotContainDefinition (Type type, string name)
409 Error_TypeDoesNotContainDefinition (loc, type, name);
412 public static void Error_TypeDoesNotContainDefinition (Location loc, Type type, string name)
414 Report.SymbolRelatedToPreviousError (type);
415 Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
416 TypeManager.CSharpName (type), name);
419 protected static void Error_ValueAssignment (Location loc)
421 Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
424 ResolveFlags ExprClassToResolveFlags
429 case ExprClass.Namespace:
430 return ResolveFlags.Type;
432 case ExprClass.MethodGroup:
433 return ResolveFlags.MethodGroup;
435 case ExprClass.Value:
436 case ExprClass.Variable:
437 case ExprClass.PropertyAccess:
438 case ExprClass.EventAccess:
439 case ExprClass.IndexerAccess:
440 return ResolveFlags.VariableOrValue;
443 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
449 /// Resolves an expression and performs semantic analysis on it.
453 /// Currently Resolve wraps DoResolve to perform sanity
454 /// checking and assertion checking on what we expect from Resolve.
456 public Expression Resolve (EmitContext ec, ResolveFlags flags)
458 if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type)
459 return ResolveAsTypeStep (ec, false);
461 bool do_flow_analysis = ec.DoFlowAnalysis;
462 bool omit_struct_analysis = ec.OmitStructFlowAnalysis;
463 if ((flags & ResolveFlags.DisableFlowAnalysis) != 0)
464 do_flow_analysis = false;
465 if ((flags & ResolveFlags.DisableStructFlowAnalysis) != 0)
466 omit_struct_analysis = true;
469 using (ec.WithFlowAnalysis (do_flow_analysis, omit_struct_analysis)) {
470 if (this is SimpleName) {
471 bool intermediate = (flags & ResolveFlags.Intermediate) == ResolveFlags.Intermediate;
472 e = ((SimpleName) this).DoResolve (ec, intermediate);
481 if ((flags & e.ExprClassToResolveFlags) == 0) {
482 e.Error_UnexpectedKind (flags, loc);
486 if (e.type == null && !(e is Namespace)) {
487 throw new Exception (
488 "Expression " + e.GetType () +
489 " did not set its type after Resolve\n" +
490 "called from: " + this.GetType ());
497 /// Resolves an expression and performs semantic analysis on it.
499 public Expression Resolve (EmitContext ec)
501 Expression e = Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
503 if (e != null && e.eclass == ExprClass.MethodGroup && RootContext.Version == LanguageVersion.ISO_1) {
504 ((MethodGroupExpr) e).ReportUsageError ();
510 public Constant ResolveAsConstant (EmitContext ec, MemberCore mc)
512 Expression e = Resolve (ec);
516 Constant c = e as Constant;
520 Const.Error_ExpressionMustBeConstant (loc, mc.GetSignatureForError ());
525 /// Resolves an expression for LValue assignment
529 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
530 /// checking and assertion checking on what we expect from Resolve
532 public Expression ResolveLValue (EmitContext ec, Expression right_side, Location loc)
534 int errors = Report.Errors;
535 bool out_access = right_side == EmptyExpression.OutAccess;
537 Expression e = DoResolveLValue (ec, right_side);
539 if (e != null && out_access && !(e is IMemoryLocation)) {
540 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
541 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
543 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
544 // e.GetType () + " " + e.GetSignatureForError ());
549 if (errors == Report.Errors) {
551 Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
553 Error_ValueAssignment (loc);
558 if (e.eclass == ExprClass.Invalid)
559 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
561 if (e.eclass == ExprClass.MethodGroup) {
562 ((MethodGroupExpr) e).ReportUsageError ();
566 if ((e.type == null) && !(e is ConstructedType))
567 throw new Exception ("Expression " + e + " did not set its type after Resolve");
573 /// Emits the code for the expression
577 /// The Emit method is invoked to generate the code
578 /// for the expression.
580 public abstract void Emit (EmitContext ec);
582 // Emit code to branch to @target if this expression is equivalent to @on_true.
583 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
584 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
585 // including the use of conditional branches. Note also that a branch MUST be emitted
586 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
589 ec.ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
592 // Emit this expression for its side effects, not for its value.
593 // The default implementation is to emit the value, and then throw it away.
594 // Subclasses can provide more efficient implementations, but those MUST be equivalent
595 public virtual void EmitSideEffect (EmitContext ec)
598 ec.ig.Emit (OpCodes.Pop);
602 /// Protected constructor. Only derivate types should
603 /// be able to be created
606 protected Expression ()
608 eclass = ExprClass.Invalid;
613 /// Returns a fully formed expression after a MemberLookup
616 public static Expression ExprClassFromMemberInfo (Type container_type, MemberInfo mi, Location loc)
619 return new EventExpr ((EventInfo) mi, loc);
620 else if (mi is FieldInfo) {
621 FieldInfo fi = (FieldInfo) mi;
622 if (fi.IsLiteral || (fi.IsInitOnly && fi.FieldType == TypeManager.decimal_type))
623 return new ConstantExpr (fi, loc);
624 return new FieldExpr (fi, loc);
625 } else if (mi is PropertyInfo)
626 return new PropertyExpr (container_type, (PropertyInfo) mi, loc);
627 else if (mi is Type) {
628 return new TypeExpression ((System.Type) mi, loc);
634 protected static ArrayList almost_matched_members = new ArrayList (4);
637 // FIXME: Probably implement a cache for (t,name,current_access_set)?
639 // This code could use some optimizations, but we need to do some
640 // measurements. For example, we could use a delegate to `flag' when
641 // something can not any longer be a method-group (because it is something
645 // If the return value is an Array, then it is an array of
648 // If the return value is an MemberInfo, it is anything, but a Method
652 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
653 // the arguments here and have MemberLookup return only the methods that
654 // match the argument count/type, unlike we are doing now (we delay this
657 // This is so we can catch correctly attempts to invoke instance methods
658 // from a static body (scan for error 120 in ResolveSimpleName).
661 // FIXME: Potential optimization, have a static ArrayList
664 public static Expression MemberLookup (Type container_type, Type queried_type, string name,
665 MemberTypes mt, BindingFlags bf, Location loc)
667 return MemberLookup (container_type, null, queried_type, name, mt, bf, loc);
671 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
672 // `qualifier_type' or null to lookup members in the current class.
675 public static Expression MemberLookup (Type container_type,
676 Type qualifier_type, Type queried_type,
677 string name, MemberTypes mt,
678 BindingFlags bf, Location loc)
680 almost_matched_members.Clear ();
682 MemberInfo [] mi = TypeManager.MemberLookup (container_type, qualifier_type,
683 queried_type, mt, bf, name, almost_matched_members);
689 bool is_interface = qualifier_type != null && qualifier_type.IsInterface;
690 ArrayList methods = new ArrayList (2);
691 ArrayList non_methods = null;
693 foreach (MemberInfo m in mi) {
694 if (m is MethodBase) {
699 if (non_methods == null) {
700 non_methods = new ArrayList (2);
705 foreach (MemberInfo n_m in non_methods) {
706 if (m.DeclaringType.IsInterface && TypeManager.ImplementsInterface (m.DeclaringType, n_m.DeclaringType))
709 Report.SymbolRelatedToPreviousError (m);
710 Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
711 TypeManager.GetFullNameSignature (m), TypeManager.GetFullNameSignature (n_m));
716 if (methods.Count == 0)
717 return ExprClassFromMemberInfo (container_type, (MemberInfo)non_methods [0], loc);
719 if (non_methods != null) {
720 MethodBase method = (MethodBase) methods [0];
721 MemberInfo non_method = (MemberInfo) non_methods [0];
722 if (method.DeclaringType == non_method.DeclaringType) {
723 // Cannot happen with C# code, but is valid in IL
724 Report.SymbolRelatedToPreviousError (method);
725 Report.SymbolRelatedToPreviousError (non_method);
726 Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
727 TypeManager.GetFullNameSignature (non_method),
728 TypeManager.CSharpSignature (method));
733 Report.SymbolRelatedToPreviousError (method);
734 Report.SymbolRelatedToPreviousError (non_method);
735 Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and non-method `{1}'. Using method `{0}'",
736 TypeManager.CSharpSignature (method), TypeManager.GetFullNameSignature (non_method));
740 return new MethodGroupExpr (methods, queried_type, loc);
743 if (mi [0] is MethodBase)
744 return new MethodGroupExpr (mi, queried_type, loc);
746 return ExprClassFromMemberInfo (container_type, mi [0], loc);
749 public const MemberTypes AllMemberTypes =
750 MemberTypes.Constructor |
754 MemberTypes.NestedType |
755 MemberTypes.Property;
757 public const BindingFlags AllBindingFlags =
758 BindingFlags.Public |
759 BindingFlags.Static |
760 BindingFlags.Instance;
762 public static Expression MemberLookup (Type container_type, Type queried_type,
763 string name, Location loc)
765 return MemberLookup (container_type, null, queried_type, name,
766 AllMemberTypes, AllBindingFlags, loc);
769 public static Expression MemberLookup (Type container_type, Type qualifier_type,
770 Type queried_type, string name, Location loc)
772 return MemberLookup (container_type, qualifier_type, queried_type,
773 name, AllMemberTypes, AllBindingFlags, loc);
776 public static MethodGroupExpr MethodLookup (Type container_type, Type queried_type,
777 string name, Location loc)
779 return (MethodGroupExpr)MemberLookup (container_type, null, queried_type, name,
780 MemberTypes.Method, AllBindingFlags, loc);
784 /// This is a wrapper for MemberLookup that is not used to "probe", but
785 /// to find a final definition. If the final definition is not found, we
786 /// look for private members and display a useful debugging message if we
789 protected Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
790 Type queried_type, string name,
791 MemberTypes mt, BindingFlags bf,
796 int errors = Report.Errors;
798 e = MemberLookup (ec.ContainerType, qualifier_type, queried_type, name, mt, bf, loc);
800 if (e != null || errors != Report.Errors)
803 // No errors were reported by MemberLookup, but there was an error.
804 return Error_MemberLookupFailed (ec.ContainerType, qualifier_type, queried_type,
808 protected virtual Expression Error_MemberLookupFailed (Type container_type, Type qualifier_type,
809 Type queried_type, string name, string class_name,
810 MemberTypes mt, BindingFlags bf)
812 if (almost_matched_members.Count != 0) {
813 for (int i = 0; i < almost_matched_members.Count; ++i) {
814 MemberInfo m = (MemberInfo) almost_matched_members [i];
815 for (int j = 0; j < i; ++j) {
816 if (m == almost_matched_members [j]) {
824 Type declaring_type = m.DeclaringType;
826 Report.SymbolRelatedToPreviousError (m);
827 if (qualifier_type == null) {
828 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
829 TypeManager.CSharpName (m.DeclaringType),
830 TypeManager.CSharpName (container_type));
832 } else if (qualifier_type != container_type &&
833 TypeManager.IsNestedFamilyAccessible (container_type, declaring_type)) {
834 // Although a derived class can access protected members of
835 // its base class it cannot do so through an instance of the
836 // base class (CS1540). If the qualifier_type is a base of the
837 // ec.ContainerType and the lookup succeeds with the latter one,
838 // then we are in this situation.
839 Error_CannotAccessProtected (loc, m, qualifier_type, container_type);
841 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (m));
844 almost_matched_members.Clear ();
848 MemberInfo[] lookup = null;
849 if (queried_type == null) {
850 class_name = "global::";
852 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
853 mt, (bf & ~BindingFlags.Public) | BindingFlags.NonPublic,
856 if (lookup != null) {
857 Report.SymbolRelatedToPreviousError (lookup [0]);
858 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (lookup [0]));
859 return Error_MemberLookupFailed (lookup);
862 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
863 AllMemberTypes, AllBindingFlags | BindingFlags.NonPublic,
867 if (lookup == null) {
868 if (class_name != null) {
869 Report.Error (103, loc, "The name `{0}' does not exist in the current context",
872 Error_TypeDoesNotContainDefinition (queried_type, name);
877 if (TypeManager.MemberLookup (queried_type, null, queried_type,
878 AllMemberTypes, AllBindingFlags |
879 BindingFlags.NonPublic, name, null) == null) {
880 if ((lookup.Length == 1) && (lookup [0] is Type)) {
881 Type t = (Type) lookup [0];
883 Report.Error (305, loc,
884 "Using the generic type `{0}' " +
885 "requires {1} type arguments",
886 TypeManager.CSharpName (t),
887 TypeManager.GetNumberOfTypeArguments (t).ToString ());
892 return Error_MemberLookupFailed (lookup);
895 protected virtual Expression Error_MemberLookupFailed (MemberInfo[] members)
897 for (int i = 0; i < members.Length; ++i) {
898 if (!(members [i] is MethodBase))
902 // By default propagate the closest candidates upwards
903 return new MethodGroupExpr (members, type, loc);
906 protected virtual void Error_NegativeArrayIndex (Location loc)
908 throw new NotImplementedException ();
911 protected void Error_PointerInsideExpressionTree ()
913 Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
917 /// Returns an expression that can be used to invoke operator true
918 /// on the expression if it exists.
920 static public Expression GetOperatorTrue (EmitContext ec, Expression e, Location loc)
922 return GetOperatorTrueOrFalse (ec, e, true, loc);
926 /// Returns an expression that can be used to invoke operator false
927 /// on the expression if it exists.
929 static public Expression GetOperatorFalse (EmitContext ec, Expression e, Location loc)
931 return GetOperatorTrueOrFalse (ec, e, false, loc);
934 static Expression GetOperatorTrueOrFalse (EmitContext ec, Expression e, bool is_true, Location loc)
936 MethodGroupExpr operator_group;
937 string mname = Operator.GetMetadataName (is_true ? Operator.OpType.True : Operator.OpType.False);
938 operator_group = MethodLookup (ec.ContainerType, e.Type, mname, loc) as MethodGroupExpr;
939 if (operator_group == null)
942 ArrayList arguments = new ArrayList (1);
943 arguments.Add (new Argument (e, Argument.AType.Expression));
944 operator_group = operator_group.OverloadResolve (
945 ec, ref arguments, false, loc);
947 if (operator_group == null)
950 return new UserOperatorCall (operator_group, arguments, null, loc);
954 /// Resolves the expression `e' into a boolean expression: either through
955 /// an implicit conversion, or through an `operator true' invocation
957 public static Expression ResolveBoolean (EmitContext ec, Expression e, Location loc)
963 if (e.Type == TypeManager.bool_type)
966 Expression converted = Convert.ImplicitConversion (ec, e, TypeManager.bool_type, Location.Null);
968 if (converted != null)
972 // If no implicit conversion to bool exists, try using `operator true'
974 converted = Expression.GetOperatorTrue (ec, e, loc);
975 if (converted == null){
976 e.Error_ValueCannotBeConverted (ec, loc, TypeManager.bool_type, false);
982 public virtual string ExprClassName
986 case ExprClass.Invalid:
988 case ExprClass.Value:
990 case ExprClass.Variable:
992 case ExprClass.Namespace:
996 case ExprClass.MethodGroup:
997 return "method group";
998 case ExprClass.PropertyAccess:
999 return "property access";
1000 case ExprClass.EventAccess:
1001 return "event access";
1002 case ExprClass.IndexerAccess:
1003 return "indexer access";
1004 case ExprClass.Nothing:
1007 throw new Exception ("Should not happen");
1012 /// Reports that we were expecting `expr' to be of class `expected'
1014 public void Error_UnexpectedKind (DeclSpace ds, string expected, Location loc)
1016 Error_UnexpectedKind (ds, expected, ExprClassName, loc);
1019 public void Error_UnexpectedKind (DeclSpace ds, string expected, string was, Location loc)
1021 string name = GetSignatureForError ();
1023 name = ds.GetSignatureForError () + '.' + name;
1025 Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
1026 name, was, expected);
1029 public void Error_UnexpectedKind (ResolveFlags flags, Location loc)
1031 string [] valid = new string [4];
1034 if ((flags & ResolveFlags.VariableOrValue) != 0) {
1035 valid [count++] = "variable";
1036 valid [count++] = "value";
1039 if ((flags & ResolveFlags.Type) != 0)
1040 valid [count++] = "type";
1042 if ((flags & ResolveFlags.MethodGroup) != 0)
1043 valid [count++] = "method group";
1046 valid [count++] = "unknown";
1048 StringBuilder sb = new StringBuilder (valid [0]);
1049 for (int i = 1; i < count - 1; i++) {
1051 sb.Append (valid [i]);
1054 sb.Append ("' or `");
1055 sb.Append (valid [count - 1]);
1058 Report.Error (119, loc,
1059 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1062 public static void UnsafeError (Location loc)
1064 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1068 // Load the object from the pointer.
1070 public static void LoadFromPtr (ILGenerator ig, Type t)
1072 if (t == TypeManager.int32_type)
1073 ig.Emit (OpCodes.Ldind_I4);
1074 else if (t == TypeManager.uint32_type)
1075 ig.Emit (OpCodes.Ldind_U4);
1076 else if (t == TypeManager.short_type)
1077 ig.Emit (OpCodes.Ldind_I2);
1078 else if (t == TypeManager.ushort_type)
1079 ig.Emit (OpCodes.Ldind_U2);
1080 else if (t == TypeManager.char_type)
1081 ig.Emit (OpCodes.Ldind_U2);
1082 else if (t == TypeManager.byte_type)
1083 ig.Emit (OpCodes.Ldind_U1);
1084 else if (t == TypeManager.sbyte_type)
1085 ig.Emit (OpCodes.Ldind_I1);
1086 else if (t == TypeManager.uint64_type)
1087 ig.Emit (OpCodes.Ldind_I8);
1088 else if (t == TypeManager.int64_type)
1089 ig.Emit (OpCodes.Ldind_I8);
1090 else if (t == TypeManager.float_type)
1091 ig.Emit (OpCodes.Ldind_R4);
1092 else if (t == TypeManager.double_type)
1093 ig.Emit (OpCodes.Ldind_R8);
1094 else if (t == TypeManager.bool_type)
1095 ig.Emit (OpCodes.Ldind_I1);
1096 else if (t == TypeManager.intptr_type)
1097 ig.Emit (OpCodes.Ldind_I);
1098 else if (TypeManager.IsEnumType (t)) {
1099 if (t == TypeManager.enum_type)
1100 ig.Emit (OpCodes.Ldind_Ref);
1102 LoadFromPtr (ig, TypeManager.GetEnumUnderlyingType (t));
1103 } else if (t.IsValueType || TypeManager.IsGenericParameter (t))
1104 ig.Emit (OpCodes.Ldobj, t);
1105 else if (t.IsPointer)
1106 ig.Emit (OpCodes.Ldind_I);
1108 ig.Emit (OpCodes.Ldind_Ref);
1112 // The stack contains the pointer and the value of type `type'
1114 public static void StoreFromPtr (ILGenerator ig, Type type)
1116 if (TypeManager.IsEnumType (type))
1117 type = TypeManager.GetEnumUnderlyingType (type);
1118 if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
1119 ig.Emit (OpCodes.Stind_I4);
1120 else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
1121 ig.Emit (OpCodes.Stind_I8);
1122 else if (type == TypeManager.char_type || type == TypeManager.short_type ||
1123 type == TypeManager.ushort_type)
1124 ig.Emit (OpCodes.Stind_I2);
1125 else if (type == TypeManager.float_type)
1126 ig.Emit (OpCodes.Stind_R4);
1127 else if (type == TypeManager.double_type)
1128 ig.Emit (OpCodes.Stind_R8);
1129 else if (type == TypeManager.byte_type || type == TypeManager.sbyte_type ||
1130 type == TypeManager.bool_type)
1131 ig.Emit (OpCodes.Stind_I1);
1132 else if (type == TypeManager.intptr_type)
1133 ig.Emit (OpCodes.Stind_I);
1134 else if (type.IsValueType || TypeManager.IsGenericParameter (type))
1135 ig.Emit (OpCodes.Stobj, type);
1137 ig.Emit (OpCodes.Stind_Ref);
1141 // Returns the size of type `t' if known, otherwise, 0
1143 public static int GetTypeSize (Type t)
1145 t = TypeManager.TypeToCoreType (t);
1146 if (t == TypeManager.int32_type ||
1147 t == TypeManager.uint32_type ||
1148 t == TypeManager.float_type)
1150 else if (t == TypeManager.int64_type ||
1151 t == TypeManager.uint64_type ||
1152 t == TypeManager.double_type)
1154 else if (t == TypeManager.byte_type ||
1155 t == TypeManager.sbyte_type ||
1156 t == TypeManager.bool_type)
1158 else if (t == TypeManager.short_type ||
1159 t == TypeManager.char_type ||
1160 t == TypeManager.ushort_type)
1162 else if (t == TypeManager.decimal_type)
1168 protected void Error_CannotCallAbstractBase (string name)
1170 Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
1173 protected void Error_CannotModifyIntermediateExpressionValue (EmitContext ec)
1175 Report.SymbolRelatedToPreviousError (type);
1176 if (ec.CurrentInitializerVariable != null) {
1177 Report.Error (1918, loc, "Members of a value type property `{0}' cannot be assigned with an object initializer",
1178 GetSignatureForError ());
1180 Report.Error (1612, loc, "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
1181 GetSignatureForError ());
1186 // Converts `source' to an int, uint, long or ulong.
1188 public Expression ConvertExpressionToArrayIndex (EmitContext ec, Expression source)
1190 Expression converted;
1192 using (ec.With (EmitContext.Flags.CheckState, true)) {
1193 converted = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, source.loc);
1194 if (converted == null)
1195 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, source.loc);
1196 if (converted == null)
1197 converted = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, source.loc);
1198 if (converted == null)
1199 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, source.loc);
1201 if (converted == null) {
1202 source.Error_ValueCannotBeConverted (ec, source.loc, TypeManager.int32_type, false);
1208 // Only positive constants are allowed at compile time
1210 Constant c = converted as Constant;
1213 Error_NegativeArrayIndex (source.loc);
1218 return new ArrayIndexCast (converted).Resolve (ec);
1222 // Derived classes implement this method by cloning the fields that
1223 // could become altered during the Resolve stage
1225 // Only expressions that are created for the parser need to implement
1228 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1230 throw new NotImplementedException (
1232 "CloneTo not implemented for expression {0}", this.GetType ()));
1236 // Clones an expression created by the parser.
1238 // We only support expressions created by the parser so far, not
1239 // expressions that have been resolved (many more classes would need
1240 // to implement CloneTo).
1242 // This infrastructure is here merely for Lambda expressions which
1243 // compile the same code using different type values for the same
1244 // arguments to find the correct overload
1246 public Expression Clone (CloneContext clonectx)
1248 Expression cloned = (Expression) MemberwiseClone ();
1249 CloneTo (clonectx, cloned);
1255 // Implementation of expression to expression tree conversion
1257 public abstract Expression CreateExpressionTree (EmitContext ec);
1259 protected Expression CreateExpressionFactoryCall (string name, ArrayList args)
1261 return CreateExpressionFactoryCall (name, null, args, loc);
1264 protected Expression CreateExpressionFactoryCall (string name, TypeArguments typeArguments, ArrayList args)
1266 return CreateExpressionFactoryCall (name, typeArguments, args, loc);
1269 public static Expression CreateExpressionFactoryCall (string name, TypeArguments typeArguments, ArrayList args, Location loc)
1271 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (loc), name, typeArguments, loc), args);
1274 protected static TypeExpr CreateExpressionTypeExpression (Location loc)
1276 TypeExpr texpr = TypeManager.expression_type_expr;
1277 if (texpr == null) {
1278 Type t = TypeManager.CoreLookupType ("System.Linq.Expressions", "Expression", Kind.Class, true);
1282 TypeManager.expression_type_expr = texpr = new TypeExpression (t, Location.Null);
1288 public virtual void MutateHoistedGenericType (AnonymousMethodStorey storey)
1290 // TODO: It should probably be type = storey.MutateType (type);
1295 /// This is just a base class for expressions that can
1296 /// appear on statements (invocations, object creation,
1297 /// assignments, post/pre increment and decrement). The idea
1298 /// being that they would support an extra Emition interface that
1299 /// does not leave a result on the stack.
1301 public abstract class ExpressionStatement : Expression {
1303 public virtual ExpressionStatement ResolveStatement (EmitContext ec)
1305 Expression e = Resolve (ec);
1309 ExpressionStatement es = e as ExpressionStatement;
1311 Error_InvalidExpressionStatement ();
1317 /// Requests the expression to be emitted in a `statement'
1318 /// context. This means that no new value is left on the
1319 /// stack after invoking this method (constrasted with
1320 /// Emit that will always leave a value on the stack).
1322 public abstract void EmitStatement (EmitContext ec);
1324 public override void EmitSideEffect (EmitContext ec)
1331 /// This kind of cast is used to encapsulate the child
1332 /// whose type is child.Type into an expression that is
1333 /// reported to return "return_type". This is used to encapsulate
1334 /// expressions which have compatible types, but need to be dealt
1335 /// at higher levels with.
1337 /// For example, a "byte" expression could be encapsulated in one
1338 /// of these as an "unsigned int". The type for the expression
1339 /// would be "unsigned int".
1342 public abstract class TypeCast : Expression
1344 protected readonly Expression child;
1346 protected TypeCast (Expression child, Type return_type)
1348 eclass = child.eclass;
1349 loc = child.Location;
1354 public override Expression CreateExpressionTree (EmitContext ec)
1356 ArrayList args = new ArrayList (2);
1357 args.Add (new Argument (child.CreateExpressionTree (ec)));
1358 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1360 if (type.IsPointer || child.Type.IsPointer)
1361 Error_PointerInsideExpressionTree ();
1363 return CreateExpressionFactoryCall (ec.CheckState ? "ConvertChecked" : "Convert", args);
1366 public override Expression DoResolve (EmitContext ec)
1368 // This should never be invoked, we are born in fully
1369 // initialized state.
1374 public override void Emit (EmitContext ec)
1379 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
1381 return child.GetAttributableValue (ec, value_type, out value);
1384 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1386 child.MutateHoistedGenericType (storey);
1389 protected override void CloneTo (CloneContext clonectx, Expression t)
1394 public override bool IsNull {
1395 get { return child.IsNull; }
1399 public class EmptyCast : TypeCast {
1400 EmptyCast (Expression child, Type target_type)
1401 : base (child, target_type)
1405 public static Expression Create (Expression child, Type type)
1407 Constant c = child as Constant;
1409 return new EmptyConstantCast (c, type);
1411 EmptyCast e = child as EmptyCast;
1413 return new EmptyCast (e.child, type);
1415 return new EmptyCast (child, type);
1418 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1420 child.EmitBranchable (ec, label, on_true);
1423 public override void EmitSideEffect (EmitContext ec)
1425 child.EmitSideEffect (ec);
1430 /// Performs a cast using an operator (op_Explicit or op_Implicit)
1432 public class OperatorCast : TypeCast {
1433 MethodInfo conversion_operator;
1436 public OperatorCast (Expression child, Type target_type) : this (child, target_type, false) {}
1438 public OperatorCast (Expression child, Type target_type, bool find_explicit)
1439 : base (child, target_type)
1441 this.find_explicit = find_explicit;
1444 // Returns the implicit operator that converts from
1445 // 'child.Type' to our target type (type)
1446 MethodInfo GetConversionOperator (bool find_explicit)
1448 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1452 mi = TypeManager.MemberLookup (child.Type, child.Type, child.Type, MemberTypes.Method,
1453 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1456 mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1457 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1460 foreach (MethodInfo oper in mi) {
1461 ParameterData pd = TypeManager.GetParameterData (oper);
1463 if (pd.ParameterType (0) == child.Type && TypeManager.TypeToCoreType (oper.ReturnType) == type)
1471 public override void Emit (EmitContext ec)
1473 ILGenerator ig = ec.ig;
1476 conversion_operator = GetConversionOperator (find_explicit);
1478 if (conversion_operator == null)
1479 throw new InternalErrorException ("Outer conversion routine is out of sync");
1481 ig.Emit (OpCodes.Call, conversion_operator);
1487 /// This is a numeric cast to a Decimal
1489 public class CastToDecimal : TypeCast {
1490 MethodInfo conversion_operator;
1492 public CastToDecimal (Expression child)
1493 : this (child, false)
1497 public CastToDecimal (Expression child, bool find_explicit)
1498 : base (child, TypeManager.decimal_type)
1500 conversion_operator = GetConversionOperator (find_explicit);
1502 if (conversion_operator == null)
1503 throw new InternalErrorException ("Outer conversion routine is out of sync");
1506 // Returns the implicit operator that converts from
1507 // 'child.Type' to System.Decimal.
1508 MethodInfo GetConversionOperator (bool find_explicit)
1510 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1512 MemberInfo [] mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1513 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1515 foreach (MethodInfo oper in mi) {
1516 ParameterData pd = TypeManager.GetParameterData (oper);
1518 if (pd.ParameterType (0) == child.Type && TypeManager.TypeToCoreType (oper.ReturnType) == type)
1524 public override void Emit (EmitContext ec)
1526 ILGenerator ig = ec.ig;
1529 ig.Emit (OpCodes.Call, conversion_operator);
1534 /// This is an explicit numeric cast from a Decimal
1536 public class CastFromDecimal : TypeCast
1538 static IDictionary operators;
1540 public CastFromDecimal (Expression child, Type return_type)
1541 : base (child, return_type)
1543 if (child.Type != TypeManager.decimal_type)
1544 throw new InternalErrorException (
1545 "The expected type is Decimal, instead it is " + child.Type.FullName);
1548 // Returns the explicit operator that converts from an
1549 // express of type System.Decimal to 'type'.
1550 public Expression Resolve ()
1552 if (operators == null) {
1553 MemberInfo[] all_oper = TypeManager.MemberLookup (TypeManager.decimal_type,
1554 TypeManager.decimal_type, TypeManager.decimal_type, MemberTypes.Method,
1555 BindingFlags.Static | BindingFlags.Public, "op_Explicit", null);
1557 operators = new System.Collections.Specialized.HybridDictionary ();
1558 foreach (MethodInfo oper in all_oper) {
1559 ParameterData pd = TypeManager.GetParameterData (oper);
1560 if (pd.ParameterType (0) == TypeManager.decimal_type)
1561 operators.Add (TypeManager.TypeToCoreType (oper.ReturnType), oper);
1565 return operators.Contains (type) ? this : null;
1568 public override void Emit (EmitContext ec)
1570 ILGenerator ig = ec.ig;
1573 ig.Emit (OpCodes.Call, (MethodInfo)operators [type]);
1579 // Constant specialization of EmptyCast.
1580 // We need to special case this since an empty cast of
1581 // a constant is still a constant.
1583 public class EmptyConstantCast : Constant
1585 public readonly Constant child;
1587 public EmptyConstantCast(Constant child, Type type)
1588 : base (child.Location)
1590 eclass = child.eclass;
1595 public override string AsString ()
1597 return child.AsString ();
1600 public override object GetValue ()
1602 return child.GetValue ();
1605 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
1607 // FIXME: check that 'type' can be converted to 'target_type' first
1608 return child.ConvertExplicitly (in_checked_context, target_type);
1611 public override Expression CreateExpressionTree (EmitContext ec)
1613 ArrayList args = new ArrayList (2);
1614 args.Add (new Argument (child.CreateExpressionTree (ec)));
1615 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1617 Error_PointerInsideExpressionTree ();
1619 return CreateExpressionFactoryCall ("Convert", args);
1622 public override Constant Increment ()
1624 return child.Increment ();
1627 public override bool IsDefaultValue {
1628 get { return child.IsDefaultValue; }
1631 public override bool IsNegative {
1632 get { return child.IsNegative; }
1635 public override bool IsNull {
1636 get { return child.IsNull; }
1639 public override bool IsZeroInteger {
1640 get { return child.IsZeroInteger; }
1643 public override void Emit (EmitContext ec)
1648 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1650 child.EmitBranchable (ec, label, on_true);
1653 public override void EmitSideEffect (EmitContext ec)
1655 child.EmitSideEffect (ec);
1658 public override Constant ConvertImplicitly (Type target_type)
1660 // FIXME: Do we need to check user conversions?
1661 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1663 return child.ConvertImplicitly (target_type);
1669 /// This class is used to wrap literals which belong inside Enums
1671 public class EnumConstant : Constant {
1672 public Constant Child;
1674 public EnumConstant (Constant child, Type enum_type):
1675 base (child.Location)
1677 eclass = child.eclass;
1682 public override Expression DoResolve (EmitContext ec)
1684 // This should never be invoked, we are born in fully
1685 // initialized state.
1690 public override void Emit (EmitContext ec)
1695 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1697 Child.EmitBranchable (ec, label, on_true);
1700 public override void EmitSideEffect (EmitContext ec)
1702 Child.EmitSideEffect (ec);
1705 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
1707 value = GetTypedValue ();
1711 public override string GetSignatureForError()
1713 return TypeManager.CSharpName (Type);
1716 public override object GetValue ()
1718 return Child.GetValue ();
1721 public override object GetTypedValue ()
1723 // FIXME: runtime is not ready to work with just emited enums
1724 if (!RootContext.StdLib) {
1725 return Child.GetValue ();
1728 return System.Enum.ToObject (type, Child.GetValue ());
1731 public override string AsString ()
1733 return TypeManager.CSharpEnumValue (type, Child.GetValue ());
1736 public override Constant Increment()
1738 return new EnumConstant (Child.Increment (), type);
1741 public override bool IsDefaultValue {
1743 return Child.IsDefaultValue;
1747 public override bool IsZeroInteger {
1748 get { return Child.IsZeroInteger; }
1751 public override bool IsNegative {
1753 return Child.IsNegative;
1757 public override Constant ConvertExplicitly(bool in_checked_context, Type target_type)
1759 if (Child.Type == target_type)
1762 return Child.ConvertExplicitly (in_checked_context, target_type);
1765 public override Constant ConvertImplicitly (Type type)
1767 Type this_type = TypeManager.DropGenericTypeArguments (Type);
1768 type = TypeManager.DropGenericTypeArguments (type);
1770 if (this_type == type) {
1771 // This is workaround of mono bug. It can be removed when the latest corlib spreads enough
1772 if (TypeManager.IsEnumType (type.UnderlyingSystemType))
1775 Type child_type = TypeManager.DropGenericTypeArguments (Child.Type);
1776 if (type.UnderlyingSystemType != child_type)
1777 Child = Child.ConvertImplicitly (type.UnderlyingSystemType);
1781 if (!Convert.ImplicitStandardConversionExists (this, type)){
1785 return Child.ConvertImplicitly(type);
1791 /// This kind of cast is used to encapsulate Value Types in objects.
1793 /// The effect of it is to box the value type emitted by the previous
1796 public class BoxedCast : TypeCast {
1798 public BoxedCast (Expression expr, Type target_type)
1799 : base (expr, target_type)
1801 eclass = ExprClass.Value;
1804 public override Expression DoResolve (EmitContext ec)
1806 // This should never be invoked, we are born in fully
1807 // initialized state.
1812 public override void Emit (EmitContext ec)
1816 ec.ig.Emit (OpCodes.Box, child.Type);
1819 public override void EmitSideEffect (EmitContext ec)
1821 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1822 // so, we need to emit the box+pop instructions in most cases
1823 if (child.Type.IsValueType &&
1824 (type == TypeManager.object_type || type == TypeManager.value_type))
1825 child.EmitSideEffect (ec);
1827 base.EmitSideEffect (ec);
1831 public class UnboxCast : TypeCast {
1832 public UnboxCast (Expression expr, Type return_type)
1833 : base (expr, return_type)
1837 public override Expression DoResolve (EmitContext ec)
1839 // This should never be invoked, we are born in fully
1840 // initialized state.
1845 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1847 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
1848 Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
1849 return base.DoResolveLValue (ec, right_side);
1852 public override void Emit (EmitContext ec)
1855 ILGenerator ig = ec.ig;
1859 if (t.IsGenericParameter || t.IsGenericType && t.IsValueType)
1860 ig.Emit (OpCodes.Unbox_Any, t);
1864 ig.Emit (OpCodes.Unbox, t);
1866 LoadFromPtr (ig, t);
1870 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1872 type = storey.MutateType (type);
1877 /// This is used to perform explicit numeric conversions.
1879 /// Explicit numeric conversions might trigger exceptions in a checked
1880 /// context, so they should generate the conv.ovf opcodes instead of
1883 public class ConvCast : TypeCast {
1884 public enum Mode : byte {
1885 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1887 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1888 U2_I1, U2_U1, U2_I2, U2_CH,
1889 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1890 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1891 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH,
1892 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH,
1893 CH_I1, CH_U1, CH_I2,
1894 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1895 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4
1900 public ConvCast (Expression child, Type return_type, Mode m)
1901 : base (child, return_type)
1906 public override Expression DoResolve (EmitContext ec)
1908 // This should never be invoked, we are born in fully
1909 // initialized state.
1914 public override string ToString ()
1916 return String.Format ("ConvCast ({0}, {1})", mode, child);
1919 public override void Emit (EmitContext ec)
1921 ILGenerator ig = ec.ig;
1927 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1928 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1929 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1930 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1931 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1933 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1934 case Mode.U1_CH: /* nothing */ break;
1936 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1937 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1938 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1939 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1940 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1941 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1943 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1944 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1945 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1946 case Mode.U2_CH: /* nothing */ break;
1948 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1949 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1950 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1951 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1952 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1953 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1954 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1956 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1957 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1958 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1959 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1960 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1961 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1963 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1964 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1965 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1966 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1967 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1968 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1969 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1970 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1972 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1973 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1974 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1975 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1976 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1977 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1978 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1979 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1981 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1982 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1983 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1985 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1986 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1987 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1988 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1989 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1990 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1991 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1992 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1993 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1995 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1996 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1997 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1998 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1999 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
2000 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
2001 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
2002 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
2003 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
2004 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
2008 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
2009 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
2010 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
2011 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
2012 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
2014 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
2015 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
2017 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
2018 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
2019 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
2020 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
2021 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
2022 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
2024 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
2025 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
2026 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
2027 case Mode.U2_CH: /* nothing */ break;
2029 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
2030 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
2031 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
2032 case Mode.I4_U4: /* nothing */ break;
2033 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
2034 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
2035 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
2037 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
2038 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
2039 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
2040 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
2041 case Mode.U4_I4: /* nothing */ break;
2042 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
2044 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
2045 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
2046 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
2047 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
2048 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
2049 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
2050 case Mode.I8_U8: /* nothing */ break;
2051 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
2053 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
2054 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
2055 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
2056 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
2057 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
2058 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
2059 case Mode.U8_I8: /* nothing */ break;
2060 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
2062 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
2063 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
2064 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
2066 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
2067 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
2068 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
2069 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
2070 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
2071 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
2072 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
2073 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
2074 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
2076 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
2077 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
2078 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
2079 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
2080 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
2081 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
2082 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
2083 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
2084 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
2085 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
2091 public class OpcodeCast : TypeCast {
2094 public OpcodeCast (Expression child, Type return_type, OpCode op)
2095 : base (child, return_type)
2100 public override Expression DoResolve (EmitContext ec)
2102 // This should never be invoked, we are born in fully
2103 // initialized state.
2108 public override void Emit (EmitContext ec)
2114 public Type UnderlyingType {
2115 get { return child.Type; }
2120 /// This kind of cast is used to encapsulate a child and cast it
2121 /// to the class requested
2123 public sealed class ClassCast : TypeCast {
2124 Type child_generic_parameter;
2126 public ClassCast (Expression child, Type return_type)
2127 : base (child, return_type)
2130 if (TypeManager.IsGenericParameter (child.Type))
2131 child_generic_parameter = child.Type;
2134 public override Expression DoResolve (EmitContext ec)
2136 // This should never be invoked, we are born in fully
2137 // initialized state.
2142 public override void Emit (EmitContext ec)
2146 if (child_generic_parameter != null)
2147 ec.ig.Emit (OpCodes.Box, child_generic_parameter);
2150 if (type.IsGenericParameter)
2151 ec.ig.Emit (OpCodes.Unbox_Any, type);
2154 ec.ig.Emit (OpCodes.Castclass, type);
2157 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2159 type = storey.MutateType (type);
2160 if (child_generic_parameter != null)
2161 child_generic_parameter = storey.MutateGenericArgument (child_generic_parameter);
2163 base.MutateHoistedGenericType (storey);
2168 // Created during resolving pahse when an expression is wrapped or constantified
2169 // and original expression can be used later (e.g. for expression trees)
2171 public class ReducedExpression : Expression
2173 class ReducedConstantExpression : Constant
2175 readonly Constant expr;
2176 readonly Expression orig_expr;
2178 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2179 : base (expr.Location)
2182 this.orig_expr = orig_expr;
2183 eclass = expr.eclass;
2187 public override string AsString ()
2189 return expr.AsString ();
2192 public override Expression CreateExpressionTree (EmitContext ec)
2194 return orig_expr.CreateExpressionTree (ec);
2197 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
2200 // Even if resolved result is a constant original expression was not
2201 // and attribute accepts constants only
2203 Attribute.Error_AttributeArgumentNotValid (loc);
2208 public override object GetValue ()
2210 return expr.GetValue ();
2213 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
2215 throw new NotImplementedException ();
2218 public override Expression DoResolve (EmitContext ec)
2223 public override Constant Increment ()
2225 throw new NotImplementedException ();
2228 public override bool IsDefaultValue {
2230 return expr.IsDefaultValue;
2234 public override bool IsNegative {
2236 return expr.IsNegative;
2240 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2242 expr.MutateHoistedGenericType (storey);
2245 public override void Emit (EmitContext ec)
2251 readonly Expression expr, orig_expr;
2253 private ReducedExpression (Expression expr, Expression orig_expr)
2256 this.orig_expr = orig_expr;
2257 this.loc = orig_expr.Location;
2260 public static Expression Create (Constant expr, Expression original_expr)
2262 return new ReducedConstantExpression (expr, original_expr);
2265 public static Expression Create (Expression expr, Expression original_expr)
2267 Constant c = expr as Constant;
2269 return Create (c, original_expr);
2271 return new ReducedExpression (expr, original_expr);
2274 public override Expression CreateExpressionTree (EmitContext ec)
2276 return orig_expr.CreateExpressionTree (ec);
2279 public override Expression DoResolve (EmitContext ec)
2281 eclass = expr.eclass;
2286 public override void Emit (EmitContext ec)
2291 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2293 expr.EmitBranchable (ec, target, on_true);
2296 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2298 expr.MutateHoistedGenericType (storey);
2303 // Unresolved type name expressions
2305 public abstract class ATypeNameExpression : FullNamedExpression
2307 public readonly string Name;
2308 protected TypeArguments targs;
2310 protected ATypeNameExpression (string name, Location l)
2316 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2323 public bool HasTypeArguments {
2325 return targs != null;
2329 public override string GetSignatureForError ()
2331 if (targs != null) {
2332 return TypeManager.RemoveGenericArity (Name) + "<" +
2333 targs.GetSignatureForError () + ">";
2341 /// SimpleName expressions are formed of a single word and only happen at the beginning
2342 /// of a dotted-name.
2344 public class SimpleName : ATypeNameExpression {
2347 public SimpleName (string name, Location l)
2352 public SimpleName (string name, TypeArguments args, Location l)
2353 : base (name, args, l)
2357 public SimpleName (string name, TypeParameter[] type_params, Location l)
2360 targs = new TypeArguments (l);
2361 foreach (TypeParameter type_param in type_params)
2362 targs.Add (new TypeParameterExpr (type_param, l));
2365 public static string RemoveGenericArity (string name)
2368 StringBuilder sb = null;
2370 int pos = name.IndexOf ('`', start);
2375 sb.Append (name.Substring (start));
2380 sb = new StringBuilder ();
2381 sb.Append (name.Substring (start, pos-start));
2384 while ((pos < name.Length) && Char.IsNumber (name [pos]))
2388 } while (start < name.Length);
2390 return sb.ToString ();
2393 public SimpleName GetMethodGroup ()
2395 return new SimpleName (RemoveGenericArity (Name), targs, loc);
2398 public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
2400 if (ec.IsInFieldInitializer)
2401 Report.Error (236, l,
2402 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2406 120, l, "`{0}': An object reference is required for the nonstatic field, method or property",
2410 public bool IdenticalNameAndTypeName (EmitContext ec, Expression resolved_to, Location loc)
2412 return resolved_to != null && resolved_to.Type != null &&
2413 resolved_to.Type.Name == Name &&
2414 (ec.DeclContainer.LookupNamespaceOrType (Name, loc, /* ignore_cs0104 = */ true) != null);
2417 public override Expression DoResolve (EmitContext ec)
2419 return SimpleNameResolve (ec, null, false);
2422 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
2424 return SimpleNameResolve (ec, right_side, false);
2428 public Expression DoResolve (EmitContext ec, bool intermediate)
2430 return SimpleNameResolve (ec, null, intermediate);
2433 static bool IsNestedChild (Type t, Type parent)
2435 while (parent != null) {
2436 if (TypeManager.IsNestedChildOf (t, TypeManager.DropGenericTypeArguments (parent)))
2439 parent = parent.BaseType;
2445 FullNamedExpression ResolveNested (IResolveContext ec, Type t)
2447 if (!TypeManager.IsGenericTypeDefinition (t) && !TypeManager.IsGenericType (t))
2450 DeclSpace ds = ec.DeclContainer;
2451 while (ds != null && !IsNestedChild (t, ds.TypeBuilder))
2457 Type[] gen_params = TypeManager.GetTypeArguments (t);
2459 int arg_count = targs != null ? targs.Count : 0;
2461 for (; (ds != null) && ds.IsGeneric; ds = ds.Parent) {
2462 if (arg_count + ds.CountTypeParameters == gen_params.Length) {
2463 TypeArguments new_args = new TypeArguments (loc);
2464 foreach (TypeParameter param in ds.TypeParameters)
2465 new_args.Add (new TypeParameterExpr (param, loc));
2468 new_args.Add (targs);
2470 return new ConstructedType (t, new_args, loc);
2477 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2479 FullNamedExpression fne = ec.GenericDeclContainer.LookupGeneric (Name, loc);
2481 return fne.ResolveAsTypeStep (ec, silent);
2483 int errors = Report.Errors;
2484 fne = ec.DeclContainer.LookupNamespaceOrType (Name, loc, /*ignore_cs0104=*/ false);
2487 if (fne.Type == null)
2490 FullNamedExpression nested = ResolveNested (ec, fne.Type);
2492 return nested.ResolveAsTypeStep (ec, false);
2494 if (targs != null) {
2495 ConstructedType ct = new ConstructedType (fne, targs, loc);
2496 return ct.ResolveAsTypeStep (ec, false);
2502 if (silent || errors != Report.Errors)
2505 Error_TypeOrNamespaceNotFound (ec);
2509 protected virtual void Error_TypeOrNamespaceNotFound (IResolveContext ec)
2511 MemberCore mc = ec.DeclContainer.GetDefinition (Name);
2513 Error_UnexpectedKind (ec.DeclContainer, "type", GetMemberType (mc), loc);
2517 string ns = ec.DeclContainer.NamespaceEntry.NS.Name;
2518 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2519 foreach (Assembly a in RootNamespace.Global.Assemblies) {
2520 Type type = a.GetType (fullname);
2522 Report.SymbolRelatedToPreviousError (type);
2523 Expression.ErrorIsInaccesible (loc, TypeManager.CSharpName (type));
2528 Type t = ec.DeclContainer.LookupAnyGeneric (Name);
2530 Namespace.Error_InvalidNumberOfTypeArguments (t, loc);
2534 if (targs != null) {
2535 FullNamedExpression retval = ec.DeclContainer.LookupNamespaceOrType (SimpleName.RemoveGenericArity (Name), loc, true);
2536 if (retval != null) {
2537 Namespace.Error_TypeArgumentsCannotBeUsed (retval.Type, loc);
2542 NamespaceEntry.Error_NamespaceNotFound (loc, Name);
2545 // TODO: I am still not convinced about this. If someone else will need it
2546 // implement this as virtual property in MemberCore hierarchy
2547 public static string GetMemberType (MemberCore mc)
2553 if (mc is FieldBase)
2555 if (mc is MethodCore)
2557 if (mc is EnumMember)
2565 Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2571 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2577 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2584 /// 7.5.2: Simple Names.
2586 /// Local Variables and Parameters are handled at
2587 /// parse time, so they never occur as SimpleNames.
2589 /// The `intermediate' flag is used by MemberAccess only
2590 /// and it is used to inform us that it is ok for us to
2591 /// avoid the static check, because MemberAccess might end
2592 /// up resolving the Name as a Type name and the access as
2593 /// a static type access.
2595 /// ie: Type Type; .... { Type.GetType (""); }
2597 /// Type is both an instance variable and a Type; Type.GetType
2598 /// is the static method not an instance method of type.
2600 Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2602 Expression e = null;
2605 // Stage 1: Performed by the parser (binding to locals or parameters).
2607 Block current_block = ec.CurrentBlock;
2608 if (current_block != null){
2609 LocalInfo vi = current_block.GetLocalInfo (Name);
2611 if (targs != null) {
2612 Report.Error (307, loc,
2613 "The variable `{0}' cannot be used with type arguments",
2618 LocalVariableReference var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2619 if (right_side != null) {
2620 return var.ResolveLValue (ec, right_side, loc);
2622 ResolveFlags rf = ResolveFlags.VariableOrValue;
2624 rf |= ResolveFlags.DisableFlowAnalysis;
2625 return var.Resolve (ec, rf);
2629 ParameterReference pref = current_block.Toplevel.GetParameterReference (Name, loc);
2631 if (targs != null) {
2632 Report.Error (307, loc,
2633 "The variable `{0}' cannot be used with type arguments",
2638 if (right_side != null)
2639 return pref.ResolveLValue (ec, right_side, loc);
2641 return pref.Resolve (ec);
2644 Expression expr = current_block.Toplevel.GetTransparentIdentifier (Name);
2646 if (right_side != null)
2647 return expr.ResolveLValue (ec, right_side, loc);
2648 return expr.Resolve (ec);
2653 // Stage 2: Lookup members
2656 Type almost_matched_type = null;
2657 ArrayList almost_matched = null;
2658 for (DeclSpace lookup_ds = ec.DeclContainer; lookup_ds != null; lookup_ds = lookup_ds.Parent) {
2659 // either RootDeclSpace or GenericMethod
2660 if (lookup_ds.TypeBuilder == null)
2663 e = MemberLookup (ec.ContainerType, lookup_ds.TypeBuilder, Name, loc);
2665 if (e is PropertyExpr) {
2666 // since TypeManager.MemberLookup doesn't know if we're doing a lvalue access or not,
2667 // it doesn't know which accessor to check permissions against
2668 if (((PropertyExpr) e).IsAccessibleFrom (ec.ContainerType, right_side != null))
2670 } else if (e is EventExpr) {
2671 if (((EventExpr) e).IsAccessibleFrom (ec.ContainerType))
2679 if (almost_matched == null && almost_matched_members.Count > 0) {
2680 almost_matched_type = lookup_ds.TypeBuilder;
2681 almost_matched = (ArrayList) almost_matched_members.Clone ();
2686 if (almost_matched == null && almost_matched_members.Count > 0) {
2687 almost_matched_type = ec.ContainerType;
2688 almost_matched = (ArrayList) almost_matched_members.Clone ();
2690 e = ResolveAsTypeStep (ec, true);
2694 if (current_block != null) {
2695 IKnownVariable ikv = current_block.Explicit.GetKnownVariable (Name);
2697 LocalInfo li = ikv as LocalInfo;
2698 // Supress CS0219 warning
2702 Error_VariableIsUsedBeforeItIsDeclared (Name);
2707 if (almost_matched != null)
2708 almost_matched_members = almost_matched;
2709 if (almost_matched_type == null)
2710 almost_matched_type = ec.ContainerType;
2711 Error_MemberLookupFailed (ec.ContainerType, null, almost_matched_type, Name,
2712 ec.DeclContainer.Name, AllMemberTypes, AllBindingFlags);
2716 if (e is TypeExpr) {
2720 ConstructedType ct = new ConstructedType (
2721 e.Type, targs, loc);
2722 return ct.ResolveAsTypeStep (ec, false);
2725 if (e is MemberExpr) {
2726 MemberExpr me = (MemberExpr) e;
2729 if (me.IsInstance) {
2730 if (ec.IsStatic || ec.IsInFieldInitializer) {
2732 // Note that an MemberExpr can be both IsInstance and IsStatic.
2733 // An unresolved MethodGroupExpr can contain both kinds of methods
2734 // and each predicate is true if the MethodGroupExpr contains
2735 // at least one of that kind of method.
2739 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2740 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2745 // Pass the buck to MemberAccess and Invocation.
2747 left = EmptyExpression.Null;
2749 left = ec.GetThis (loc);
2752 left = new TypeExpression (ec.ContainerType, loc);
2755 me = me.ResolveMemberAccess (ec, left, loc, null);
2759 if (targs != null) {
2761 me.SetTypeArguments (targs);
2764 if (!me.IsStatic && (me.InstanceExpression != null) &&
2765 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2766 me.InstanceExpression.Type != me.DeclaringType &&
2767 !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2768 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2769 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2770 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2774 return (right_side != null)
2775 ? me.DoResolveLValue (ec, right_side)
2776 : me.DoResolve (ec);
2782 protected override void CloneTo (CloneContext clonectx, Expression target)
2784 // CloneTo: Nothing, we do not keep any state on this expression
2789 /// Represents a namespace or a type. The name of the class was inspired by
2790 /// section 10.8.1 (Fully Qualified Names).
2792 public abstract class FullNamedExpression : Expression {
2794 public override Expression CreateExpressionTree (EmitContext ec)
2796 throw new NotSupportedException ("ET");
2799 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2801 throw new NotSupportedException ();
2804 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2809 public override void Emit (EmitContext ec)
2811 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2812 GetSignatureForError ());
2817 /// Expression that evaluates to a type
2819 public abstract class TypeExpr : FullNamedExpression {
2820 override public FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2822 TypeExpr t = DoResolveAsTypeStep (ec);
2826 eclass = ExprClass.Type;
2830 override public Expression DoResolve (EmitContext ec)
2832 return ResolveAsTypeTerminal (ec, false);
2835 public virtual bool CheckAccessLevel (DeclSpace ds)
2837 return ds.CheckAccessLevel (Type);
2840 public virtual bool AsAccessible (DeclSpace ds)
2842 return ds.IsAccessibleAs (Type);
2845 public virtual bool IsClass {
2846 get { return Type.IsClass; }
2849 public virtual bool IsValueType {
2850 get { return Type.IsValueType; }
2853 public virtual bool IsInterface {
2854 get { return Type.IsInterface; }
2857 public virtual bool IsSealed {
2858 get { return Type.IsSealed; }
2861 public virtual bool CanInheritFrom ()
2863 if (Type == TypeManager.enum_type ||
2864 (Type == TypeManager.value_type && RootContext.StdLib) ||
2865 Type == TypeManager.multicast_delegate_type ||
2866 Type == TypeManager.delegate_type ||
2867 Type == TypeManager.array_type)
2873 protected abstract TypeExpr DoResolveAsTypeStep (IResolveContext ec);
2875 public override bool Equals (object obj)
2877 TypeExpr tobj = obj as TypeExpr;
2881 return Type == tobj.Type;
2884 public override int GetHashCode ()
2886 return Type.GetHashCode ();
2889 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2891 type = storey.MutateType (type);
2896 /// Fully resolved Expression that already evaluated to a type
2898 public class TypeExpression : TypeExpr {
2899 public TypeExpression (Type t, Location l)
2902 eclass = ExprClass.Type;
2906 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2911 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2918 /// Used to create types from a fully qualified name. These are just used
2919 /// by the parser to setup the core types. A TypeLookupExpression is always
2920 /// classified as a type.
2922 public sealed class TypeLookupExpression : TypeExpr {
2923 readonly string name;
2925 public TypeLookupExpression (string name)
2928 eclass = ExprClass.Type;
2931 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2933 // It's null for corlib compilation only
2935 return DoResolveAsTypeStep (ec);
2940 private class UnexpectedType
2944 // This performes recursive type lookup, providing support for generic types.
2945 // For example, given the type:
2947 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]]
2949 // The types will be checked in the following order:
2952 // System.Collections |
2953 // System.Collections.Generic |
2955 // System | recursive call 1 |
2956 // System.Int32 _| | main method call
2958 // System | recursive call 2 |
2959 // System.String _| |
2961 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]] _|
2963 private Type TypeLookup (IResolveContext ec, string name)
2968 FullNamedExpression resolved = null;
2970 Type recursive_type = null;
2971 while (index < name.Length) {
2972 if (name[index] == '[') {
2977 if (name[index] == '[')
2979 else if (name[index] == ']')
2981 } while (braces > 0);
2982 recursive_type = TypeLookup (ec, name.Substring (open + 1, index - open - 1));
2983 if (recursive_type == null || (recursive_type == typeof(UnexpectedType)))
2984 return recursive_type;
2987 if (name[index] == ',')
2989 else if ((name[index] == '.' && !done) || (index == name.Length && name[0] != '[')) {
2990 string substring = name.Substring(dot, index - dot);
2992 if (resolved == null)
2993 resolved = RootNamespace.Global.Lookup (ec.DeclContainer, substring, Location.Null);
2994 else if (resolved is Namespace)
2995 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
2996 else if (type != null)
2997 type = TypeManager.GetNestedType (type, substring);
3001 if (resolved == null)
3003 else if (type == null && resolved is TypeExpr)
3004 type = resolved.Type;
3011 if (name[0] != '[') {
3012 string substring = name.Substring(dot, index - dot);
3015 return TypeManager.GetNestedType (type, substring);
3017 if (resolved != null) {
3018 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
3019 if (resolved is TypeExpr)
3020 return resolved.Type;
3022 if (resolved == null)
3025 resolved.Error_UnexpectedKind (ec.DeclContainer, "type", loc);
3026 return typeof (UnexpectedType);
3032 return recursive_type;
3035 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
3037 Type t = TypeLookup (ec, name);
3039 NamespaceEntry.Error_NamespaceNotFound (loc, name);
3042 if (t == typeof(UnexpectedType))
3048 protected override void CloneTo (CloneContext clonectx, Expression target)
3050 // CloneTo: Nothing, we do not keep any state on this expression
3053 public override string GetSignatureForError ()
3056 return TypeManager.CSharpName (name);
3058 return base.GetSignatureForError ();
3063 /// Represents an "unbound generic type", ie. typeof (Foo<>).
3066 public class UnboundTypeExpression : TypeExpr
3070 public UnboundTypeExpression (MemberName name, Location l)
3076 protected override void CloneTo (CloneContext clonectx, Expression target)
3081 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
3084 if (name.Left != null) {
3085 Expression lexpr = name.Left.GetTypeExpression ();
3086 expr = new MemberAccess (lexpr, name.Basename);
3088 expr = new SimpleName (name.Basename, loc);
3091 FullNamedExpression fne = expr.ResolveAsTypeStep (ec, false);
3096 return new TypeExpression (type, loc);
3101 /// This class denotes an expression which evaluates to a member
3102 /// of a struct or a class.
3104 public abstract class MemberExpr : Expression
3106 protected bool is_base;
3109 /// The name of this member.
3111 public abstract string Name {
3116 // When base.member is used
3118 public bool IsBase {
3119 get { return is_base; }
3120 set { is_base = value; }
3124 /// Whether this is an instance member.
3126 public abstract bool IsInstance {
3131 /// Whether this is a static member.
3133 public abstract bool IsStatic {
3138 /// The type which declares this member.
3140 public abstract Type DeclaringType {
3145 /// The instance expression associated with this member, if it's a
3146 /// non-static member.
3148 public Expression InstanceExpression;
3150 public static void error176 (Location loc, string name)
3152 Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
3153 "with an instance reference, qualify it with a type name instead", name);
3156 public static void Error_BaseAccessInExpressionTree (Location loc)
3158 Report.Error (831, loc, "An expression tree may not contain a base access");
3161 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3163 if (InstanceExpression != null)
3164 InstanceExpression.MutateHoistedGenericType (storey);
3167 // TODO: possible optimalization
3168 // Cache resolved constant result in FieldBuilder <-> expression map
3169 public virtual MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3170 SimpleName original)
3174 // original == null || original.Resolve (...) ==> left
3177 if (left is TypeExpr) {
3178 left = left.ResolveAsTypeTerminal (ec, true);
3183 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3191 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3194 return ResolveExtensionMemberAccess (left);
3197 InstanceExpression = left;
3201 protected virtual MemberExpr ResolveExtensionMemberAccess (Expression left)
3203 error176 (loc, GetSignatureForError ());
3207 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3212 if (InstanceExpression == EmptyExpression.Null) {
3213 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3217 if (InstanceExpression.Type.IsValueType) {
3218 if (InstanceExpression is IMemoryLocation) {
3219 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
3221 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
3222 InstanceExpression.Emit (ec);
3224 t.AddressOf (ec, AddressOp.Store);
3227 InstanceExpression.Emit (ec);
3229 if (prepare_for_load)
3230 ec.ig.Emit (OpCodes.Dup);
3233 public virtual void SetTypeArguments (TypeArguments ta)
3235 // TODO: need to get correct member type
3236 Report.Error (307, loc, "The property `{0}' cannot be used with type arguments",
3237 GetSignatureForError ());
3242 /// Represents group of extension methods
3244 public class ExtensionMethodGroupExpr : MethodGroupExpr
3246 readonly NamespaceEntry namespace_entry;
3247 public Expression ExtensionExpression;
3248 Argument extension_argument;
3250 public ExtensionMethodGroupExpr (ArrayList list, NamespaceEntry n, Type extensionType, Location l)
3251 : base (list, extensionType, l)
3253 this.namespace_entry = n;
3256 public override bool IsStatic {
3257 get { return true; }
3260 public bool IsTopLevel {
3261 get { return namespace_entry == null; }
3264 public override void EmitArguments (EmitContext ec, ArrayList arguments)
3266 if (arguments == null)
3267 arguments = new ArrayList (1);
3268 arguments.Insert (0, extension_argument);
3269 base.EmitArguments (ec, arguments);
3272 public override void EmitCall (EmitContext ec, ArrayList arguments)
3274 if (arguments == null)
3275 arguments = new ArrayList (1);
3276 arguments.Insert (0, extension_argument);
3277 base.EmitCall (ec, arguments);
3280 public override MethodGroupExpr OverloadResolve (EmitContext ec, ref ArrayList arguments, bool may_fail, Location loc)
3282 if (arguments == null)
3283 arguments = new ArrayList (1);
3285 arguments.Insert (0, new Argument (ExtensionExpression));
3286 MethodGroupExpr mg = ResolveOverloadExtensions (ec, arguments, namespace_entry, loc);
3288 // Store resolved argument and restore original arguments
3290 ((ExtensionMethodGroupExpr)mg).extension_argument = (Argument)arguments [0];
3291 arguments.RemoveAt (0);
3296 MethodGroupExpr ResolveOverloadExtensions (EmitContext ec, ArrayList arguments, NamespaceEntry ns, Location loc)
3298 // Use normal resolve rules
3299 MethodGroupExpr mg = base.OverloadResolve (ec, ref arguments, ns != null, loc);
3307 ExtensionMethodGroupExpr e = ns.LookupExtensionMethod (type, null, Name, loc);
3309 return base.OverloadResolve (ec, ref arguments, false, loc);
3311 e.ExtensionExpression = ExtensionExpression;
3312 e.SetTypeArguments (type_arguments);
3313 return e.ResolveOverloadExtensions (ec, arguments, e.namespace_entry, loc);
3318 /// MethodGroupExpr represents a group of method candidates which
3319 /// can be resolved to the best method overload
3321 public class MethodGroupExpr : MemberExpr
3323 public interface IErrorHandler
3325 bool NoExactMatch (EmitContext ec, MethodBase method);
3328 public IErrorHandler CustomErrorHandler;
3329 public MethodBase [] Methods;
3330 MethodBase best_candidate;
3331 // TODO: make private
3332 public TypeArguments type_arguments;
3333 bool identical_type_name;
3336 public MethodGroupExpr (MemberInfo [] mi, Type type, Location l)
3339 Methods = new MethodBase [mi.Length];
3340 mi.CopyTo (Methods, 0);
3343 public MethodGroupExpr (ArrayList list, Type type, Location l)
3347 Methods = (MethodBase[])list.ToArray (typeof (MethodBase));
3349 foreach (MemberInfo m in list){
3350 if (!(m is MethodBase)){
3351 Console.WriteLine ("Name " + m.Name);
3352 Console.WriteLine ("Found a: " + m.GetType ().FullName);
3361 protected MethodGroupExpr (Type type, Location loc)
3364 eclass = ExprClass.MethodGroup;
3368 public override Type DeclaringType {
3371 // We assume that the top-level type is in the end
3373 return Methods [Methods.Length - 1].DeclaringType;
3374 //return Methods [0].DeclaringType;
3378 public Type DelegateType {
3380 delegate_type = value;
3384 public bool IdenticalTypeName {
3386 return identical_type_name;
3390 identical_type_name = value;
3394 public override string GetSignatureForError ()
3396 if (best_candidate != null)
3397 return TypeManager.CSharpSignature (best_candidate);
3399 return TypeManager.CSharpSignature (Methods [0]);
3402 public override string Name {
3404 return Methods [0].Name;
3408 public override bool IsInstance {
3410 if (best_candidate != null)
3411 return !best_candidate.IsStatic;
3413 foreach (MethodBase mb in Methods)
3421 public override bool IsStatic {
3423 if (best_candidate != null)
3424 return best_candidate.IsStatic;
3426 foreach (MethodBase mb in Methods)
3434 public static explicit operator ConstructorInfo (MethodGroupExpr mg)
3436 return (ConstructorInfo)mg.best_candidate;
3439 public static explicit operator MethodInfo (MethodGroupExpr mg)
3441 return (MethodInfo)mg.best_candidate;
3445 // 7.4.3.3 Better conversion from expression
3446 // Returns : 1 if a->p is better,
3447 // 2 if a->q is better,
3448 // 0 if neither is better
3450 static int BetterExpressionConversion (EmitContext ec, Argument a, Type p, Type q)
3452 Type argument_type = TypeManager.TypeToCoreType (a.Type);
3453 if (argument_type == TypeManager.anonymous_method_type && RootContext.Version > LanguageVersion.ISO_2) {
3455 // Uwrap delegate from Expression<T>
3457 if (TypeManager.DropGenericTypeArguments (p) == TypeManager.expression_type) {
3458 p = TypeManager.GetTypeArguments (p) [0];
3460 if (TypeManager.DropGenericTypeArguments (q) == TypeManager.expression_type) {
3461 q = TypeManager.GetTypeArguments (q) [0];
3464 p = Delegate.GetInvokeMethod (null, p).ReturnType;
3465 q = Delegate.GetInvokeMethod (null, q).ReturnType;
3466 if (p == TypeManager.void_type && q != TypeManager.void_type)
3468 if (q == TypeManager.void_type && p != TypeManager.void_type)
3471 if (argument_type == p)
3474 if (argument_type == q)
3478 return BetterTypeConversion (ec, p, q);
3482 // 7.4.3.4 Better conversion from type
3484 public static int BetterTypeConversion (EmitContext ec, Type p, Type q)
3486 if (p == null || q == null)
3487 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3489 if (p == TypeManager.int32_type) {
3490 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3492 } else if (p == TypeManager.int64_type) {
3493 if (q == TypeManager.uint64_type)
3495 } else if (p == TypeManager.sbyte_type) {
3496 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3497 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3499 } else if (p == TypeManager.short_type) {
3500 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3501 q == TypeManager.uint64_type)
3505 if (q == TypeManager.int32_type) {
3506 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3508 } if (q == TypeManager.int64_type) {
3509 if (p == TypeManager.uint64_type)
3511 } else if (q == TypeManager.sbyte_type) {
3512 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3513 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3515 } if (q == TypeManager.short_type) {
3516 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3517 p == TypeManager.uint64_type)
3521 // TODO: this is expensive
3522 Expression p_tmp = new EmptyExpression (p);
3523 Expression q_tmp = new EmptyExpression (q);
3525 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3526 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3528 if (p_to_q && !q_to_p)
3531 if (q_to_p && !p_to_q)
3538 /// Determines "Better function" between candidate
3539 /// and the current best match
3542 /// Returns a boolean indicating :
3543 /// false if candidate ain't better
3544 /// true if candidate is better than the current best match
3546 static bool BetterFunction (EmitContext ec, ArrayList args, int argument_count,
3547 MethodBase candidate, bool candidate_params,
3548 MethodBase best, bool best_params)
3550 ParameterData candidate_pd = TypeManager.GetParameterData (candidate);
3551 ParameterData best_pd = TypeManager.GetParameterData (best);
3553 bool better_at_least_one = false;
3555 for (int j = 0, c_idx = 0, b_idx = 0; j < argument_count; ++j, ++c_idx, ++b_idx)
3557 Argument a = (Argument) args [j];
3559 Type ct = TypeManager.TypeToCoreType (candidate_pd.ParameterType (c_idx));
3560 Type bt = TypeManager.TypeToCoreType (best_pd.ParameterType (b_idx));
3562 if (candidate_params && candidate_pd.ParameterModifier (c_idx) == Parameter.Modifier.PARAMS)
3564 ct = TypeManager.GetElementType (ct);
3568 if (best_params && best_pd.ParameterModifier (b_idx) == Parameter.Modifier.PARAMS)
3570 bt = TypeManager.GetElementType (bt);
3578 int result = BetterExpressionConversion (ec, a, ct, bt);
3580 // for each argument, the conversion to 'ct' should be no worse than
3581 // the conversion to 'bt'.
3585 // for at least one argument, the conversion to 'ct' should be better than
3586 // the conversion to 'bt'.
3588 better_at_least_one = true;
3591 if (better_at_least_one)
3595 // This handles the case
3597 // Add (float f1, float f2, float f3);
3598 // Add (params decimal [] foo);
3600 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3601 // first candidate would've chosen as better.
3607 // The two methods have equal parameter types. Now apply tie-breaking rules
3609 if (TypeManager.IsGenericMethod (best) && !TypeManager.IsGenericMethod (candidate))
3611 if (!TypeManager.IsGenericMethod (best) && TypeManager.IsGenericMethod (candidate))
3615 // This handles the following cases:
3617 // Trim () is better than Trim (params char[] chars)
3618 // Concat (string s1, string s2, string s3) is better than
3619 // Concat (string s1, params string [] srest)
3620 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3622 if (!candidate_params && best_params)
3624 if (candidate_params && !best_params)
3627 int candidate_param_count = candidate_pd.Count;
3628 int best_param_count = best_pd.Count;
3630 if (candidate_param_count != best_param_count)
3631 // can only happen if (candidate_params && best_params)
3632 return candidate_param_count > best_param_count;
3635 // now, both methods have the same number of parameters, and the parameters have the same types
3636 // Pick the "more specific" signature
3639 MethodBase orig_candidate = TypeManager.DropGenericMethodArguments (candidate);
3640 MethodBase orig_best = TypeManager.DropGenericMethodArguments (best);
3642 ParameterData orig_candidate_pd = TypeManager.GetParameterData (orig_candidate);
3643 ParameterData orig_best_pd = TypeManager.GetParameterData (orig_best);
3645 bool specific_at_least_once = false;
3646 for (int j = 0; j < candidate_param_count; ++j)
3648 Type ct = TypeManager.TypeToCoreType (orig_candidate_pd.ParameterType (j));
3649 Type bt = TypeManager.TypeToCoreType (orig_best_pd.ParameterType (j));
3652 Type specific = MoreSpecific (ct, bt);
3656 specific_at_least_once = true;
3659 if (specific_at_least_once)
3662 // FIXME: handle lifted operators
3668 protected override MemberExpr ResolveExtensionMemberAccess (Expression left)
3671 return base.ResolveExtensionMemberAccess (left);
3674 // When left side is an expression and at least one candidate method is
3675 // static, it can be extension method
3677 InstanceExpression = left;
3681 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3682 SimpleName original)
3684 if (!(left is TypeExpr) &&
3685 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3686 IdenticalTypeName = true;
3688 return base.ResolveMemberAccess (ec, left, loc, original);
3691 public override Expression CreateExpressionTree (EmitContext ec)
3693 if (best_candidate == null) {
3694 Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3698 if (best_candidate.IsConstructor)
3699 return new TypeOfConstructorInfo (best_candidate, loc);
3701 IMethodData md = TypeManager.GetMethod (best_candidate);
3702 if (md != null && md.IsExcluded ())
3703 Report.Error (765, loc,
3704 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3706 return new TypeOfMethodInfo (best_candidate, loc);
3709 override public Expression DoResolve (EmitContext ec)
3711 if (InstanceExpression != null) {
3712 InstanceExpression = InstanceExpression.DoResolve (ec);
3713 if (InstanceExpression == null)
3720 public void ReportUsageError ()
3722 Report.Error (654, loc, "Method `" + DeclaringType + "." +
3723 Name + "()' is referenced without parentheses");
3726 override public void Emit (EmitContext ec)
3728 ReportUsageError ();
3731 public virtual void EmitArguments (EmitContext ec, ArrayList arguments)
3733 Invocation.EmitArguments (ec, arguments, false, null);
3736 public virtual void EmitCall (EmitContext ec, ArrayList arguments)
3738 Invocation.EmitCall (ec, IsBase, InstanceExpression, best_candidate, arguments, loc);
3741 protected virtual void Error_InvalidArguments (EmitContext ec, Location loc, int idx, MethodBase method,
3742 Argument a, ParameterData expected_par, Type paramType)
3744 ExtensionMethodGroupExpr emg = this as ExtensionMethodGroupExpr;
3746 if (a is CollectionElementInitializer.ElementInitializerArgument) {
3747 Report.SymbolRelatedToPreviousError (method);
3748 if ((expected_par.ParameterModifier (idx) & Parameter.Modifier.ISBYREF) != 0) {
3749 Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
3750 TypeManager.CSharpSignature (method));
3753 Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
3754 TypeManager.CSharpSignature (method));
3755 } else if (delegate_type == null) {
3756 Report.SymbolRelatedToPreviousError (method);
3758 Report.Error (1928, loc,
3759 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3760 emg.ExtensionExpression.GetSignatureForError (),
3761 emg.Name, TypeManager.CSharpSignature (method));
3763 Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
3764 TypeManager.CSharpSignature (method));
3767 Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
3768 TypeManager.CSharpName (delegate_type));
3770 Parameter.Modifier mod = expected_par.ParameterModifier (idx);
3772 string index = (idx + 1).ToString ();
3773 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
3774 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
3775 if ((mod & Parameter.Modifier.ISBYREF) == 0)
3776 Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
3777 index, Parameter.GetModifierSignature (a.Modifier));
3779 Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
3780 index, Parameter.GetModifierSignature (mod));
3782 string p1 = a.GetSignatureForError ();
3783 string p2 = TypeManager.CSharpName (paramType);
3786 Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
3787 Report.SymbolRelatedToPreviousError (a.Expr.Type);
3788 Report.SymbolRelatedToPreviousError (paramType);
3791 if (idx == 0 && emg != null) {
3792 Report.Error (1929, loc,
3793 "Extension method instance type `{0}' cannot be converted to `{1}'", p1, p2);
3795 Report.Error (1503, loc,
3796 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
3801 public override void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl)
3803 Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3804 Name, TypeManager.CSharpName (target));
3807 protected virtual int GetApplicableParametersCount (MethodBase method, ParameterData parameters)
3809 return parameters.Count;
3812 public static bool IsAncestralType (Type first_type, Type second_type)
3814 return first_type != second_type &&
3815 (TypeManager.IsSubclassOf (second_type, first_type) ||
3816 TypeManager.ImplementsInterface (second_type, first_type));
3820 /// Determines if the candidate method is applicable (section 14.4.2.1)
3821 /// to the given set of arguments
3822 /// A return value rates candidate method compatibility,
3823 /// 0 = the best, int.MaxValue = the worst
3825 public int IsApplicable (EmitContext ec,
3826 ArrayList arguments, int arg_count, ref MethodBase method, ref bool params_expanded_form)
3828 MethodBase candidate = method;
3830 ParameterData pd = TypeManager.GetParameterData (candidate);
3831 int param_count = GetApplicableParametersCount (candidate, pd);
3833 if (arg_count != param_count) {
3835 return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
3836 if (arg_count < param_count - 1)
3837 return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
3842 // 1. Handle generic method using type arguments when specified or type inference
3844 if (TypeManager.IsGenericMethod (candidate)) {
3845 if (type_arguments != null) {
3846 Type [] g_args = candidate.GetGenericArguments ();
3847 if (g_args.Length != type_arguments.Count)
3848 return int.MaxValue - 20000 + Math.Abs (type_arguments.Count - g_args.Length);
3850 // TODO: Don't create new method, create Parameters only
3851 method = ((MethodInfo) candidate).MakeGenericMethod (type_arguments.Arguments);
3853 pd = TypeManager.GetParameterData (candidate);
3855 int score = TypeManager.InferTypeArguments (ec, arguments, ref candidate);
3857 return score - 20000;
3859 if (TypeManager.IsGenericMethodDefinition (candidate))
3860 throw new InternalErrorException ("A generic method `{0}' definition took part in overload resolution",
3861 TypeManager.CSharpSignature (candidate));
3863 pd = TypeManager.GetParameterData (candidate);
3866 if (type_arguments != null)
3867 return int.MaxValue - 15000;
3872 // 2. Each argument has to be implicitly convertible to method parameter
3875 Parameter.Modifier p_mod = 0;
3877 for (int i = 0; i < arg_count; i++) {
3878 Argument a = (Argument) arguments [i];
3879 Parameter.Modifier a_mod = a.Modifier &
3880 ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3882 if (p_mod != Parameter.Modifier.PARAMS) {
3883 p_mod = pd.ParameterModifier (i) & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3885 if (p_mod == Parameter.Modifier.ARGLIST) {
3886 if (a.Type == TypeManager.runtime_argument_handle_type)
3892 pt = pd.ParameterType (i);
3894 params_expanded_form = true;
3898 if (!params_expanded_form)
3899 score = IsArgumentCompatible (ec, a_mod, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
3901 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0) {
3902 // It can be applicable in expanded form
3903 score = IsArgumentCompatible (ec, a_mod, a, 0, pt.GetElementType ());
3905 params_expanded_form = true;
3909 if (params_expanded_form)
3911 return (arg_count - i) * 2 + score;
3915 if (arg_count != param_count)
3916 params_expanded_form = true;
3921 int IsArgumentCompatible (EmitContext ec, Parameter.Modifier arg_mod, Argument argument, Parameter.Modifier param_mod, Type parameter)
3924 // Types have to be identical when ref or out modifer is used
3926 if (arg_mod != 0 || param_mod != 0) {
3927 if (TypeManager.HasElementType (parameter))
3928 parameter = parameter.GetElementType ();
3930 Type a_type = argument.Type;
3931 if (TypeManager.HasElementType (a_type))
3932 a_type = a_type.GetElementType ();
3934 if (a_type != parameter)
3937 if (delegate_type != null ?
3938 !Delegate.IsTypeCovariant (argument.Expr, parameter) :
3939 !Convert.ImplicitConversionExists (ec, argument.Expr, parameter))
3943 if (arg_mod != param_mod)
3949 public static bool IsOverride (MethodBase cand_method, MethodBase base_method)
3951 if (!IsAncestralType (base_method.DeclaringType, cand_method.DeclaringType))
3954 ParameterData cand_pd = TypeManager.GetParameterData (cand_method);
3955 ParameterData base_pd = TypeManager.GetParameterData (base_method);
3957 if (cand_pd.Count != base_pd.Count)
3960 for (int j = 0; j < cand_pd.Count; ++j)
3962 Parameter.Modifier cm = cand_pd.ParameterModifier (j);
3963 Parameter.Modifier bm = base_pd.ParameterModifier (j);
3964 Type ct = TypeManager.TypeToCoreType (cand_pd.ParameterType (j));
3965 Type bt = TypeManager.TypeToCoreType (base_pd.ParameterType (j));
3967 if (cm != bm || ct != bt)
3974 public static MethodGroupExpr MakeUnionSet (MethodGroupExpr mg1, MethodGroupExpr mg2, Location loc)
3985 ArrayList all = new ArrayList (mg1.Methods);
3986 foreach (MethodBase m in mg2.Methods){
3987 if (!TypeManager.ArrayContainsMethod (mg1.Methods, m, false))
3991 return new MethodGroupExpr (all, null, loc);
3994 static Type MoreSpecific (Type p, Type q)
3996 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
3998 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4001 if (TypeManager.HasElementType (p))
4003 Type pe = TypeManager.GetElementType (p);
4004 Type qe = TypeManager.GetElementType (q);
4005 Type specific = MoreSpecific (pe, qe);
4011 else if (TypeManager.IsGenericType (p))
4013 Type[] pargs = TypeManager.GetTypeArguments (p);
4014 Type[] qargs = TypeManager.GetTypeArguments (q);
4016 bool p_specific_at_least_once = false;
4017 bool q_specific_at_least_once = false;
4019 for (int i = 0; i < pargs.Length; i++)
4021 Type specific = MoreSpecific (pargs [i], qargs [i]);
4022 if (specific == pargs [i])
4023 p_specific_at_least_once = true;
4024 if (specific == qargs [i])
4025 q_specific_at_least_once = true;
4028 if (p_specific_at_least_once && !q_specific_at_least_once)
4030 if (!p_specific_at_least_once && q_specific_at_least_once)
4037 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4039 base.MutateHoistedGenericType (storey);
4041 MethodInfo mi = best_candidate as MethodInfo;
4043 best_candidate = storey.MutateGenericMethod (mi);
4047 best_candidate = storey.MutateConstructor ((ConstructorInfo) this);
4051 /// Find the Applicable Function Members (7.4.2.1)
4053 /// me: Method Group expression with the members to select.
4054 /// it might contain constructors or methods (or anything
4055 /// that maps to a method).
4057 /// Arguments: ArrayList containing resolved Argument objects.
4059 /// loc: The location if we want an error to be reported, or a Null
4060 /// location for "probing" purposes.
4062 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4063 /// that is the best match of me on Arguments.
4066 public virtual MethodGroupExpr OverloadResolve (EmitContext ec, ref ArrayList Arguments,
4067 bool may_fail, Location loc)
4069 bool method_params = false;
4070 Type applicable_type = null;
4072 ArrayList candidates = new ArrayList (2);
4073 ArrayList candidate_overrides = null;
4076 // Used to keep a map between the candidate
4077 // and whether it is being considered in its
4078 // normal or expanded form
4080 // false is normal form, true is expanded form
4082 Hashtable candidate_to_form = null;
4084 if (Arguments != null)
4085 arg_count = Arguments.Count;
4087 if (RootContext.Version == LanguageVersion.ISO_1 && Name == "Invoke" && TypeManager.IsDelegateType (DeclaringType)) {
4089 Report.Error (1533, loc, "Invoke cannot be called directly on a delegate");
4093 int nmethods = Methods.Length;
4097 // Methods marked 'override' don't take part in 'applicable_type'
4098 // computation, nor in the actual overload resolution.
4099 // However, they still need to be emitted instead of a base virtual method.
4100 // So, we salt them away into the 'candidate_overrides' array.
4102 // In case of reflected methods, we replace each overriding method with
4103 // its corresponding base virtual method. This is to improve compatibility
4104 // with non-C# libraries which change the visibility of overrides (#75636)
4107 for (int i = 0; i < Methods.Length; ++i) {
4108 MethodBase m = Methods [i];
4109 if (TypeManager.IsOverride (m)) {
4110 if (candidate_overrides == null)
4111 candidate_overrides = new ArrayList ();
4112 candidate_overrides.Add (m);
4113 m = TypeManager.TryGetBaseDefinition (m);
4122 // Enable message recording, it's used mainly by lambda expressions
4124 Report.IMessageRecorder msg_recorder = new Report.MessageRecorder ();
4125 Report.IMessageRecorder prev_recorder = Report.SetMessageRecorder (msg_recorder);
4128 // First we construct the set of applicable methods
4130 bool is_sorted = true;
4131 int best_candidate_rate = int.MaxValue;
4132 for (int i = 0; i < nmethods; i++) {
4133 Type decl_type = Methods [i].DeclaringType;
4136 // If we have already found an applicable method
4137 // we eliminate all base types (Section 14.5.5.1)
4139 if (applicable_type != null && IsAncestralType (decl_type, applicable_type))
4143 // Check if candidate is applicable (section 14.4.2.1)
4145 bool params_expanded_form = false;
4146 int candidate_rate = IsApplicable (ec, Arguments, arg_count, ref Methods [i], ref params_expanded_form);
4148 if (candidate_rate < best_candidate_rate) {
4149 best_candidate_rate = candidate_rate;
4150 best_candidate = Methods [i];
4153 if (params_expanded_form) {
4154 if (candidate_to_form == null)
4155 candidate_to_form = new PtrHashtable ();
4156 MethodBase candidate = Methods [i];
4157 candidate_to_form [candidate] = candidate;
4160 if (candidate_rate != 0) {
4161 if (msg_recorder != null)
4162 msg_recorder.EndSession ();
4166 msg_recorder = null;
4167 candidates.Add (Methods [i]);
4169 if (applicable_type == null)
4170 applicable_type = decl_type;
4171 else if (applicable_type != decl_type) {
4173 if (IsAncestralType (applicable_type, decl_type))
4174 applicable_type = decl_type;
4178 Report.SetMessageRecorder (prev_recorder);
4179 if (msg_recorder != null && !msg_recorder.IsEmpty) {
4181 msg_recorder.PrintMessages ();
4186 int candidate_top = candidates.Count;
4188 if (applicable_type == null) {
4190 // When we found a top level method which does not match and it's
4191 // not an extension method. We start extension methods lookup from here
4193 if (InstanceExpression != null) {
4194 ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (type, Name, loc);
4195 if (ex_method_lookup != null) {
4196 ex_method_lookup.ExtensionExpression = InstanceExpression;
4197 ex_method_lookup.SetTypeArguments (type_arguments);
4198 return ex_method_lookup.OverloadResolve (ec, ref Arguments, may_fail, loc);
4206 // Okay so we have failed to find exact match so we
4207 // return error info about the closest match
4209 if (best_candidate != null) {
4210 if (CustomErrorHandler != null) {
4211 if (CustomErrorHandler.NoExactMatch (ec, best_candidate))
4215 ParameterData pd = TypeManager.GetParameterData (best_candidate);
4216 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4217 if (arg_count == pd.Count || pd.HasParams) {
4218 if (TypeManager.IsGenericMethodDefinition (best_candidate)) {
4219 if (type_arguments == null) {
4220 Report.Error (411, loc,
4221 "The type arguments for method `{0}' cannot be inferred from " +
4222 "the usage. Try specifying the type arguments explicitly",
4223 TypeManager.CSharpSignature (best_candidate));
4227 Type [] g_args = TypeManager.GetGenericArguments (best_candidate);
4228 if (type_arguments.Count != g_args.Length) {
4229 Report.SymbolRelatedToPreviousError (best_candidate);
4230 Report.Error (305, loc, "Using the generic method `{0}' requires `{1}' type argument(s)",
4231 TypeManager.CSharpSignature (best_candidate),
4232 g_args.Length.ToString ());
4236 if (type_arguments != null && !TypeManager.IsGenericMethod (best_candidate)) {
4237 Namespace.Error_TypeArgumentsCannotBeUsed (best_candidate, loc);
4242 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate, cand_params, may_fail, loc))
4247 if (almost_matched_members.Count != 0) {
4248 Error_MemberLookupFailed (ec.ContainerType, type, type, ".ctor",
4249 null, MemberTypes.Constructor, AllBindingFlags);
4254 // We failed to find any method with correct argument count
4256 if (Name == ConstructorInfo.ConstructorName) {
4257 Report.SymbolRelatedToPreviousError (type);
4258 Report.Error (1729, loc,
4259 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4260 TypeManager.CSharpName (type), arg_count);
4262 Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4263 Name, arg_count.ToString ());
4271 // At this point, applicable_type is _one_ of the most derived types
4272 // in the set of types containing the methods in this MethodGroup.
4273 // Filter the candidates so that they only contain methods from the
4274 // most derived types.
4277 int finalized = 0; // Number of finalized candidates
4280 // Invariant: applicable_type is a most derived type
4282 // We'll try to complete Section 14.5.5.1 for 'applicable_type' by
4283 // eliminating all it's base types. At the same time, we'll also move
4284 // every unrelated type to the end of the array, and pick the next
4285 // 'applicable_type'.
4287 Type next_applicable_type = null;
4288 int j = finalized; // where to put the next finalized candidate
4289 int k = finalized; // where to put the next undiscarded candidate
4290 for (int i = finalized; i < candidate_top; ++i) {
4291 MethodBase candidate = (MethodBase) candidates [i];
4292 Type decl_type = candidate.DeclaringType;
4294 if (decl_type == applicable_type) {
4295 candidates [k++] = candidates [j];
4296 candidates [j++] = candidates [i];
4300 if (IsAncestralType (decl_type, applicable_type))
4303 if (next_applicable_type != null &&
4304 IsAncestralType (decl_type, next_applicable_type))
4307 candidates [k++] = candidates [i];
4309 if (next_applicable_type == null ||
4310 IsAncestralType (next_applicable_type, decl_type))
4311 next_applicable_type = decl_type;
4314 applicable_type = next_applicable_type;
4317 } while (applicable_type != null);
4321 // Now we actually find the best method
4324 best_candidate = (MethodBase) candidates [0];
4325 if (delegate_type == null)
4326 method_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4328 for (int ix = 1; ix < candidate_top; ix++) {
4329 MethodBase candidate = (MethodBase) candidates [ix];
4331 if (candidate == best_candidate)
4334 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4336 if (BetterFunction (ec, Arguments, arg_count,
4337 candidate, cand_params,
4338 best_candidate, method_params)) {
4339 best_candidate = candidate;
4340 method_params = cand_params;
4344 // Now check that there are no ambiguities i.e the selected method
4345 // should be better than all the others
4347 MethodBase ambiguous = null;
4348 for (int ix = 1; ix < candidate_top; ix++) {
4349 MethodBase candidate = (MethodBase) candidates [ix];
4351 if (candidate == best_candidate)
4354 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4355 if (!BetterFunction (ec, Arguments, arg_count,
4356 best_candidate, method_params,
4357 candidate, cand_params))
4360 Report.SymbolRelatedToPreviousError (candidate);
4361 ambiguous = candidate;
4365 if (ambiguous != null) {
4366 Report.SymbolRelatedToPreviousError (ambiguous);
4367 Report.SymbolRelatedToPreviousError (best_candidate);
4368 Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4369 TypeManager.CSharpSignature (ambiguous), TypeManager.CSharpSignature (best_candidate));
4374 // If the method is a virtual function, pick an override closer to the LHS type.
4376 if (!IsBase && best_candidate.IsVirtual) {
4377 if (TypeManager.IsOverride (best_candidate))
4378 throw new InternalErrorException (
4379 "Should not happen. An 'override' method took part in overload resolution: " + best_candidate);
4381 if (candidate_overrides != null) {
4382 Type[] gen_args = null;
4383 bool gen_override = false;
4384 if (TypeManager.IsGenericMethod (best_candidate))
4385 gen_args = TypeManager.GetGenericArguments (best_candidate);
4387 foreach (MethodBase candidate in candidate_overrides) {
4388 if (TypeManager.IsGenericMethod (candidate)) {
4389 if (gen_args == null)
4392 if (gen_args.Length != TypeManager.GetGenericArguments (candidate).Length)
4395 if (gen_args != null)
4399 if (IsOverride (candidate, best_candidate)) {
4400 gen_override = true;
4401 best_candidate = candidate;
4405 if (gen_override && gen_args != null) {
4407 best_candidate = ((MethodInfo) best_candidate).MakeGenericMethod (gen_args);
4414 // And now check if the arguments are all
4415 // compatible, perform conversions if
4416 // necessary etc. and return if everything is
4419 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate,
4420 method_params, may_fail, loc))
4423 if (best_candidate == null)
4426 MethodBase the_method = TypeManager.DropGenericMethodArguments (best_candidate);
4428 if (the_method.IsGenericMethodDefinition &&
4429 !ConstraintChecker.CheckConstraints (ec, the_method, best_candidate, loc))
4433 IMethodData data = TypeManager.GetMethod (the_method);
4435 data.SetMemberIsUsed ();
4440 public override void SetTypeArguments (TypeArguments ta)
4442 type_arguments = ta;
4445 public bool VerifyArgumentsCompat (EmitContext ec, ref ArrayList arguments,
4446 int arg_count, MethodBase method,
4447 bool chose_params_expanded,
4448 bool may_fail, Location loc)
4450 ParameterData pd = TypeManager.GetParameterData (method);
4452 int errors = Report.Errors;
4453 Parameter.Modifier p_mod = 0;
4455 int a_idx = 0, a_pos = 0;
4457 ArrayList params_initializers = null;
4458 bool has_unsafe_arg = false;
4460 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4461 a = (Argument) arguments [a_idx];
4462 if (p_mod != Parameter.Modifier.PARAMS) {
4463 p_mod = pd.ParameterModifier (a_idx);
4464 pt = pd.ParameterType (a_idx);
4465 has_unsafe_arg |= pt.IsPointer;
4467 if (p_mod == Parameter.Modifier.ARGLIST) {
4468 if (a.Type != TypeManager.runtime_argument_handle_type)
4473 if (p_mod == Parameter.Modifier.PARAMS) {
4474 if (chose_params_expanded) {
4475 params_initializers = new ArrayList (arg_count - a_idx);
4476 pt = TypeManager.GetElementType (pt);
4478 } else if (p_mod != 0) {
4479 pt = TypeManager.GetElementType (pt);
4484 // Types have to be identical when ref or out modifer is used
4486 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4487 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4490 if (!TypeManager.IsEqual (a.Expr.Type, pt))
4497 if (TypeManager.IsEqual (a.Type, pt)) {
4500 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4506 // Convert params arguments to an array initializer
4508 if (params_initializers != null) {
4509 // we choose to use 'a.Expr' rather than 'conv' so that
4510 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
4511 params_initializers.Add (a.Expr);
4512 arguments.RemoveAt (a_idx--);
4517 // Update the argument with the implicit conversion
4522 // Fill not provided arguments required by params modifier
4524 if (params_initializers == null && pd.HasParams && arg_count < pd.Count && a_idx + 1 == pd.Count) {
4525 if (arguments == null)
4526 arguments = new ArrayList (1);
4528 pt = pd.Types [GetApplicableParametersCount (method, pd) - 1];
4529 pt = TypeManager.GetElementType (pt);
4530 has_unsafe_arg |= pt.IsPointer;
4531 params_initializers = new ArrayList (0);
4534 if (a_idx == arg_count) {
4536 // Append an array argument with all params arguments
4538 if (params_initializers != null) {
4539 arguments.Add (new Argument (
4540 new ArrayCreation (new TypeExpression (pt, loc), "[]",
4541 params_initializers, loc).Resolve (ec)));
4544 if (has_unsafe_arg && !ec.InUnsafe) {
4553 if (!may_fail && Report.Errors == errors) {
4554 if (CustomErrorHandler != null)
4555 CustomErrorHandler.NoExactMatch (ec, best_candidate);
4557 Error_InvalidArguments (ec, loc, a_pos, method, a, pd, pt);
4563 public class ConstantExpr : MemberExpr
4567 public ConstantExpr (FieldInfo constant, Location loc)
4569 this.constant = constant;
4573 public override string Name {
4574 get { throw new NotImplementedException (); }
4577 public override bool IsInstance {
4578 get { return !IsStatic; }
4581 public override bool IsStatic {
4582 get { return constant.IsStatic; }
4585 public override Type DeclaringType {
4586 get { return constant.DeclaringType; }
4589 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc, SimpleName original)
4591 constant = TypeManager.GetGenericFieldDefinition (constant);
4593 IConstant ic = TypeManager.GetConstant (constant);
4595 if (constant.IsLiteral) {
4596 ic = new ExternalConstant (constant);
4598 ic = ExternalConstant.CreateDecimal (constant);
4599 // HACK: decimal field was not resolved as constant
4601 return new FieldExpr (constant, loc).ResolveMemberAccess (ec, left, loc, original);
4603 TypeManager.RegisterConstant (constant, ic);
4606 return base.ResolveMemberAccess (ec, left, loc, original);
4609 public override Expression CreateExpressionTree (EmitContext ec)
4611 throw new NotSupportedException ("ET");
4614 public override Expression DoResolve (EmitContext ec)
4616 IConstant ic = TypeManager.GetConstant (constant);
4617 if (ic.ResolveValue ()) {
4618 if (!ec.IsInObsoleteScope)
4619 ic.CheckObsoleteness (loc);
4622 return ic.CreateConstantReference (loc);
4625 public override void Emit (EmitContext ec)
4627 throw new NotSupportedException ();
4630 public override string GetSignatureForError ()
4632 return TypeManager.GetFullNameSignature (constant);
4637 /// Fully resolved expression that evaluates to a Field
4639 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariableReference {
4640 public FieldInfo FieldInfo;
4641 readonly Type constructed_generic_type;
4642 VariableInfo variable_info;
4644 LocalTemporary temp;
4646 bool in_initializer;
4648 public FieldExpr (FieldInfo fi, Location l, bool in_initializer):
4651 this.in_initializer = in_initializer;
4654 public FieldExpr (FieldInfo fi, Location l)
4657 eclass = ExprClass.Variable;
4658 type = TypeManager.TypeToCoreType (fi.FieldType);
4662 public FieldExpr (FieldInfo fi, Type genericType, Location l)
4665 this.constructed_generic_type = genericType;
4668 public override string Name {
4670 return FieldInfo.Name;
4674 public override bool IsInstance {
4676 return !FieldInfo.IsStatic;
4680 public override bool IsStatic {
4682 return FieldInfo.IsStatic;
4686 public override Type DeclaringType {
4688 return FieldInfo.DeclaringType;
4692 public override string GetSignatureForError ()
4694 return TypeManager.GetFullNameSignature (FieldInfo);
4697 public VariableInfo VariableInfo {
4699 return variable_info;
4703 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
4704 SimpleName original)
4706 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
4707 Type t = fi.FieldType;
4709 if (t.IsPointer && !ec.InUnsafe) {
4713 return base.ResolveMemberAccess (ec, left, loc, original);
4716 public void SetHasAddressTaken ()
4718 IVariableReference vr = InstanceExpression as IVariableReference;
4720 vr.SetHasAddressTaken ();
4723 public override Expression CreateExpressionTree (EmitContext ec)
4725 Expression instance;
4726 if (InstanceExpression == null) {
4727 instance = new NullLiteral (loc);
4729 instance = InstanceExpression.CreateExpressionTree (ec);
4732 ArrayList args = new ArrayList (2);
4733 args.Add (new Argument (instance));
4734 args.Add (new Argument (CreateTypeOfExpression ()));
4735 return CreateExpressionFactoryCall ("Field", args);
4738 public Expression CreateTypeOfExpression ()
4740 return new TypeOfField (FieldInfo, loc);
4743 override public Expression DoResolve (EmitContext ec)
4745 return DoResolve (ec, false, false);
4748 Expression DoResolve (EmitContext ec, bool lvalue_instance, bool out_access)
4750 if (!FieldInfo.IsStatic){
4751 if (InstanceExpression == null){
4753 // This can happen when referencing an instance field using
4754 // a fully qualified type expression: TypeName.InstanceField = xxx
4756 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4760 // Resolve the field's instance expression while flow analysis is turned
4761 // off: when accessing a field "a.b", we must check whether the field
4762 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4764 if (lvalue_instance) {
4765 using (ec.With (EmitContext.Flags.DoFlowAnalysis, false)) {
4766 Expression right_side =
4767 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4768 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side, loc);
4771 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
4772 InstanceExpression = InstanceExpression.Resolve (ec, rf);
4775 if (InstanceExpression == null)
4778 using (ec.Set (EmitContext.Flags.OmitStructFlowAnalysis)) {
4779 InstanceExpression.CheckMarshalByRefAccess (ec);
4783 if (!in_initializer && !ec.IsInFieldInitializer) {
4784 ObsoleteAttribute oa;
4785 FieldBase f = TypeManager.GetField (FieldInfo);
4787 if (!ec.IsInObsoleteScope)
4788 f.CheckObsoleteness (loc);
4790 // To be sure that type is external because we do not register generated fields
4791 } else if (!(FieldInfo.DeclaringType is TypeBuilder)) {
4792 oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
4794 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
4798 IFixedBuffer fb = AttributeTester.GetFixedBuffer (FieldInfo);
4799 IVariableReference var = InstanceExpression as IVariableReference;
4802 if (!ec.InFixedInitializer && ec.ContainerType.IsValueType) {
4803 Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4806 if (InstanceExpression.eclass != ExprClass.Variable) {
4807 Report.SymbolRelatedToPreviousError (FieldInfo);
4808 Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4809 TypeManager.GetFullNameSignature (FieldInfo));
4810 } else if (var != null && var.IsHoisted) {
4811 AnonymousMethodExpression.Error_AddressOfCapturedVar (var, loc);
4814 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4817 // If the instance expression is a local variable or parameter.
4818 if (var == null || var.VariableInfo == null)
4821 VariableInfo vi = var.VariableInfo;
4822 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
4825 variable_info = vi.GetSubStruct (FieldInfo.Name);
4829 static readonly int [] codes = {
4830 191, // instance, write access
4831 192, // instance, out access
4832 198, // static, write access
4833 199, // static, out access
4834 1648, // member of value instance, write access
4835 1649, // member of value instance, out access
4836 1650, // member of value static, write access
4837 1651 // member of value static, out access
4840 static readonly string [] msgs = {
4841 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4842 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4843 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4844 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4845 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4846 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4847 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4848 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4851 // The return value is always null. Returning a value simplifies calling code.
4852 Expression Report_AssignToReadonly (Expression right_side)
4855 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4859 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4861 Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4866 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4868 IVariableReference var = InstanceExpression as IVariableReference;
4869 if (var != null && var.VariableInfo != null)
4870 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
4872 bool lvalue_instance = !FieldInfo.IsStatic && FieldInfo.DeclaringType.IsValueType;
4873 bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
4875 Expression e = DoResolve (ec, lvalue_instance, out_access);
4880 FieldBase fb = TypeManager.GetField (FieldInfo);
4884 if (FieldInfo.IsInitOnly) {
4885 // InitOnly fields can only be assigned in constructors or initializers
4886 if (!ec.IsInFieldInitializer && !ec.IsConstructor)
4887 return Report_AssignToReadonly (right_side);
4889 if (ec.IsConstructor) {
4890 Type ctype = ec.TypeContainer.CurrentType;
4892 ctype = ec.ContainerType;
4894 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4895 if (!TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
4896 return Report_AssignToReadonly (right_side);
4897 // static InitOnly fields cannot be assigned-to in an instance constructor
4898 if (IsStatic && !ec.IsStatic)
4899 return Report_AssignToReadonly (right_side);
4900 // instance constructors can't modify InitOnly fields of other instances of the same type
4901 if (!IsStatic && !(InstanceExpression is This))
4902 return Report_AssignToReadonly (right_side);
4906 if (right_side == EmptyExpression.OutAccess &&
4907 !IsStatic && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type)) {
4908 Report.SymbolRelatedToPreviousError (DeclaringType);
4909 Report.Warning (197, 1, loc,
4910 "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",
4911 GetSignatureForError ());
4917 bool is_marshal_by_ref ()
4919 return !IsStatic && Type.IsValueType && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type);
4922 public override void CheckMarshalByRefAccess (EmitContext ec)
4924 if (is_marshal_by_ref () && !(InstanceExpression is This)) {
4925 Report.SymbolRelatedToPreviousError (DeclaringType);
4926 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",
4927 GetSignatureForError ());
4931 public override int GetHashCode ()
4933 return FieldInfo.GetHashCode ();
4936 public bool IsFixedVariable {
4939 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
4941 IVariableReference variable = InstanceExpression as IVariableReference;
4942 return variable != null && InstanceExpression.Type.IsValueType && variable.IsFixedVariable;
4946 public bool IsHoisted {
4948 IVariableReference hv = InstanceExpression as IVariableReference;
4949 return hv != null && hv.IsHoisted;
4953 public override bool Equals (object obj)
4955 FieldExpr fe = obj as FieldExpr;
4959 if (FieldInfo != fe.FieldInfo)
4962 if (InstanceExpression == null || fe.InstanceExpression == null)
4965 return InstanceExpression.Equals (fe.InstanceExpression);
4968 public void Emit (EmitContext ec, bool leave_copy)
4970 ILGenerator ig = ec.ig;
4971 bool is_volatile = false;
4973 FieldBase f = TypeManager.GetField (FieldInfo);
4975 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4978 f.SetMemberIsUsed ();
4981 if (FieldInfo.IsStatic){
4983 ig.Emit (OpCodes.Volatile);
4985 ig.Emit (OpCodes.Ldsfld, GetConstructedFieldInfo ());
4988 EmitInstance (ec, false);
4990 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
4992 ig.Emit (OpCodes.Ldflda, GetConstructedFieldInfo ());
4993 ig.Emit (OpCodes.Ldflda, ff.Element);
4996 ig.Emit (OpCodes.Volatile);
4998 ig.Emit (OpCodes.Ldfld, GetConstructedFieldInfo ());
5003 ec.ig.Emit (OpCodes.Dup);
5004 if (!FieldInfo.IsStatic) {
5005 temp = new LocalTemporary (this.Type);
5011 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5013 FieldAttributes fa = FieldInfo.Attributes;
5014 bool is_static = (fa & FieldAttributes.Static) != 0;
5015 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
5016 ILGenerator ig = ec.ig;
5018 if (is_readonly && !ec.IsConstructor){
5019 Report_AssignToReadonly (source);
5023 prepared = prepare_for_load;
5024 EmitInstance (ec, prepared);
5028 ec.ig.Emit (OpCodes.Dup);
5029 if (!FieldInfo.IsStatic) {
5030 temp = new LocalTemporary (this.Type);
5035 FieldBase f = TypeManager.GetField (FieldInfo);
5037 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
5038 ig.Emit (OpCodes.Volatile);
5044 ig.Emit (OpCodes.Stsfld, GetConstructedFieldInfo ());
5046 ig.Emit (OpCodes.Stfld, GetConstructedFieldInfo ());
5055 public override void Emit (EmitContext ec)
5060 public override void EmitSideEffect (EmitContext ec)
5062 FieldBase f = TypeManager.GetField (FieldInfo);
5063 bool is_volatile = f != null && (f.ModFlags & Modifiers.VOLATILE) != 0;
5065 if (is_volatile || is_marshal_by_ref ())
5066 base.EmitSideEffect (ec);
5069 public override void Error_VariableIsUsedBeforeItIsDeclared (string name)
5071 Report.Error (844, loc,
5072 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the field `{1}'",
5073 name, GetSignatureForError ());
5076 public void AddressOf (EmitContext ec, AddressOp mode)
5078 ILGenerator ig = ec.ig;
5080 FieldBase f = TypeManager.GetField (FieldInfo);
5082 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
5083 Report.Warning (420, 1, loc, "`{0}': A volatile field references will not be treated as volatile",
5084 f.GetSignatureForError ());
5087 if ((mode & AddressOp.Store) != 0)
5089 if ((mode & AddressOp.Load) != 0)
5090 f.SetMemberIsUsed ();
5094 // Handle initonly fields specially: make a copy and then
5095 // get the address of the copy.
5098 if (FieldInfo.IsInitOnly){
5100 if (ec.IsConstructor){
5101 if (FieldInfo.IsStatic){
5113 local = ig.DeclareLocal (type);
5114 ig.Emit (OpCodes.Stloc, local);
5115 ig.Emit (OpCodes.Ldloca, local);
5120 if (FieldInfo.IsStatic){
5121 ig.Emit (OpCodes.Ldsflda, GetConstructedFieldInfo ());
5124 EmitInstance (ec, false);
5125 ig.Emit (OpCodes.Ldflda, GetConstructedFieldInfo ());
5129 FieldInfo GetConstructedFieldInfo ()
5131 if (constructed_generic_type == null)
5134 return TypeBuilder.GetField (constructed_generic_type, FieldInfo);
5136 throw new NotSupportedException ();
5140 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5142 FieldInfo = storey.MutateField (FieldInfo);
5143 base.MutateHoistedGenericType (storey);
5149 /// Expression that evaluates to a Property. The Assign class
5150 /// might set the `Value' expression if we are in an assignment.
5152 /// This is not an LValue because we need to re-write the expression, we
5153 /// can not take data from the stack and store it.
5155 public class PropertyExpr : MemberExpr, IAssignMethod {
5156 public readonly PropertyInfo PropertyInfo;
5157 MethodInfo getter, setter;
5162 LocalTemporary temp;
5165 public PropertyExpr (Type container_type, PropertyInfo pi, Location l)
5168 eclass = ExprClass.PropertyAccess;
5172 type = TypeManager.TypeToCoreType (pi.PropertyType);
5174 ResolveAccessors (container_type);
5177 public override string Name {
5179 return PropertyInfo.Name;
5183 public override bool IsInstance {
5189 public override bool IsStatic {
5195 public override Expression CreateExpressionTree (EmitContext ec)
5198 if (IsSingleDimensionalArrayLength ()) {
5199 args = new ArrayList (1);
5200 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5201 return CreateExpressionFactoryCall ("ArrayLength", args);
5205 Error_BaseAccessInExpressionTree (loc);
5209 args = new ArrayList (2);
5210 if (InstanceExpression == null)
5211 args.Add (new Argument (new NullLiteral (loc)));
5213 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5214 args.Add (new Argument (new TypeOfMethodInfo (getter, loc)));
5215 return CreateExpressionFactoryCall ("Property", args);
5218 public Expression CreateSetterTypeOfExpression ()
5220 return new TypeOfMethodInfo (setter, loc);
5223 public override Type DeclaringType {
5225 return PropertyInfo.DeclaringType;
5229 public override string GetSignatureForError ()
5231 return TypeManager.GetFullNameSignature (PropertyInfo);
5234 void FindAccessors (Type invocation_type)
5236 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
5237 BindingFlags.Static | BindingFlags.Instance |
5238 BindingFlags.DeclaredOnly;
5240 Type current = PropertyInfo.DeclaringType;
5241 for (; current != null; current = current.BaseType) {
5242 MemberInfo[] group = TypeManager.MemberLookup (
5243 invocation_type, invocation_type, current,
5244 MemberTypes.Property, flags, PropertyInfo.Name, null);
5249 if (group.Length != 1)
5250 // Oooops, can this ever happen ?
5253 PropertyInfo pi = (PropertyInfo) group [0];
5256 getter = pi.GetGetMethod (true);
5259 setter = pi.GetSetMethod (true);
5261 MethodInfo accessor = getter != null ? getter : setter;
5263 if (!accessor.IsVirtual)
5269 // We also perform the permission checking here, as the PropertyInfo does not
5270 // hold the information for the accessibility of its setter/getter
5272 // TODO: Refactor to use some kind of cache together with GetPropertyFromAccessor
5273 void ResolveAccessors (Type container_type)
5275 FindAccessors (container_type);
5277 if (getter != null) {
5278 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
5279 IMethodData md = TypeManager.GetMethod (the_getter);
5281 md.SetMemberIsUsed ();
5283 is_static = getter.IsStatic;
5286 if (setter != null) {
5287 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
5288 IMethodData md = TypeManager.GetMethod (the_setter);
5290 md.SetMemberIsUsed ();
5292 is_static = setter.IsStatic;
5296 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5298 if (InstanceExpression != null)
5299 InstanceExpression.MutateHoistedGenericType (storey);
5301 type = storey.MutateType (type);
5302 getter = storey.MutateGenericMethod (getter);
5305 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
5308 InstanceExpression = null;
5312 if (InstanceExpression == null) {
5313 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5317 InstanceExpression = InstanceExpression.DoResolve (ec);
5318 if (lvalue_instance && InstanceExpression != null)
5319 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
5321 if (InstanceExpression == null)
5324 InstanceExpression.CheckMarshalByRefAccess (ec);
5326 if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) &&
5327 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
5328 !TypeManager.IsNestedChildOf (ec.ContainerType, InstanceExpression.Type) &&
5329 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.ContainerType)) {
5330 Report.SymbolRelatedToPreviousError (PropertyInfo);
5331 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
5338 void Error_PropertyNotFound (MethodInfo mi, bool getter)
5340 // TODO: correctly we should compare arguments but it will lead to bigger changes
5341 if (mi is MethodBuilder) {
5342 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
5346 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
5348 ParameterData iparams = TypeManager.GetParameterData (mi);
5349 sig.Append (getter ? "get_" : "set_");
5351 sig.Append (iparams.GetSignatureForError ());
5353 Report.SymbolRelatedToPreviousError (mi);
5354 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
5355 Name, sig.ToString ());
5358 public bool IsAccessibleFrom (Type invocation_type, bool lvalue)
5361 MethodInfo accessor = lvalue ? setter : getter;
5362 if (accessor == null && lvalue)
5364 return accessor != null && IsAccessorAccessible (invocation_type, accessor, out dummy);
5367 bool IsSingleDimensionalArrayLength ()
5369 if (DeclaringType != TypeManager.array_type || getter == null || Name != "Length")
5372 string t_name = InstanceExpression.Type.Name;
5373 int t_name_len = t_name.Length;
5374 return t_name_len > 2 && t_name [t_name_len - 2] == '[';
5377 override public Expression DoResolve (EmitContext ec)
5382 if (getter != null){
5383 if (TypeManager.GetParameterData (getter).Count != 0){
5384 Error_PropertyNotFound (getter, true);
5389 if (getter == null){
5391 // The following condition happens if the PropertyExpr was
5392 // created, but is invalid (ie, the property is inaccessible),
5393 // and we did not want to embed the knowledge about this in
5394 // the caller routine. This only avoids double error reporting.
5399 if (InstanceExpression != EmptyExpression.Null) {
5400 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5401 TypeManager.GetFullNameSignature (PropertyInfo));
5406 bool must_do_cs1540_check = false;
5407 if (getter != null &&
5408 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
5409 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
5410 if (pm != null && pm.HasCustomAccessModifier) {
5411 Report.SymbolRelatedToPreviousError (pm);
5412 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5413 TypeManager.CSharpSignature (getter));
5416 Report.SymbolRelatedToPreviousError (getter);
5417 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
5422 if (!InstanceResolve (ec, false, must_do_cs1540_check))
5426 // Only base will allow this invocation to happen.
5428 if (IsBase && getter.IsAbstract) {
5429 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5433 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
5443 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
5445 if (right_side == EmptyExpression.OutAccess) {
5446 if (ec.CurrentBlock.Toplevel.GetTransparentIdentifier (PropertyInfo.Name) != null) {
5447 Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5450 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as `ref' or `out' parameter",
5451 GetSignatureForError ());
5456 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5457 Error_CannotModifyIntermediateExpressionValue (ec);
5460 if (setter == null){
5462 // The following condition happens if the PropertyExpr was
5463 // created, but is invalid (ie, the property is inaccessible),
5464 // and we did not want to embed the knowledge about this in
5465 // the caller routine. This only avoids double error reporting.
5470 if (ec.CurrentBlock.Toplevel.GetTransparentIdentifier (PropertyInfo.Name) != null) {
5471 Report.Error (1947, loc, "A range variable `{0}' cannot be assigned to. Consider using `let' clause to store the value",
5474 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
5475 GetSignatureForError ());
5480 if (TypeManager.GetParameterData (setter).Count != 1){
5481 Error_PropertyNotFound (setter, false);
5485 bool must_do_cs1540_check;
5486 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
5487 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
5488 if (pm != null && pm.HasCustomAccessModifier) {
5489 Report.SymbolRelatedToPreviousError (pm);
5490 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5491 TypeManager.CSharpSignature (setter));
5494 Report.SymbolRelatedToPreviousError (setter);
5495 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
5500 if (!InstanceResolve (ec, PropertyInfo.DeclaringType.IsValueType, must_do_cs1540_check))
5504 // Only base will allow this invocation to happen.
5506 if (IsBase && setter.IsAbstract){
5507 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5511 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe) {
5518 public override void Emit (EmitContext ec)
5523 public void Emit (EmitContext ec, bool leave_copy)
5526 // Special case: length of single dimension array property is turned into ldlen
5528 if (IsSingleDimensionalArrayLength ()) {
5530 EmitInstance (ec, false);
5531 ec.ig.Emit (OpCodes.Ldlen);
5532 ec.ig.Emit (OpCodes.Conv_I4);
5536 Invocation.EmitCall (ec, IsBase, InstanceExpression, getter, null, loc, prepared, false);
5539 ec.ig.Emit (OpCodes.Dup);
5541 temp = new LocalTemporary (this.Type);
5548 // Implements the IAssignMethod interface for assignments
5550 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5552 Expression my_source = source;
5554 if (prepare_for_load) {
5559 ec.ig.Emit (OpCodes.Dup);
5561 temp = new LocalTemporary (this.Type);
5565 } else if (leave_copy) {
5567 temp = new LocalTemporary (this.Type);
5572 ArrayList args = new ArrayList (1);
5573 args.Add (new Argument (my_source, Argument.AType.Expression));
5575 Invocation.EmitCall (ec, IsBase, InstanceExpression, setter, args, loc, false, prepared);
5585 /// Fully resolved expression that evaluates to an Event
5587 public class EventExpr : MemberExpr {
5588 public readonly EventInfo EventInfo;
5591 MethodInfo add_accessor, remove_accessor;
5593 public EventExpr (EventInfo ei, Location loc)
5597 eclass = ExprClass.EventAccess;
5599 add_accessor = TypeManager.GetAddMethod (ei);
5600 remove_accessor = TypeManager.GetRemoveMethod (ei);
5601 if (add_accessor.IsStatic || remove_accessor.IsStatic)
5604 if (EventInfo is MyEventBuilder){
5605 MyEventBuilder eb = (MyEventBuilder) EventInfo;
5606 type = eb.EventType;
5609 type = EventInfo.EventHandlerType;
5612 public override string Name {
5614 return EventInfo.Name;
5618 public override bool IsInstance {
5624 public override bool IsStatic {
5630 public override Type DeclaringType {
5632 return EventInfo.DeclaringType;
5636 void Error_AssignmentEventOnly ()
5638 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5639 GetSignatureForError ());
5642 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
5643 SimpleName original)
5646 // If the event is local to this class, we transform ourselves into a FieldExpr
5649 if (EventInfo.DeclaringType == ec.ContainerType ||
5650 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
5651 EventField mi = TypeManager.GetEventField (EventInfo);
5654 if (!ec.IsInObsoleteScope)
5655 mi.CheckObsoleteness (loc);
5657 if ((mi.ModFlags & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0 && !ec.IsInCompoundAssignment)
5658 Error_AssignmentEventOnly ();
5660 FieldExpr ml = new FieldExpr (mi.FieldBuilder, loc);
5662 InstanceExpression = null;
5664 return ml.ResolveMemberAccess (ec, left, loc, original);
5668 if (left is This && !ec.IsInCompoundAssignment)
5669 Error_AssignmentEventOnly ();
5671 return base.ResolveMemberAccess (ec, left, loc, original);
5674 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
5677 InstanceExpression = null;
5681 if (InstanceExpression == null) {
5682 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5686 InstanceExpression = InstanceExpression.DoResolve (ec);
5687 if (InstanceExpression == null)
5690 if (IsBase && add_accessor.IsAbstract) {
5691 Error_CannotCallAbstractBase(TypeManager.CSharpSignature(add_accessor));
5696 // This is using the same mechanism as the CS1540 check in PropertyExpr.
5697 // However, in the Event case, we reported a CS0122 instead.
5699 // TODO: Exact copy from PropertyExpr
5701 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
5702 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
5703 !TypeManager.IsNestedChildOf (ec.ContainerType, InstanceExpression.Type) &&
5704 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.ContainerType)) {
5705 Report.SymbolRelatedToPreviousError (EventInfo);
5706 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5713 public bool IsAccessibleFrom (Type invocation_type)
5716 return IsAccessorAccessible (invocation_type, add_accessor, out dummy) &&
5717 IsAccessorAccessible (invocation_type, remove_accessor, out dummy);
5720 public override Expression CreateExpressionTree (EmitContext ec)
5722 throw new NotSupportedException ("ET");
5725 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5727 // contexts where an LValue is valid have already devolved to FieldExprs
5728 Error_CannotAssign ();
5732 public override Expression DoResolve (EmitContext ec)
5734 bool must_do_cs1540_check;
5735 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
5736 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
5737 Report.SymbolRelatedToPreviousError (EventInfo);
5738 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5742 if (!InstanceResolve (ec, must_do_cs1540_check))
5745 if (!ec.IsInCompoundAssignment) {
5746 Error_CannotAssign ();
5753 public override void Emit (EmitContext ec)
5755 Error_CannotAssign ();
5758 public void Error_CannotAssign ()
5760 Report.Error (70, loc,
5761 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
5762 GetSignatureForError (), TypeManager.CSharpName (EventInfo.DeclaringType));
5765 public override string GetSignatureForError ()
5767 return TypeManager.CSharpSignature (EventInfo);
5770 public void EmitAddOrRemove (EmitContext ec, bool is_add, Expression source)
5772 ArrayList args = new ArrayList (1);
5773 args.Add (new Argument (source, Argument.AType.Expression));
5774 Invocation.EmitCall (ec, IsBase, InstanceExpression, is_add ? add_accessor : remove_accessor, args, loc);
5778 public class TemporaryVariable : VariableReference
5782 public TemporaryVariable (Type type, Location loc)
5786 eclass = ExprClass.Variable;
5789 public override Expression CreateExpressionTree (EmitContext ec)
5791 throw new NotSupportedException ("ET");
5794 public override Expression DoResolve (EmitContext ec)
5799 TypeExpr te = new TypeExpression (type, loc);
5800 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
5801 if (!li.Resolve (ec))
5805 // Don't capture temporary variables except when using
5806 // iterator redirection
5808 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.IsIterator && ec.IsVariableCapturingRequired) {
5809 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
5810 storey.CaptureLocalVariable (ec, li);
5816 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5818 return DoResolve (ec);
5821 public override void Emit (EmitContext ec)
5826 public void EmitAssign (EmitContext ec, Expression source)
5828 EmitAssign (ec, source, false, false);
5831 public override HoistedVariable HoistedVariable {
5832 get { return li.HoistedVariableReference; }
5835 public override bool IsFixedVariable {
5836 get { return true; }
5839 public override bool IsRef {
5840 get { return false; }
5843 public override string Name {
5844 get { throw new NotImplementedException (); }
5847 public override void SetHasAddressTaken ()
5849 throw new NotImplementedException ();
5852 protected override ILocalVariable Variable {
5856 public override VariableInfo VariableInfo {
5857 get { throw new NotImplementedException (); }
5862 /// Handles `var' contextual keyword; var becomes a keyword only
5863 /// if no type called var exists in a variable scope
5865 public class VarExpr : SimpleName
5867 // Used for error reporting only
5868 ArrayList initializer;
5870 public VarExpr (Location loc)
5875 public ArrayList VariableInitializer {
5877 this.initializer = value;
5881 public bool InferType (EmitContext ec, Expression right_side)
5884 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
5886 type = right_side.Type;
5887 if (type == TypeManager.null_type || type == TypeManager.void_type || type == TypeManager.anonymous_method_type) {
5888 Report.Error (815, loc, "An implicitly typed local variable declaration cannot be initialized with `{0}'",
5889 right_side.GetSignatureForError ());
5893 eclass = ExprClass.Variable;
5897 protected override void Error_TypeOrNamespaceNotFound (IResolveContext ec)
5899 Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");
5902 public override TypeExpr ResolveAsContextualType (IResolveContext rc, bool silent)
5904 TypeExpr te = base.ResolveAsContextualType (rc, true);
5908 if (initializer == null)
5911 if (initializer.Count > 1) {
5912 Location loc = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [1]).Location;
5913 Report.Error (819, loc, "An implicitly typed local variable declaration cannot include multiple declarators");
5918 Expression variable_initializer = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [0]).expression_or_array_initializer;
5919 if (variable_initializer == null) {
5920 Report.Error (818, loc, "An implicitly typed local variable declarator must include an initializer");