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);
100 // TODO: Rename to something meaningful, this is flow-analysis interface only
101 public interface IVariable {
102 VariableInfo VariableInfo { get; }
103 bool IsFixed { get; }
107 /// Base class for expressions
109 public abstract class Expression {
110 public ExprClass eclass;
112 protected Location loc;
116 set { type = value; }
119 public virtual Location Location {
124 /// Utility wrapper routine for Error, just to beautify the code
126 public void Error (int error, string s)
128 Report.Error (error, loc, s);
131 // Not nice but we have broken hierarchy.
132 public virtual void CheckMarshalByRefAccess (EmitContext ec)
136 public virtual bool GetAttributableValue (Type value_type, out object value)
138 Attribute.Error_AttributeArgumentNotValid (loc);
143 public virtual string GetSignatureForError ()
145 return TypeManager.CSharpName (type);
148 public static bool IsAccessorAccessible (Type invocation_type, MethodInfo mi, out bool must_do_cs1540_check)
150 MethodAttributes ma = mi.Attributes & MethodAttributes.MemberAccessMask;
152 must_do_cs1540_check = false; // by default we do not check for this
154 if (ma == MethodAttributes.Public)
158 // If only accessible to the current class or children
160 if (ma == MethodAttributes.Private)
161 return TypeManager.IsPrivateAccessible (invocation_type, mi.DeclaringType) ||
162 TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType);
164 if (TypeManager.IsThisOrFriendAssembly (mi.DeclaringType.Assembly)) {
165 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamORAssem)
168 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamANDAssem)
172 // Family and FamANDAssem require that we derive.
173 // FamORAssem requires that we derive if in different assemblies.
174 if (!TypeManager.IsNestedFamilyAccessible (invocation_type, mi.DeclaringType))
177 if (!TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType))
178 must_do_cs1540_check = true;
183 public virtual bool IsNull {
190 /// Performs semantic analysis on the Expression
194 /// The Resolve method is invoked to perform the semantic analysis
197 /// The return value is an expression (it can be the
198 /// same expression in some cases) or a new
199 /// expression that better represents this node.
201 /// For example, optimizations of Unary (LiteralInt)
202 /// would return a new LiteralInt with a negated
205 /// If there is an error during semantic analysis,
206 /// then an error should be reported (using Report)
207 /// and a null value should be returned.
209 /// There are two side effects expected from calling
210 /// Resolve(): the the field variable "eclass" should
211 /// be set to any value of the enumeration
212 /// `ExprClass' and the type variable should be set
213 /// to a valid type (this is the type of the
216 public abstract Expression DoResolve (EmitContext ec);
218 public virtual Expression DoResolveLValue (EmitContext ec, Expression right_side)
224 // This is used if the expression should be resolved as a type or namespace name.
225 // the default implementation fails.
227 public virtual FullNamedExpression ResolveAsTypeStep (IResolveContext rc, bool silent)
231 EmitContext ec = rc as EmitContext;
235 e.Error_UnexpectedKind (ResolveFlags.Type, loc);
241 // C# 3.0 introduced contextual keywords (var) which behaves like a type if type with
242 // same name exists or as a keyword when no type was found
244 public virtual TypeExpr ResolveAsContextualType (IResolveContext rc, bool silent)
246 return ResolveAsTypeTerminal (rc, silent);
250 // This is used to resolve the expression as a type, a null
251 // value will be returned if the expression is not a type
254 public virtual TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
256 TypeExpr te = ResolveAsBaseTerminal (ec, silent);
260 if (!silent) { // && !(te is TypeParameterExpr)) {
261 ObsoleteAttribute obsolete_attr = AttributeTester.GetObsoleteAttribute (te.Type);
262 if (obsolete_attr != null && !ec.IsInObsoleteScope) {
263 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location);
267 // Constrains don't need to be checked for overrides
268 GenericMethod gm = ec.GenericDeclContainer as GenericMethod;
269 if (gm != null && (gm.ModFlags & Modifiers.OVERRIDE) != 0) {
274 ConstructedType ct = te as ConstructedType;
275 if ((ct != null) && !ct.CheckConstraints (ec))
281 public TypeExpr ResolveAsBaseTerminal (IResolveContext ec, bool silent)
283 int errors = Report.Errors;
285 FullNamedExpression fne = ResolveAsTypeStep (ec, silent);
290 if (fne.eclass != ExprClass.Type) {
291 if (!silent && errors == Report.Errors)
292 fne.Error_UnexpectedKind (null, "type", loc);
296 TypeExpr te = fne as TypeExpr;
298 if (!te.CheckAccessLevel (ec.DeclContainer)) {
299 Report.SymbolRelatedToPreviousError (te.Type);
300 ErrorIsInaccesible (loc, TypeManager.CSharpName (te.Type));
308 public static void ErrorIsInaccesible (Location loc, string name)
310 Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", name);
313 protected static void Error_CannotAccessProtected (Location loc, MemberInfo m, Type qualifier, Type container)
315 Report.Error (1540, loc, "Cannot access protected member `{0}' via a qualifier of type `{1}'."
316 + " The qualifier must be of type `{2}' or derived from it",
317 TypeManager.GetFullNameSignature (m),
318 TypeManager.CSharpName (qualifier),
319 TypeManager.CSharpName (container));
323 public static void Error_InvalidExpressionStatement (Location loc)
325 Report.Error (201, loc, "Only assignment, call, increment, decrement, and new object " +
326 "expressions can be used as a statement");
329 public void Error_InvalidExpressionStatement ()
331 Error_InvalidExpressionStatement (loc);
334 protected void Error_CannotAssign (string to, string roContext)
336 Report.Error (1656, loc, "Cannot assign to `{0}' because it is a `{1}'",
340 public static void Error_VoidInvalidInTheContext (Location loc)
342 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
345 public virtual void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl)
347 // The error was already reported as CS1660
348 if (type == TypeManager.anonymous_method_type)
351 if (TypeManager.IsGenericParameter (Type) && TypeManager.IsGenericParameter (target) && type.Name == target.Name) {
353 string sig1 = type.DeclaringMethod == null ?
354 TypeManager.CSharpName (type.DeclaringType) :
355 TypeManager.CSharpSignature (type.DeclaringMethod);
356 string sig2 = target.DeclaringMethod == null ?
357 TypeManager.CSharpName (target.DeclaringType) :
358 TypeManager.CSharpSignature (target.DeclaringMethod);
359 Report.ExtraInformation (loc,
361 "The generic parameter `{0}' of `{1}' cannot be converted to the generic parameter `{0}' of `{2}' (in the previous ",
362 Type.Name, sig1, sig2));
364 } else if (Type.FullName == target.FullName){
365 Report.ExtraInformation (loc,
367 "The type `{0}' has two conflicting definitions, one comes from `{1}' and the other from `{2}' (in the previous ",
368 Type.FullName, Type.Assembly.FullName, target.Assembly.FullName));
372 Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
373 TypeManager.CSharpName (type), TypeManager.CSharpName (target));
377 Expression e = (this is EnumConstant) ? ((EnumConstant)this).Child : this;
378 bool b = Convert.ExplicitNumericConversion (e, target) != null;
381 Convert.ExplicitReferenceConversionExists (Type, target) ||
382 Convert.ExplicitUnsafe (e, target) != null ||
383 (ec != null && Convert.ExplicitUserConversion (ec, this, target, Location.Null) != null))
385 Report.Error (266, loc, "Cannot implicitly convert type `{0}' to `{1}'. " +
386 "An explicit conversion exists (are you missing a cast?)",
387 TypeManager.CSharpName (Type), TypeManager.CSharpName (target));
391 Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
392 TypeManager.CSharpName (type),
393 TypeManager.CSharpName (target));
396 protected void Error_VariableIsUsedBeforeItIsDeclared (string name)
398 Report.Error (841, loc, "The variable `{0}' cannot be used before it is declared",
402 protected virtual void Error_TypeDoesNotContainDefinition (Type type, string name)
404 Error_TypeDoesNotContainDefinition (loc, type, name);
407 public static void Error_TypeDoesNotContainDefinition (Location loc, Type type, string name)
409 Report.SymbolRelatedToPreviousError (type);
410 Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
411 TypeManager.CSharpName (type), name);
414 protected static void Error_ValueAssignment (Location loc)
416 Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
419 ResolveFlags ExprClassToResolveFlags
424 case ExprClass.Namespace:
425 return ResolveFlags.Type;
427 case ExprClass.MethodGroup:
428 return ResolveFlags.MethodGroup;
430 case ExprClass.Value:
431 case ExprClass.Variable:
432 case ExprClass.PropertyAccess:
433 case ExprClass.EventAccess:
434 case ExprClass.IndexerAccess:
435 return ResolveFlags.VariableOrValue;
438 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
444 /// Resolves an expression and performs semantic analysis on it.
448 /// Currently Resolve wraps DoResolve to perform sanity
449 /// checking and assertion checking on what we expect from Resolve.
451 public Expression Resolve (EmitContext ec, ResolveFlags flags)
453 if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type)
454 return ResolveAsTypeStep (ec, false);
456 bool do_flow_analysis = ec.DoFlowAnalysis;
457 bool omit_struct_analysis = ec.OmitStructFlowAnalysis;
458 if ((flags & ResolveFlags.DisableFlowAnalysis) != 0)
459 do_flow_analysis = false;
460 if ((flags & ResolveFlags.DisableStructFlowAnalysis) != 0)
461 omit_struct_analysis = true;
464 using (ec.WithFlowAnalysis (do_flow_analysis, omit_struct_analysis)) {
465 if (this is SimpleName) {
466 bool intermediate = (flags & ResolveFlags.Intermediate) == ResolveFlags.Intermediate;
467 e = ((SimpleName) this).DoResolve (ec, intermediate);
476 if ((flags & e.ExprClassToResolveFlags) == 0) {
477 e.Error_UnexpectedKind (flags, loc);
481 if (e.type == null && !(e is Namespace)) {
482 throw new Exception (
483 "Expression " + e.GetType () +
484 " did not set its type after Resolve\n" +
485 "called from: " + this.GetType ());
492 /// Resolves an expression and performs semantic analysis on it.
494 public Expression Resolve (EmitContext ec)
496 Expression e = Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
498 if (e != null && e.eclass == ExprClass.MethodGroup && RootContext.Version == LanguageVersion.ISO_1) {
499 ((MethodGroupExpr) e).ReportUsageError ();
505 public Constant ResolveAsConstant (EmitContext ec, MemberCore mc)
507 Expression e = Resolve (ec);
511 Constant c = e as Constant;
515 Const.Error_ExpressionMustBeConstant (loc, mc.GetSignatureForError ());
520 /// Resolves an expression for LValue assignment
524 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
525 /// checking and assertion checking on what we expect from Resolve
527 public Expression ResolveLValue (EmitContext ec, Expression right_side, Location loc)
529 int errors = Report.Errors;
530 bool out_access = right_side == EmptyExpression.OutAccess;
532 Expression e = DoResolveLValue (ec, right_side);
534 if (e != null && out_access && !(e is IMemoryLocation)) {
535 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
536 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
538 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
539 // e.GetType () + " " + e.GetSignatureForError ());
544 if (errors == Report.Errors) {
546 Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
548 Error_ValueAssignment (loc);
553 if (e.eclass == ExprClass.Invalid)
554 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
556 if (e.eclass == ExprClass.MethodGroup) {
557 ((MethodGroupExpr) e).ReportUsageError ();
561 if ((e.type == null) && !(e is ConstructedType))
562 throw new Exception ("Expression " + e + " did not set its type after Resolve");
568 /// Emits the code for the expression
572 /// The Emit method is invoked to generate the code
573 /// for the expression.
575 public abstract void Emit (EmitContext ec);
577 // Emit code to branch to @target if this expression is equivalent to @on_true.
578 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
579 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
580 // including the use of conditional branches. Note also that a branch MUST be emitted
581 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
584 ec.ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
587 // Emit this expression for its side effects, not for its value.
588 // The default implementation is to emit the value, and then throw it away.
589 // Subclasses can provide more efficient implementations, but those MUST be equivalent
590 public virtual void EmitSideEffect (EmitContext ec)
593 ec.ig.Emit (OpCodes.Pop);
597 /// Protected constructor. Only derivate types should
598 /// be able to be created
601 protected Expression ()
603 eclass = ExprClass.Invalid;
608 /// Returns a fully formed expression after a MemberLookup
611 public static Expression ExprClassFromMemberInfo (Type container_type, MemberInfo mi, Location loc)
614 return new EventExpr ((EventInfo) mi, loc);
615 else if (mi is FieldInfo) {
616 FieldInfo fi = (FieldInfo) mi;
617 if (fi.IsLiteral || (fi.IsInitOnly && fi.FieldType == TypeManager.decimal_type))
618 return new ConstantExpr (fi, loc);
619 return new FieldExpr (fi, loc);
620 } else if (mi is PropertyInfo)
621 return new PropertyExpr (container_type, (PropertyInfo) mi, loc);
622 else if (mi is Type) {
623 return new TypeExpression ((System.Type) mi, loc);
629 protected static ArrayList almost_matched_members = new ArrayList (4);
632 // FIXME: Probably implement a cache for (t,name,current_access_set)?
634 // This code could use some optimizations, but we need to do some
635 // measurements. For example, we could use a delegate to `flag' when
636 // something can not any longer be a method-group (because it is something
640 // If the return value is an Array, then it is an array of
643 // If the return value is an MemberInfo, it is anything, but a Method
647 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
648 // the arguments here and have MemberLookup return only the methods that
649 // match the argument count/type, unlike we are doing now (we delay this
652 // This is so we can catch correctly attempts to invoke instance methods
653 // from a static body (scan for error 120 in ResolveSimpleName).
656 // FIXME: Potential optimization, have a static ArrayList
659 public static Expression MemberLookup (Type container_type, Type queried_type, string name,
660 MemberTypes mt, BindingFlags bf, Location loc)
662 return MemberLookup (container_type, null, queried_type, name, mt, bf, loc);
666 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
667 // `qualifier_type' or null to lookup members in the current class.
670 public static Expression MemberLookup (Type container_type,
671 Type qualifier_type, Type queried_type,
672 string name, MemberTypes mt,
673 BindingFlags bf, Location loc)
675 almost_matched_members.Clear ();
677 MemberInfo [] mi = TypeManager.MemberLookup (container_type, qualifier_type,
678 queried_type, mt, bf, name, almost_matched_members);
684 bool is_interface = qualifier_type != null && qualifier_type.IsInterface;
685 ArrayList methods = new ArrayList (2);
686 ArrayList non_methods = null;
688 foreach (MemberInfo m in mi) {
689 if (m is MethodBase) {
694 if (non_methods == null) {
695 non_methods = new ArrayList (2);
700 foreach (MemberInfo n_m in non_methods) {
701 if (m.DeclaringType.IsInterface && TypeManager.ImplementsInterface (m.DeclaringType, n_m.DeclaringType))
704 Report.SymbolRelatedToPreviousError (m);
705 Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
706 TypeManager.GetFullNameSignature (m), TypeManager.GetFullNameSignature (n_m));
711 if (methods.Count == 0)
712 return ExprClassFromMemberInfo (container_type, (MemberInfo)non_methods [0], loc);
714 if (non_methods != null) {
715 MethodBase method = (MethodBase) methods [0];
716 MemberInfo non_method = (MemberInfo) non_methods [0];
717 if (method.DeclaringType == non_method.DeclaringType) {
718 // Cannot happen with C# code, but is valid in IL
719 Report.SymbolRelatedToPreviousError (method);
720 Report.SymbolRelatedToPreviousError (non_method);
721 Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
722 TypeManager.GetFullNameSignature (non_method),
723 TypeManager.CSharpSignature (method));
728 Report.SymbolRelatedToPreviousError (method);
729 Report.SymbolRelatedToPreviousError (non_method);
730 Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and non-method `{1}'. Using method `{0}'",
731 TypeManager.CSharpSignature (method), TypeManager.GetFullNameSignature (non_method));
735 return new MethodGroupExpr (methods, queried_type, loc);
738 if (mi [0] is MethodBase)
739 return new MethodGroupExpr (mi, queried_type, loc);
741 return ExprClassFromMemberInfo (container_type, mi [0], loc);
744 public const MemberTypes AllMemberTypes =
745 MemberTypes.Constructor |
749 MemberTypes.NestedType |
750 MemberTypes.Property;
752 public const BindingFlags AllBindingFlags =
753 BindingFlags.Public |
754 BindingFlags.Static |
755 BindingFlags.Instance;
757 public static Expression MemberLookup (Type container_type, Type queried_type,
758 string name, Location loc)
760 return MemberLookup (container_type, null, queried_type, name,
761 AllMemberTypes, AllBindingFlags, loc);
764 public static Expression MemberLookup (Type container_type, Type qualifier_type,
765 Type queried_type, string name, Location loc)
767 return MemberLookup (container_type, qualifier_type, queried_type,
768 name, AllMemberTypes, AllBindingFlags, loc);
771 public static MethodGroupExpr MethodLookup (Type container_type, Type queried_type,
772 string name, Location loc)
774 return (MethodGroupExpr)MemberLookup (container_type, null, queried_type, name,
775 MemberTypes.Method, AllBindingFlags, loc);
779 /// This is a wrapper for MemberLookup that is not used to "probe", but
780 /// to find a final definition. If the final definition is not found, we
781 /// look for private members and display a useful debugging message if we
784 protected Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
785 Type queried_type, string name,
786 MemberTypes mt, BindingFlags bf,
791 int errors = Report.Errors;
793 e = MemberLookup (ec.ContainerType, qualifier_type, queried_type, name, mt, bf, loc);
795 if (e != null || errors != Report.Errors)
798 // No errors were reported by MemberLookup, but there was an error.
799 return Error_MemberLookupFailed (ec.ContainerType, qualifier_type, queried_type,
803 protected virtual Expression Error_MemberLookupFailed (Type container_type, Type qualifier_type,
804 Type queried_type, string name, string class_name,
805 MemberTypes mt, BindingFlags bf)
807 if (almost_matched_members.Count != 0) {
808 for (int i = 0; i < almost_matched_members.Count; ++i) {
809 MemberInfo m = (MemberInfo) almost_matched_members [i];
810 for (int j = 0; j < i; ++j) {
811 if (m == almost_matched_members [j]) {
819 Type declaring_type = m.DeclaringType;
821 Report.SymbolRelatedToPreviousError (m);
822 if (qualifier_type == null) {
823 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
824 TypeManager.CSharpName (m.DeclaringType),
825 TypeManager.CSharpName (container_type));
827 } else if (qualifier_type != container_type &&
828 TypeManager.IsNestedFamilyAccessible (container_type, declaring_type)) {
829 // Although a derived class can access protected members of
830 // its base class it cannot do so through an instance of the
831 // base class (CS1540). If the qualifier_type is a base of the
832 // ec.ContainerType and the lookup succeeds with the latter one,
833 // then we are in this situation.
834 Error_CannotAccessProtected (loc, m, qualifier_type, container_type);
836 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (m));
839 almost_matched_members.Clear ();
843 MemberInfo[] lookup = null;
844 if (queried_type == null) {
845 class_name = "global::";
847 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
848 mt, (bf & ~BindingFlags.Public) | BindingFlags.NonPublic,
851 if (lookup != null) {
852 Report.SymbolRelatedToPreviousError (lookup [0]);
853 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (lookup [0]));
854 return Error_MemberLookupFailed (lookup);
857 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
858 AllMemberTypes, AllBindingFlags | BindingFlags.NonPublic,
862 if (lookup == null) {
863 if (class_name != null) {
864 Report.Error (103, loc, "The name `{0}' does not exist in the current context",
867 Error_TypeDoesNotContainDefinition (queried_type, name);
872 if (TypeManager.MemberLookup (queried_type, null, queried_type,
873 AllMemberTypes, AllBindingFlags |
874 BindingFlags.NonPublic, name, null) == null) {
875 if ((lookup.Length == 1) && (lookup [0] is Type)) {
876 Type t = (Type) lookup [0];
878 Report.Error (305, loc,
879 "Using the generic type `{0}' " +
880 "requires {1} type arguments",
881 TypeManager.CSharpName (t),
882 TypeManager.GetNumberOfTypeArguments (t).ToString ());
887 return Error_MemberLookupFailed (lookup);
890 protected virtual Expression Error_MemberLookupFailed (MemberInfo[] members)
892 for (int i = 0; i < members.Length; ++i) {
893 if (!(members [i] is MethodBase))
897 // By default propagate the closest candidates upwards
898 return new MethodGroupExpr (members, type, loc);
901 protected virtual void Error_NegativeArrayIndex (Location loc)
903 throw new NotImplementedException ();
906 protected void Error_PointerInsideExpressionTree ()
908 Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
912 /// Returns an expression that can be used to invoke operator true
913 /// on the expression if it exists.
915 static public Expression GetOperatorTrue (EmitContext ec, Expression e, Location loc)
917 return GetOperatorTrueOrFalse (ec, e, true, loc);
921 /// Returns an expression that can be used to invoke operator false
922 /// on the expression if it exists.
924 static public Expression GetOperatorFalse (EmitContext ec, Expression e, Location loc)
926 return GetOperatorTrueOrFalse (ec, e, false, loc);
929 static Expression GetOperatorTrueOrFalse (EmitContext ec, Expression e, bool is_true, Location loc)
931 MethodGroupExpr operator_group;
932 string mname = Operator.GetMetadataName (is_true ? Operator.OpType.True : Operator.OpType.False);
933 operator_group = MethodLookup (ec.ContainerType, e.Type, mname, loc) as MethodGroupExpr;
934 if (operator_group == null)
937 ArrayList arguments = new ArrayList (1);
938 arguments.Add (new Argument (e, Argument.AType.Expression));
939 operator_group = operator_group.OverloadResolve (
940 ec, ref arguments, false, loc);
942 if (operator_group == null)
945 return new UserOperatorCall (operator_group, arguments, null, loc);
949 /// Resolves the expression `e' into a boolean expression: either through
950 /// an implicit conversion, or through an `operator true' invocation
952 public static Expression ResolveBoolean (EmitContext ec, Expression e, Location loc)
958 if (e.Type == TypeManager.bool_type)
961 Expression converted = Convert.ImplicitConversion (ec, e, TypeManager.bool_type, Location.Null);
963 if (converted != null)
967 // If no implicit conversion to bool exists, try using `operator true'
969 converted = Expression.GetOperatorTrue (ec, e, loc);
970 if (converted == null){
971 e.Error_ValueCannotBeConverted (ec, loc, TypeManager.bool_type, false);
977 public virtual string ExprClassName
981 case ExprClass.Invalid:
983 case ExprClass.Value:
985 case ExprClass.Variable:
987 case ExprClass.Namespace:
991 case ExprClass.MethodGroup:
992 return "method group";
993 case ExprClass.PropertyAccess:
994 return "property access";
995 case ExprClass.EventAccess:
996 return "event access";
997 case ExprClass.IndexerAccess:
998 return "indexer access";
999 case ExprClass.Nothing:
1002 throw new Exception ("Should not happen");
1007 /// Reports that we were expecting `expr' to be of class `expected'
1009 public void Error_UnexpectedKind (DeclSpace ds, string expected, Location loc)
1011 Error_UnexpectedKind (ds, expected, ExprClassName, loc);
1014 public void Error_UnexpectedKind (DeclSpace ds, string expected, string was, Location loc)
1016 string name = GetSignatureForError ();
1018 name = ds.GetSignatureForError () + '.' + name;
1020 Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
1021 name, was, expected);
1024 public void Error_UnexpectedKind (ResolveFlags flags, Location loc)
1026 string [] valid = new string [4];
1029 if ((flags & ResolveFlags.VariableOrValue) != 0) {
1030 valid [count++] = "variable";
1031 valid [count++] = "value";
1034 if ((flags & ResolveFlags.Type) != 0)
1035 valid [count++] = "type";
1037 if ((flags & ResolveFlags.MethodGroup) != 0)
1038 valid [count++] = "method group";
1041 valid [count++] = "unknown";
1043 StringBuilder sb = new StringBuilder (valid [0]);
1044 for (int i = 1; i < count - 1; i++) {
1046 sb.Append (valid [i]);
1049 sb.Append ("' or `");
1050 sb.Append (valid [count - 1]);
1053 Report.Error (119, loc,
1054 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1057 public static void UnsafeError (Location loc)
1059 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1063 // Load the object from the pointer.
1065 public static void LoadFromPtr (ILGenerator ig, Type t)
1067 if (t == TypeManager.int32_type)
1068 ig.Emit (OpCodes.Ldind_I4);
1069 else if (t == TypeManager.uint32_type)
1070 ig.Emit (OpCodes.Ldind_U4);
1071 else if (t == TypeManager.short_type)
1072 ig.Emit (OpCodes.Ldind_I2);
1073 else if (t == TypeManager.ushort_type)
1074 ig.Emit (OpCodes.Ldind_U2);
1075 else if (t == TypeManager.char_type)
1076 ig.Emit (OpCodes.Ldind_U2);
1077 else if (t == TypeManager.byte_type)
1078 ig.Emit (OpCodes.Ldind_U1);
1079 else if (t == TypeManager.sbyte_type)
1080 ig.Emit (OpCodes.Ldind_I1);
1081 else if (t == TypeManager.uint64_type)
1082 ig.Emit (OpCodes.Ldind_I8);
1083 else if (t == TypeManager.int64_type)
1084 ig.Emit (OpCodes.Ldind_I8);
1085 else if (t == TypeManager.float_type)
1086 ig.Emit (OpCodes.Ldind_R4);
1087 else if (t == TypeManager.double_type)
1088 ig.Emit (OpCodes.Ldind_R8);
1089 else if (t == TypeManager.bool_type)
1090 ig.Emit (OpCodes.Ldind_I1);
1091 else if (t == TypeManager.intptr_type)
1092 ig.Emit (OpCodes.Ldind_I);
1093 else if (TypeManager.IsEnumType (t)) {
1094 if (t == TypeManager.enum_type)
1095 ig.Emit (OpCodes.Ldind_Ref);
1097 LoadFromPtr (ig, TypeManager.GetEnumUnderlyingType (t));
1098 } else if (t.IsValueType || TypeManager.IsGenericParameter (t))
1099 ig.Emit (OpCodes.Ldobj, t);
1100 else if (t.IsPointer)
1101 ig.Emit (OpCodes.Ldind_I);
1103 ig.Emit (OpCodes.Ldind_Ref);
1107 // The stack contains the pointer and the value of type `type'
1109 public static void StoreFromPtr (ILGenerator ig, Type type)
1111 if (TypeManager.IsEnumType (type))
1112 type = TypeManager.GetEnumUnderlyingType (type);
1113 if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
1114 ig.Emit (OpCodes.Stind_I4);
1115 else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
1116 ig.Emit (OpCodes.Stind_I8);
1117 else if (type == TypeManager.char_type || type == TypeManager.short_type ||
1118 type == TypeManager.ushort_type)
1119 ig.Emit (OpCodes.Stind_I2);
1120 else if (type == TypeManager.float_type)
1121 ig.Emit (OpCodes.Stind_R4);
1122 else if (type == TypeManager.double_type)
1123 ig.Emit (OpCodes.Stind_R8);
1124 else if (type == TypeManager.byte_type || type == TypeManager.sbyte_type ||
1125 type == TypeManager.bool_type)
1126 ig.Emit (OpCodes.Stind_I1);
1127 else if (type == TypeManager.intptr_type)
1128 ig.Emit (OpCodes.Stind_I);
1129 else if (type.IsValueType || TypeManager.IsGenericParameter (type))
1130 ig.Emit (OpCodes.Stobj, type);
1132 ig.Emit (OpCodes.Stind_Ref);
1136 // Returns the size of type `t' if known, otherwise, 0
1138 public static int GetTypeSize (Type t)
1140 t = TypeManager.TypeToCoreType (t);
1141 if (t == TypeManager.int32_type ||
1142 t == TypeManager.uint32_type ||
1143 t == TypeManager.float_type)
1145 else if (t == TypeManager.int64_type ||
1146 t == TypeManager.uint64_type ||
1147 t == TypeManager.double_type)
1149 else if (t == TypeManager.byte_type ||
1150 t == TypeManager.sbyte_type ||
1151 t == TypeManager.bool_type)
1153 else if (t == TypeManager.short_type ||
1154 t == TypeManager.char_type ||
1155 t == TypeManager.ushort_type)
1157 else if (t == TypeManager.decimal_type)
1163 protected void Error_CannotCallAbstractBase (string name)
1165 Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
1168 protected void Error_CannotModifyIntermediateExpressionValue (EmitContext ec)
1170 Report.SymbolRelatedToPreviousError (type);
1171 if (ec.CurrentInitializerVariable != null) {
1172 Report.Error (1918, loc, "Members of a value type property `{0}' cannot be assigned with an object initializer",
1173 GetSignatureForError ());
1175 Report.Error (1612, loc, "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
1176 GetSignatureForError ());
1181 // Converts `source' to an int, uint, long or ulong.
1183 public Expression ConvertExpressionToArrayIndex (EmitContext ec, Expression source)
1185 Expression converted;
1187 using (ec.With (EmitContext.Flags.CheckState, true)) {
1188 converted = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, source.loc);
1189 if (converted == null)
1190 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, source.loc);
1191 if (converted == null)
1192 converted = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, source.loc);
1193 if (converted == null)
1194 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, source.loc);
1196 if (converted == null) {
1197 source.Error_ValueCannotBeConverted (ec, source.loc, TypeManager.int32_type, false);
1203 // Only positive constants are allowed at compile time
1205 Constant c = converted as Constant;
1208 Error_NegativeArrayIndex (source.loc);
1213 return new ArrayIndexCast (converted).Resolve (ec);
1217 // Derived classes implement this method by cloning the fields that
1218 // could become altered during the Resolve stage
1220 // Only expressions that are created for the parser need to implement
1223 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1225 throw new NotImplementedException (
1227 "CloneTo not implemented for expression {0}", this.GetType ()));
1231 // Clones an expression created by the parser.
1233 // We only support expressions created by the parser so far, not
1234 // expressions that have been resolved (many more classes would need
1235 // to implement CloneTo).
1237 // This infrastructure is here merely for Lambda expressions which
1238 // compile the same code using different type values for the same
1239 // arguments to find the correct overload
1241 public Expression Clone (CloneContext clonectx)
1243 Expression cloned = (Expression) MemberwiseClone ();
1244 CloneTo (clonectx, cloned);
1250 // Implementation of expression to expression tree conversion
1252 public abstract Expression CreateExpressionTree (EmitContext ec);
1254 protected Expression CreateExpressionFactoryCall (string name, ArrayList args)
1256 return CreateExpressionFactoryCall (name, null, args, loc);
1259 protected Expression CreateExpressionFactoryCall (string name, TypeArguments typeArguments, ArrayList args)
1261 return CreateExpressionFactoryCall (name, typeArguments, args, loc);
1264 public static Expression CreateExpressionFactoryCall (string name, TypeArguments typeArguments, ArrayList args, Location loc)
1266 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (loc), name, typeArguments, loc), args);
1269 protected static TypeExpr CreateExpressionTypeExpression (Location loc)
1271 TypeExpr texpr = TypeManager.expression_type_expr;
1272 if (texpr == null) {
1273 Type t = TypeManager.CoreLookupType ("System.Linq.Expressions", "Expression", Kind.Class, true);
1277 TypeManager.expression_type_expr = texpr = new TypeExpression (t, Location.Null);
1283 public virtual void MutateHoistedGenericType (AnonymousMethodStorey storey)
1285 // TODO: It should probably be type = storey.MutateType (type);
1290 /// This is just a base class for expressions that can
1291 /// appear on statements (invocations, object creation,
1292 /// assignments, post/pre increment and decrement). The idea
1293 /// being that they would support an extra Emition interface that
1294 /// does not leave a result on the stack.
1296 public abstract class ExpressionStatement : Expression {
1298 public virtual ExpressionStatement ResolveStatement (EmitContext ec)
1300 Expression e = Resolve (ec);
1304 ExpressionStatement es = e as ExpressionStatement;
1306 Error_InvalidExpressionStatement ();
1312 /// Requests the expression to be emitted in a `statement'
1313 /// context. This means that no new value is left on the
1314 /// stack after invoking this method (constrasted with
1315 /// Emit that will always leave a value on the stack).
1317 public abstract void EmitStatement (EmitContext ec);
1319 public override void EmitSideEffect (EmitContext ec)
1326 /// This kind of cast is used to encapsulate the child
1327 /// whose type is child.Type into an expression that is
1328 /// reported to return "return_type". This is used to encapsulate
1329 /// expressions which have compatible types, but need to be dealt
1330 /// at higher levels with.
1332 /// For example, a "byte" expression could be encapsulated in one
1333 /// of these as an "unsigned int". The type for the expression
1334 /// would be "unsigned int".
1337 public abstract class TypeCast : Expression
1339 protected Expression child;
1341 protected TypeCast (Expression child, Type return_type)
1343 eclass = child.eclass;
1344 loc = child.Location;
1349 public override Expression CreateExpressionTree (EmitContext ec)
1351 ArrayList args = new ArrayList (2);
1352 args.Add (new Argument (child.CreateExpressionTree (ec)));
1353 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1355 if (type.IsPointer || child.Type.IsPointer)
1356 Error_PointerInsideExpressionTree ();
1358 return CreateExpressionFactoryCall (ec.CheckState ? "ConvertChecked" : "Convert", args);
1361 public override Expression DoResolve (EmitContext ec)
1363 // This should never be invoked, we are born in fully
1364 // initialized state.
1369 public override void Emit (EmitContext ec)
1374 public override bool GetAttributableValue (Type value_type, out object value)
1376 return child.GetAttributableValue (value_type, out value);
1379 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1381 child.MutateHoistedGenericType (storey);
1384 protected override void CloneTo (CloneContext clonectx, Expression t)
1386 TypeCast target = (TypeCast) t;
1388 target.child = child.Clone (clonectx);
1391 public override bool IsNull {
1392 get { return child.IsNull; }
1396 public class EmptyCast : TypeCast {
1397 EmptyCast (Expression child, Type target_type)
1398 : base (child, target_type)
1402 public static Expression Create (Expression child, Type type)
1404 Constant c = child as Constant;
1406 return new EmptyConstantCast (c, type);
1408 EmptyCast e = child as EmptyCast;
1410 return new EmptyCast (e.child, type);
1412 return new EmptyCast (child, type);
1415 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1417 child.EmitBranchable (ec, label, on_true);
1420 public override void EmitSideEffect (EmitContext ec)
1422 child.EmitSideEffect (ec);
1427 /// Performs a cast using an operator (op_Explicit or op_Implicit)
1429 public class OperatorCast : TypeCast {
1430 MethodInfo conversion_operator;
1433 public OperatorCast (Expression child, Type target_type) : this (child, target_type, false) {}
1435 public OperatorCast (Expression child, Type target_type, bool find_explicit)
1436 : base (child, target_type)
1438 this.find_explicit = find_explicit;
1441 // Returns the implicit operator that converts from
1442 // 'child.Type' to our target type (type)
1443 MethodInfo GetConversionOperator (bool find_explicit)
1445 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1449 mi = TypeManager.MemberLookup (child.Type, child.Type, child.Type, MemberTypes.Method,
1450 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1453 mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1454 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1457 foreach (MethodInfo oper in mi) {
1458 ParameterData pd = TypeManager.GetParameterData (oper);
1460 if (pd.ParameterType (0) == child.Type && TypeManager.TypeToCoreType (oper.ReturnType) == type)
1468 public override void Emit (EmitContext ec)
1470 ILGenerator ig = ec.ig;
1473 conversion_operator = GetConversionOperator (find_explicit);
1475 if (conversion_operator == null)
1476 throw new InternalErrorException ("Outer conversion routine is out of sync");
1478 ig.Emit (OpCodes.Call, conversion_operator);
1484 /// This is a numeric cast to a Decimal
1486 public class CastToDecimal : TypeCast {
1487 MethodInfo conversion_operator;
1489 public CastToDecimal (Expression child)
1490 : this (child, false)
1494 public CastToDecimal (Expression child, bool find_explicit)
1495 : base (child, TypeManager.decimal_type)
1497 conversion_operator = GetConversionOperator (find_explicit);
1499 if (conversion_operator == null)
1500 throw new InternalErrorException ("Outer conversion routine is out of sync");
1503 // Returns the implicit operator that converts from
1504 // 'child.Type' to System.Decimal.
1505 MethodInfo GetConversionOperator (bool find_explicit)
1507 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1509 MemberInfo [] mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1510 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1512 foreach (MethodInfo oper in mi) {
1513 ParameterData pd = TypeManager.GetParameterData (oper);
1515 if (pd.ParameterType (0) == child.Type && TypeManager.TypeToCoreType (oper.ReturnType) == type)
1521 public override void Emit (EmitContext ec)
1523 ILGenerator ig = ec.ig;
1526 ig.Emit (OpCodes.Call, conversion_operator);
1531 /// This is an explicit numeric cast from a Decimal
1533 public class CastFromDecimal : TypeCast
1535 static IDictionary operators;
1537 public CastFromDecimal (Expression child, Type return_type)
1538 : base (child, return_type)
1540 if (child.Type != TypeManager.decimal_type)
1541 throw new InternalErrorException (
1542 "The expected type is Decimal, instead it is " + child.Type.FullName);
1545 // Returns the explicit operator that converts from an
1546 // express of type System.Decimal to 'type'.
1547 public Expression Resolve ()
1549 if (operators == null) {
1550 MemberInfo[] all_oper = TypeManager.MemberLookup (TypeManager.decimal_type,
1551 TypeManager.decimal_type, TypeManager.decimal_type, MemberTypes.Method,
1552 BindingFlags.Static | BindingFlags.Public, "op_Explicit", null);
1554 operators = new System.Collections.Specialized.HybridDictionary ();
1555 foreach (MethodInfo oper in all_oper) {
1556 ParameterData pd = TypeManager.GetParameterData (oper);
1557 if (pd.ParameterType (0) == TypeManager.decimal_type)
1558 operators.Add (TypeManager.TypeToCoreType (oper.ReturnType), oper);
1562 return operators.Contains (type) ? this : null;
1565 public override void Emit (EmitContext ec)
1567 ILGenerator ig = ec.ig;
1570 ig.Emit (OpCodes.Call, (MethodInfo)operators [type]);
1576 // Constant specialization of EmptyCast.
1577 // We need to special case this since an empty cast of
1578 // a constant is still a constant.
1580 public class EmptyConstantCast : Constant
1582 public readonly Constant child;
1584 public EmptyConstantCast(Constant child, Type type)
1585 : base (child.Location)
1587 eclass = child.eclass;
1592 public override string AsString ()
1594 return child.AsString ();
1597 public override object GetValue ()
1599 return child.GetValue ();
1602 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
1604 // FIXME: check that 'type' can be converted to 'target_type' first
1605 return child.ConvertExplicitly (in_checked_context, target_type);
1608 public override Expression CreateExpressionTree (EmitContext ec)
1610 ArrayList args = new ArrayList (2);
1611 args.Add (new Argument (child.CreateExpressionTree (ec)));
1612 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1614 Error_PointerInsideExpressionTree ();
1616 return CreateExpressionFactoryCall ("Convert", args);
1619 public override Constant Increment ()
1621 return child.Increment ();
1624 public override bool IsDefaultValue {
1625 get { return child.IsDefaultValue; }
1628 public override bool IsNegative {
1629 get { return child.IsNegative; }
1632 public override bool IsNull {
1633 get { return child.IsNull; }
1636 public override bool IsZeroInteger {
1637 get { return child.IsZeroInteger; }
1640 public override void Emit (EmitContext ec)
1645 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1647 child.EmitBranchable (ec, label, on_true);
1650 public override void EmitSideEffect (EmitContext ec)
1652 child.EmitSideEffect (ec);
1655 public override Constant ConvertImplicitly (Type target_type)
1657 // FIXME: Do we need to check user conversions?
1658 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1660 return child.ConvertImplicitly (target_type);
1666 /// This class is used to wrap literals which belong inside Enums
1668 public class EnumConstant : Constant {
1669 public Constant Child;
1671 public EnumConstant (Constant child, Type enum_type):
1672 base (child.Location)
1674 eclass = child.eclass;
1679 public override Expression DoResolve (EmitContext ec)
1681 // This should never be invoked, we are born in fully
1682 // initialized state.
1687 public override void Emit (EmitContext ec)
1692 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1694 Child.EmitBranchable (ec, label, on_true);
1697 public override void EmitSideEffect (EmitContext ec)
1699 Child.EmitSideEffect (ec);
1702 public override bool GetAttributableValue (Type value_type, out object value)
1704 value = GetTypedValue ();
1708 public override string GetSignatureForError()
1710 return TypeManager.CSharpName (Type);
1713 public override object GetValue ()
1715 return Child.GetValue ();
1718 public override object GetTypedValue ()
1720 // FIXME: runtime is not ready to work with just emited enums
1721 if (!RootContext.StdLib) {
1722 return Child.GetValue ();
1725 return System.Enum.ToObject (type, Child.GetValue ());
1728 public override string AsString ()
1730 return TypeManager.CSharpEnumValue (type, Child.GetValue ());
1733 public override Constant Increment()
1735 return new EnumConstant (Child.Increment (), type);
1738 public override bool IsDefaultValue {
1740 return Child.IsDefaultValue;
1744 public override bool IsZeroInteger {
1745 get { return Child.IsZeroInteger; }
1748 public override bool IsNegative {
1750 return Child.IsNegative;
1754 public override Constant ConvertExplicitly(bool in_checked_context, Type target_type)
1756 if (Child.Type == target_type)
1759 return Child.ConvertExplicitly (in_checked_context, target_type);
1762 public override Constant ConvertImplicitly (Type type)
1764 Type this_type = TypeManager.DropGenericTypeArguments (Type);
1765 type = TypeManager.DropGenericTypeArguments (type);
1767 if (this_type == type) {
1768 // This is workaround of mono bug. It can be removed when the latest corlib spreads enough
1769 if (TypeManager.IsEnumType (type.UnderlyingSystemType))
1772 Type child_type = TypeManager.DropGenericTypeArguments (Child.Type);
1773 if (type.UnderlyingSystemType != child_type)
1774 Child = Child.ConvertImplicitly (type.UnderlyingSystemType);
1778 if (!Convert.ImplicitStandardConversionExists (this, type)){
1782 return Child.ConvertImplicitly(type);
1788 /// This kind of cast is used to encapsulate Value Types in objects.
1790 /// The effect of it is to box the value type emitted by the previous
1793 public class BoxedCast : TypeCast {
1795 public BoxedCast (Expression expr, Type target_type)
1796 : base (expr, target_type)
1798 eclass = ExprClass.Value;
1801 public override Expression DoResolve (EmitContext ec)
1803 // This should never be invoked, we are born in fully
1804 // initialized state.
1809 public override void Emit (EmitContext ec)
1813 ec.ig.Emit (OpCodes.Box, child.Type);
1816 public override void EmitSideEffect (EmitContext ec)
1818 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1819 // so, we need to emit the box+pop instructions in most cases
1820 if (child.Type.IsValueType &&
1821 (type == TypeManager.object_type || type == TypeManager.value_type))
1822 child.EmitSideEffect (ec);
1824 base.EmitSideEffect (ec);
1828 public class UnboxCast : TypeCast {
1829 public UnboxCast (Expression expr, Type return_type)
1830 : base (expr, return_type)
1834 public override Expression DoResolve (EmitContext ec)
1836 // This should never be invoked, we are born in fully
1837 // initialized state.
1842 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1844 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
1845 Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
1846 return base.DoResolveLValue (ec, right_side);
1849 public override void Emit (EmitContext ec)
1852 ILGenerator ig = ec.ig;
1856 if (t.IsGenericParameter || t.IsGenericType && t.IsValueType)
1857 ig.Emit (OpCodes.Unbox_Any, t);
1861 ig.Emit (OpCodes.Unbox, t);
1863 LoadFromPtr (ig, t);
1867 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1869 type = storey.MutateType (type);
1874 /// This is used to perform explicit numeric conversions.
1876 /// Explicit numeric conversions might trigger exceptions in a checked
1877 /// context, so they should generate the conv.ovf opcodes instead of
1880 public class ConvCast : TypeCast {
1881 public enum Mode : byte {
1882 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1884 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1885 U2_I1, U2_U1, U2_I2, U2_CH,
1886 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1887 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1888 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH,
1889 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH,
1890 CH_I1, CH_U1, CH_I2,
1891 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1892 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4
1897 public ConvCast (Expression child, Type return_type, Mode m)
1898 : base (child, return_type)
1903 public override Expression DoResolve (EmitContext ec)
1905 // This should never be invoked, we are born in fully
1906 // initialized state.
1911 public override string ToString ()
1913 return String.Format ("ConvCast ({0}, {1})", mode, child);
1916 public override void Emit (EmitContext ec)
1918 ILGenerator ig = ec.ig;
1924 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1925 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1926 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1927 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1928 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1930 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1931 case Mode.U1_CH: /* nothing */ break;
1933 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1934 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1935 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1936 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1937 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1938 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1940 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1941 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1942 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1943 case Mode.U2_CH: /* nothing */ break;
1945 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1946 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1947 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1948 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1949 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1950 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1951 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1953 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1954 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1955 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1956 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1957 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1958 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1960 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1961 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1962 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1963 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1964 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1965 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1966 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1967 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1969 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1970 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1971 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1972 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1973 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1974 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1975 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1976 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1978 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1979 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1980 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1982 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1983 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1984 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1985 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1986 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1987 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1988 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1989 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1990 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1992 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1993 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1994 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1995 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1996 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1997 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1998 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1999 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
2000 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
2001 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
2005 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
2006 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
2007 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
2008 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
2009 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
2011 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
2012 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
2014 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
2015 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
2016 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
2017 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
2018 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
2019 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
2021 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
2022 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
2023 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
2024 case Mode.U2_CH: /* nothing */ break;
2026 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
2027 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
2028 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
2029 case Mode.I4_U4: /* nothing */ break;
2030 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
2031 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
2032 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
2034 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
2035 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
2036 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
2037 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
2038 case Mode.U4_I4: /* nothing */ break;
2039 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
2041 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
2042 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
2043 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
2044 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
2045 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
2046 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
2047 case Mode.I8_U8: /* nothing */ break;
2048 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
2050 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
2051 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
2052 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
2053 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
2054 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
2055 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
2056 case Mode.U8_I8: /* nothing */ break;
2057 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
2059 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
2060 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
2061 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
2063 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
2064 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
2065 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
2066 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
2067 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
2068 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
2069 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
2070 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
2071 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
2073 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
2074 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
2075 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
2076 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
2077 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
2078 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
2079 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
2080 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
2081 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
2082 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
2088 public class OpcodeCast : TypeCast {
2092 public OpcodeCast (Expression child, Type return_type, OpCode op)
2093 : base (child, return_type)
2097 second_valid = false;
2100 public OpcodeCast (Expression child, Type return_type, OpCode op, OpCode op2)
2101 : base (child, return_type)
2106 second_valid = true;
2109 public override Expression DoResolve (EmitContext ec)
2111 // This should never be invoked, we are born in fully
2112 // initialized state.
2117 public override void Emit (EmitContext ec)
2126 public Type UnderlyingType {
2127 get { return child.Type; }
2132 /// This kind of cast is used to encapsulate a child and cast it
2133 /// to the class requested
2135 public sealed class ClassCast : TypeCast {
2136 Type child_generic_parameter;
2138 public ClassCast (Expression child, Type return_type)
2139 : base (child, return_type)
2142 if (TypeManager.IsGenericParameter (child.Type))
2143 child_generic_parameter = child.Type;
2146 public override Expression DoResolve (EmitContext ec)
2148 // This should never be invoked, we are born in fully
2149 // initialized state.
2154 public override void Emit (EmitContext ec)
2158 if (child_generic_parameter != null)
2159 ec.ig.Emit (OpCodes.Box, child_generic_parameter);
2162 if (type.IsGenericParameter)
2163 ec.ig.Emit (OpCodes.Unbox_Any, type);
2166 ec.ig.Emit (OpCodes.Castclass, type);
2169 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2171 type = storey.MutateType (type);
2172 if (child_generic_parameter != null)
2173 child_generic_parameter = storey.MutateGenericArgument (child_generic_parameter);
2175 base.MutateHoistedGenericType (storey);
2180 // Used when resolved expression has different representations for
2181 // expression trees and emit phase
2183 public class ReducedExpression : Expression
2185 class ReducedConstantExpression : Constant
2187 readonly Constant expr;
2188 readonly Expression orig_expr;
2190 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2191 : base (expr.Location)
2194 this.orig_expr = orig_expr;
2195 eclass = expr.eclass;
2199 public override string AsString ()
2201 return expr.AsString ();
2204 public override Expression CreateExpressionTree (EmitContext ec)
2206 return orig_expr.CreateExpressionTree (ec);
2209 public override object GetValue ()
2211 return expr.GetValue ();
2214 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
2216 throw new NotImplementedException ();
2219 public override Expression DoResolve (EmitContext ec)
2224 public override Constant Increment ()
2226 throw new NotImplementedException ();
2229 public override bool IsDefaultValue {
2231 return expr.IsDefaultValue;
2235 public override bool IsNegative {
2237 return expr.IsNegative;
2241 public override void Emit (EmitContext ec)
2247 readonly Expression expr, orig_expr;
2249 private ReducedExpression (Expression expr, Expression orig_expr)
2252 this.orig_expr = orig_expr;
2253 this.loc = orig_expr.Location;
2256 public static Expression Create (Constant expr, Expression original_expr)
2258 return new ReducedConstantExpression (expr, original_expr);
2261 public static Expression Create (Expression expr, Expression original_expr)
2263 Constant c = expr as Constant;
2265 return Create (c, original_expr);
2267 return new ReducedExpression (expr, original_expr);
2270 public override Expression CreateExpressionTree (EmitContext ec)
2272 return orig_expr.CreateExpressionTree (ec);
2275 public override Expression DoResolve (EmitContext ec)
2277 eclass = expr.eclass;
2282 public override void Emit (EmitContext ec)
2287 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2289 expr.EmitBranchable (ec, target, on_true);
2294 // Unresolved type name expressions
2296 public abstract class ATypeNameExpression : FullNamedExpression
2298 public readonly string Name;
2299 protected TypeArguments targs;
2301 protected ATypeNameExpression (string name, Location l)
2307 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2314 public bool HasTypeArguments {
2316 return targs != null;
2320 public override string GetSignatureForError ()
2322 if (targs != null) {
2323 return TypeManager.RemoveGenericArity (Name) + "<" +
2324 targs.GetSignatureForError () + ">";
2332 /// SimpleName expressions are formed of a single word and only happen at the beginning
2333 /// of a dotted-name.
2335 public class SimpleName : ATypeNameExpression {
2338 public SimpleName (string name, Location l)
2343 public SimpleName (string name, TypeArguments args, Location l)
2344 : base (name, args, l)
2348 public SimpleName (string name, TypeParameter[] type_params, Location l)
2351 targs = new TypeArguments (l);
2352 foreach (TypeParameter type_param in type_params)
2353 targs.Add (new TypeParameterExpr (type_param, l));
2356 public static string RemoveGenericArity (string name)
2359 StringBuilder sb = null;
2361 int pos = name.IndexOf ('`', start);
2366 sb.Append (name.Substring (start));
2371 sb = new StringBuilder ();
2372 sb.Append (name.Substring (start, pos-start));
2375 while ((pos < name.Length) && Char.IsNumber (name [pos]))
2379 } while (start < name.Length);
2381 return sb.ToString ();
2384 public SimpleName GetMethodGroup ()
2386 return new SimpleName (RemoveGenericArity (Name), targs, loc);
2389 public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
2391 if (ec.IsInFieldInitializer)
2392 Report.Error (236, l,
2393 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2397 120, l, "`{0}': An object reference is required for the nonstatic field, method or property",
2401 public bool IdenticalNameAndTypeName (EmitContext ec, Expression resolved_to, Location loc)
2403 return resolved_to != null && resolved_to.Type != null &&
2404 resolved_to.Type.Name == Name &&
2405 (ec.DeclContainer.LookupNamespaceOrType (Name, loc, /* ignore_cs0104 = */ true) != null);
2408 public override Expression DoResolve (EmitContext ec)
2410 return SimpleNameResolve (ec, null, false);
2413 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
2415 return SimpleNameResolve (ec, right_side, false);
2419 public Expression DoResolve (EmitContext ec, bool intermediate)
2421 return SimpleNameResolve (ec, null, intermediate);
2424 static bool IsNestedChild (Type t, Type parent)
2426 while (parent != null) {
2427 if (TypeManager.IsNestedChildOf (t, TypeManager.DropGenericTypeArguments (parent)))
2430 parent = parent.BaseType;
2436 FullNamedExpression ResolveNested (IResolveContext ec, Type t)
2438 if (!TypeManager.IsGenericTypeDefinition (t) && !TypeManager.IsGenericType (t))
2441 DeclSpace ds = ec.DeclContainer;
2442 while (ds != null && !IsNestedChild (t, ds.TypeBuilder))
2448 Type[] gen_params = TypeManager.GetTypeArguments (t);
2450 int arg_count = targs != null ? targs.Count : 0;
2452 for (; (ds != null) && ds.IsGeneric; ds = ds.Parent) {
2453 if (arg_count + ds.CountTypeParameters == gen_params.Length) {
2454 TypeArguments new_args = new TypeArguments (loc);
2455 foreach (TypeParameter param in ds.TypeParameters)
2456 new_args.Add (new TypeParameterExpr (param, loc));
2459 new_args.Add (targs);
2461 return new ConstructedType (t, new_args, loc);
2468 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2470 FullNamedExpression fne = ec.GenericDeclContainer.LookupGeneric (Name, loc);
2472 return fne.ResolveAsTypeStep (ec, silent);
2474 int errors = Report.Errors;
2475 fne = ec.DeclContainer.LookupNamespaceOrType (Name, loc, /*ignore_cs0104=*/ false);
2478 if (fne.Type == null)
2481 FullNamedExpression nested = ResolveNested (ec, fne.Type);
2483 return nested.ResolveAsTypeStep (ec, false);
2485 if (targs != null) {
2486 ConstructedType ct = new ConstructedType (fne, targs, loc);
2487 return ct.ResolveAsTypeStep (ec, false);
2493 if (silent || errors != Report.Errors)
2496 Error_TypeOrNamespaceNotFound (ec);
2500 protected virtual void Error_TypeOrNamespaceNotFound (IResolveContext ec)
2502 MemberCore mc = ec.DeclContainer.GetDefinition (Name);
2504 Error_UnexpectedKind (ec.DeclContainer, "type", GetMemberType (mc), loc);
2508 string ns = ec.DeclContainer.NamespaceEntry.NS.Name;
2509 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2510 foreach (Assembly a in RootNamespace.Global.Assemblies) {
2511 Type type = a.GetType (fullname);
2513 Report.SymbolRelatedToPreviousError (type);
2514 Expression.ErrorIsInaccesible (loc, TypeManager.CSharpName (type));
2519 Type t = ec.DeclContainer.LookupAnyGeneric (Name);
2521 Namespace.Error_InvalidNumberOfTypeArguments (t, loc);
2525 if (targs != null) {
2526 FullNamedExpression retval = ec.DeclContainer.LookupNamespaceOrType (SimpleName.RemoveGenericArity (Name), loc, true);
2527 if (retval != null) {
2528 Namespace.Error_TypeArgumentsCannotBeUsed (retval.Type, loc);
2533 NamespaceEntry.Error_NamespaceNotFound (loc, Name);
2536 // TODO: I am still not convinced about this. If someone else will need it
2537 // implement this as virtual property in MemberCore hierarchy
2538 public static string GetMemberType (MemberCore mc)
2544 if (mc is FieldBase)
2546 if (mc is MethodCore)
2548 if (mc is EnumMember)
2556 Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2562 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2568 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2575 /// 7.5.2: Simple Names.
2577 /// Local Variables and Parameters are handled at
2578 /// parse time, so they never occur as SimpleNames.
2580 /// The `intermediate' flag is used by MemberAccess only
2581 /// and it is used to inform us that it is ok for us to
2582 /// avoid the static check, because MemberAccess might end
2583 /// up resolving the Name as a Type name and the access as
2584 /// a static type access.
2586 /// ie: Type Type; .... { Type.GetType (""); }
2588 /// Type is both an instance variable and a Type; Type.GetType
2589 /// is the static method not an instance method of type.
2591 Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2593 Expression e = null;
2596 // Stage 1: Performed by the parser (binding to locals or parameters).
2598 Block current_block = ec.CurrentBlock;
2599 if (current_block != null){
2600 LocalInfo vi = current_block.GetLocalInfo (Name);
2602 if (targs != null) {
2603 Report.Error (307, loc,
2604 "The variable `{0}' cannot be used with type arguments",
2609 LocalVariableReference var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2610 if (right_side != null) {
2611 return var.ResolveLValue (ec, right_side, loc);
2613 ResolveFlags rf = ResolveFlags.VariableOrValue;
2615 rf |= ResolveFlags.DisableFlowAnalysis;
2616 return var.Resolve (ec, rf);
2620 ParameterReference pref = current_block.Toplevel.GetParameterReference (Name, loc);
2622 if (targs != null) {
2623 Report.Error (307, loc,
2624 "The variable `{0}' cannot be used with type arguments",
2629 if (right_side != null)
2630 return pref.ResolveLValue (ec, right_side, loc);
2632 return pref.Resolve (ec);
2635 Expression expr = current_block.Toplevel.GetTransparentIdentifier (Name);
2637 if (right_side != null)
2638 return expr.ResolveLValue (ec, right_side, loc);
2639 return expr.Resolve (ec);
2644 // Stage 2: Lookup members
2647 Type almost_matched_type = null;
2648 ArrayList almost_matched = null;
2649 for (DeclSpace lookup_ds = ec.DeclContainer; lookup_ds != null; lookup_ds = lookup_ds.Parent) {
2650 // either RootDeclSpace or GenericMethod
2651 if (lookup_ds.TypeBuilder == null)
2654 e = MemberLookup (ec.ContainerType, lookup_ds.TypeBuilder, Name, loc);
2656 if (e is PropertyExpr) {
2657 // since TypeManager.MemberLookup doesn't know if we're doing a lvalue access or not,
2658 // it doesn't know which accessor to check permissions against
2659 if (((PropertyExpr) e).IsAccessibleFrom (ec.ContainerType, right_side != null))
2661 } else if (e is EventExpr) {
2662 if (((EventExpr) e).IsAccessibleFrom (ec.ContainerType))
2670 if (almost_matched == null && almost_matched_members.Count > 0) {
2671 almost_matched_type = lookup_ds.TypeBuilder;
2672 almost_matched = (ArrayList) almost_matched_members.Clone ();
2677 if (almost_matched == null && almost_matched_members.Count > 0) {
2678 almost_matched_type = ec.ContainerType;
2679 almost_matched = (ArrayList) almost_matched_members.Clone ();
2681 e = ResolveAsTypeStep (ec, true);
2685 if (current_block != null) {
2686 IKnownVariable ikv = current_block.Explicit.GetKnownVariable (Name);
2688 LocalInfo li = ikv as LocalInfo;
2689 // Supress CS0219 warning
2693 Error_VariableIsUsedBeforeItIsDeclared (Name);
2698 if (almost_matched != null)
2699 almost_matched_members = almost_matched;
2700 if (almost_matched_type == null)
2701 almost_matched_type = ec.ContainerType;
2702 Error_MemberLookupFailed (ec.ContainerType, null, almost_matched_type, Name,
2703 ec.DeclContainer.Name, AllMemberTypes, AllBindingFlags);
2707 if (e is TypeExpr) {
2711 ConstructedType ct = new ConstructedType (
2712 e.Type, targs, loc);
2713 return ct.ResolveAsTypeStep (ec, false);
2716 if (e is MemberExpr) {
2717 MemberExpr me = (MemberExpr) e;
2720 if (me.IsInstance) {
2721 if (ec.IsStatic || ec.IsInFieldInitializer) {
2723 // Note that an MemberExpr can be both IsInstance and IsStatic.
2724 // An unresolved MethodGroupExpr can contain both kinds of methods
2725 // and each predicate is true if the MethodGroupExpr contains
2726 // at least one of that kind of method.
2730 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2731 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2736 // Pass the buck to MemberAccess and Invocation.
2738 left = EmptyExpression.Null;
2740 left = ec.GetThis (loc);
2743 left = new TypeExpression (ec.ContainerType, loc);
2746 me = me.ResolveMemberAccess (ec, left, loc, null);
2750 if (targs != null) {
2752 me.SetTypeArguments (targs);
2755 if (!me.IsStatic && (me.InstanceExpression != null) &&
2756 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2757 me.InstanceExpression.Type != me.DeclaringType &&
2758 !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2759 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2760 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2761 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2765 return (right_side != null)
2766 ? me.DoResolveLValue (ec, right_side)
2767 : me.DoResolve (ec);
2773 protected override void CloneTo (CloneContext clonectx, Expression target)
2775 // CloneTo: Nothing, we do not keep any state on this expression
2780 /// Represents a namespace or a type. The name of the class was inspired by
2781 /// section 10.8.1 (Fully Qualified Names).
2783 public abstract class FullNamedExpression : Expression {
2785 public override Expression CreateExpressionTree (EmitContext ec)
2787 throw new NotSupportedException ("ET");
2790 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2795 public override void Emit (EmitContext ec)
2797 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2798 GetSignatureForError ());
2803 /// Expression that evaluates to a type
2805 public abstract class TypeExpr : FullNamedExpression {
2806 override public FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2808 TypeExpr t = DoResolveAsTypeStep (ec);
2812 eclass = ExprClass.Type;
2816 override public Expression DoResolve (EmitContext ec)
2818 return ResolveAsTypeTerminal (ec, false);
2821 public virtual bool CheckAccessLevel (DeclSpace ds)
2823 return ds.CheckAccessLevel (Type);
2826 public virtual bool AsAccessible (DeclSpace ds)
2828 return ds.IsAccessibleAs (Type);
2831 public virtual bool IsClass {
2832 get { return Type.IsClass; }
2835 public virtual bool IsValueType {
2836 get { return Type.IsValueType; }
2839 public virtual bool IsInterface {
2840 get { return Type.IsInterface; }
2843 public virtual bool IsSealed {
2844 get { return Type.IsSealed; }
2847 public virtual bool CanInheritFrom ()
2849 if (Type == TypeManager.enum_type ||
2850 (Type == TypeManager.value_type && RootContext.StdLib) ||
2851 Type == TypeManager.multicast_delegate_type ||
2852 Type == TypeManager.delegate_type ||
2853 Type == TypeManager.array_type)
2859 protected abstract TypeExpr DoResolveAsTypeStep (IResolveContext ec);
2861 public override bool Equals (object obj)
2863 TypeExpr tobj = obj as TypeExpr;
2867 return Type == tobj.Type;
2870 public override int GetHashCode ()
2872 return Type.GetHashCode ();
2875 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2877 type = storey.MutateType (type);
2882 /// Fully resolved Expression that already evaluated to a type
2884 public class TypeExpression : TypeExpr {
2885 public TypeExpression (Type t, Location l)
2888 eclass = ExprClass.Type;
2892 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2897 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2904 /// Used to create types from a fully qualified name. These are just used
2905 /// by the parser to setup the core types. A TypeLookupExpression is always
2906 /// classified as a type.
2908 public sealed class TypeLookupExpression : TypeExpr {
2909 readonly string name;
2911 public TypeLookupExpression (string name)
2914 eclass = ExprClass.Type;
2917 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2919 // It's null for corlib compilation only
2921 return DoResolveAsTypeStep (ec);
2926 private class UnexpectedType
2930 // This performes recursive type lookup, providing support for generic types.
2931 // For example, given the type:
2933 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]]
2935 // The types will be checked in the following order:
2938 // System.Collections |
2939 // System.Collections.Generic |
2941 // System | recursive call 1 |
2942 // System.Int32 _| | main method call
2944 // System | recursive call 2 |
2945 // System.String _| |
2947 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]] _|
2949 private Type TypeLookup (IResolveContext ec, string name)
2954 FullNamedExpression resolved = null;
2956 Type recursive_type = null;
2957 while (index < name.Length) {
2958 if (name[index] == '[') {
2963 if (name[index] == '[')
2965 else if (name[index] == ']')
2967 } while (braces > 0);
2968 recursive_type = TypeLookup (ec, name.Substring (open + 1, index - open - 1));
2969 if (recursive_type == null || (recursive_type == typeof(UnexpectedType)))
2970 return recursive_type;
2973 if (name[index] == ',')
2975 else if ((name[index] == '.' && !done) || (index == name.Length && name[0] != '[')) {
2976 string substring = name.Substring(dot, index - dot);
2978 if (resolved == null)
2979 resolved = RootNamespace.Global.Lookup (ec.DeclContainer, substring, Location.Null);
2980 else if (resolved is Namespace)
2981 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
2982 else if (type != null)
2983 type = TypeManager.GetNestedType (type, substring);
2987 if (resolved == null)
2989 else if (type == null && resolved is TypeExpr)
2990 type = resolved.Type;
2997 if (name[0] != '[') {
2998 string substring = name.Substring(dot, index - dot);
3001 return TypeManager.GetNestedType (type, substring);
3003 if (resolved != null) {
3004 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
3005 if (resolved is TypeExpr)
3006 return resolved.Type;
3008 if (resolved == null)
3011 resolved.Error_UnexpectedKind (ec.DeclContainer, "type", loc);
3012 return typeof (UnexpectedType);
3018 return recursive_type;
3021 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
3023 Type t = TypeLookup (ec, name);
3025 NamespaceEntry.Error_NamespaceNotFound (loc, name);
3028 if (t == typeof(UnexpectedType))
3034 protected override void CloneTo (CloneContext clonectx, Expression target)
3036 // CloneTo: Nothing, we do not keep any state on this expression
3039 public override string GetSignatureForError ()
3042 return TypeManager.CSharpName (name);
3044 return base.GetSignatureForError ();
3049 /// Represents an "unbound generic type", ie. typeof (Foo<>).
3052 public class UnboundTypeExpression : TypeExpr
3056 public UnboundTypeExpression (MemberName name, Location l)
3062 protected override void CloneTo (CloneContext clonectx, Expression target)
3067 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
3070 if (name.Left != null) {
3071 Expression lexpr = name.Left.GetTypeExpression ();
3072 expr = new MemberAccess (lexpr, name.Basename);
3074 expr = new SimpleName (name.Basename, loc);
3077 FullNamedExpression fne = expr.ResolveAsTypeStep (ec, false);
3082 return new TypeExpression (type, loc);
3087 /// This class denotes an expression which evaluates to a member
3088 /// of a struct or a class.
3090 public abstract class MemberExpr : Expression
3092 protected bool is_base;
3095 /// The name of this member.
3097 public abstract string Name {
3102 // When base.member is used
3104 public bool IsBase {
3105 get { return is_base; }
3106 set { is_base = value; }
3110 /// Whether this is an instance member.
3112 public abstract bool IsInstance {
3117 /// Whether this is a static member.
3119 public abstract bool IsStatic {
3124 /// The type which declares this member.
3126 public abstract Type DeclaringType {
3131 /// The instance expression associated with this member, if it's a
3132 /// non-static member.
3134 public Expression InstanceExpression;
3136 public static void error176 (Location loc, string name)
3138 Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
3139 "with an instance reference, qualify it with a type name instead", name);
3142 public static void Error_BaseAccessInExpressionTree (Location loc)
3144 Report.Error (831, loc, "An expression tree may not contain a base access");
3147 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3149 if (InstanceExpression != null)
3150 InstanceExpression.MutateHoistedGenericType (storey);
3153 // TODO: possible optimalization
3154 // Cache resolved constant result in FieldBuilder <-> expression map
3155 public virtual MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3156 SimpleName original)
3160 // original == null || original.Resolve (...) ==> left
3163 if (left is TypeExpr) {
3164 left = left.ResolveAsTypeTerminal (ec, true);
3169 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3177 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3180 return ResolveExtensionMemberAccess (left);
3183 InstanceExpression = left;
3187 protected virtual MemberExpr ResolveExtensionMemberAccess (Expression left)
3189 error176 (loc, GetSignatureForError ());
3193 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3198 if (InstanceExpression == EmptyExpression.Null) {
3199 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3203 if (InstanceExpression.Type.IsValueType) {
3204 if (InstanceExpression is IMemoryLocation) {
3205 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
3207 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
3208 InstanceExpression.Emit (ec);
3210 t.AddressOf (ec, AddressOp.Store);
3213 InstanceExpression.Emit (ec);
3215 if (prepare_for_load)
3216 ec.ig.Emit (OpCodes.Dup);
3219 public virtual void SetTypeArguments (TypeArguments ta)
3221 // TODO: need to get correct member type
3222 Report.Error (307, loc, "The property `{0}' cannot be used with type arguments",
3223 GetSignatureForError ());
3228 /// Represents group of extension methods
3230 public class ExtensionMethodGroupExpr : MethodGroupExpr
3232 readonly NamespaceEntry namespace_entry;
3233 public Expression ExtensionExpression;
3234 Argument extension_argument;
3236 public ExtensionMethodGroupExpr (ArrayList list, NamespaceEntry n, Type extensionType, Location l)
3237 : base (list, extensionType, l)
3239 this.namespace_entry = n;
3242 public override bool IsStatic {
3243 get { return true; }
3246 public bool IsTopLevel {
3247 get { return namespace_entry == null; }
3250 public override void EmitArguments (EmitContext ec, ArrayList arguments)
3252 if (arguments == null)
3253 arguments = new ArrayList (1);
3254 arguments.Insert (0, extension_argument);
3255 base.EmitArguments (ec, arguments);
3258 public override void EmitCall (EmitContext ec, ArrayList arguments)
3260 if (arguments == null)
3261 arguments = new ArrayList (1);
3262 arguments.Insert (0, extension_argument);
3263 base.EmitCall (ec, arguments);
3266 public override MethodGroupExpr OverloadResolve (EmitContext ec, ref ArrayList arguments, bool may_fail, Location loc)
3268 if (arguments == null)
3269 arguments = new ArrayList (1);
3271 arguments.Insert (0, new Argument (ExtensionExpression));
3272 MethodGroupExpr mg = ResolveOverloadExtensions (ec, arguments, namespace_entry, loc);
3274 // Store resolved argument and restore original arguments
3276 ((ExtensionMethodGroupExpr)mg).extension_argument = (Argument)arguments [0];
3277 arguments.RemoveAt (0);
3282 MethodGroupExpr ResolveOverloadExtensions (EmitContext ec, ArrayList arguments, NamespaceEntry ns, Location loc)
3284 // Use normal resolve rules
3285 MethodGroupExpr mg = base.OverloadResolve (ec, ref arguments, ns != null, loc);
3293 ExtensionMethodGroupExpr e = ns.LookupExtensionMethod (type, null, Name, loc);
3295 return base.OverloadResolve (ec, ref arguments, false, loc);
3297 e.ExtensionExpression = ExtensionExpression;
3298 e.SetTypeArguments (type_arguments);
3299 return e.ResolveOverloadExtensions (ec, arguments, e.namespace_entry, loc);
3304 /// MethodGroupExpr represents a group of method candidates which
3305 /// can be resolved to the best method overload
3307 public class MethodGroupExpr : MemberExpr
3309 public interface IErrorHandler
3311 bool NoExactMatch (EmitContext ec, MethodBase method);
3314 public IErrorHandler CustomErrorHandler;
3315 public MethodBase [] Methods;
3316 MethodBase best_candidate;
3317 // TODO: make private
3318 public TypeArguments type_arguments;
3319 bool identical_type_name;
3322 public MethodGroupExpr (MemberInfo [] mi, Type type, Location l)
3325 Methods = new MethodBase [mi.Length];
3326 mi.CopyTo (Methods, 0);
3329 public MethodGroupExpr (ArrayList list, Type type, Location l)
3333 Methods = (MethodBase[])list.ToArray (typeof (MethodBase));
3335 foreach (MemberInfo m in list){
3336 if (!(m is MethodBase)){
3337 Console.WriteLine ("Name " + m.Name);
3338 Console.WriteLine ("Found a: " + m.GetType ().FullName);
3347 protected MethodGroupExpr (Type type, Location loc)
3350 eclass = ExprClass.MethodGroup;
3354 public override Type DeclaringType {
3357 // We assume that the top-level type is in the end
3359 return Methods [Methods.Length - 1].DeclaringType;
3360 //return Methods [0].DeclaringType;
3364 public Type DelegateType {
3366 delegate_type = value;
3370 public bool IdenticalTypeName {
3372 return identical_type_name;
3376 identical_type_name = value;
3380 public override string GetSignatureForError ()
3382 if (best_candidate != null)
3383 return TypeManager.CSharpSignature (best_candidate);
3385 return TypeManager.CSharpSignature (Methods [0]);
3388 public override string Name {
3390 return Methods [0].Name;
3394 public override bool IsInstance {
3396 if (best_candidate != null)
3397 return !best_candidate.IsStatic;
3399 foreach (MethodBase mb in Methods)
3407 public override bool IsStatic {
3409 if (best_candidate != null)
3410 return best_candidate.IsStatic;
3412 foreach (MethodBase mb in Methods)
3420 public static explicit operator ConstructorInfo (MethodGroupExpr mg)
3422 return (ConstructorInfo)mg.best_candidate;
3425 public static explicit operator MethodInfo (MethodGroupExpr mg)
3427 return (MethodInfo)mg.best_candidate;
3431 // 7.4.3.3 Better conversion from expression
3432 // Returns : 1 if a->p is better,
3433 // 2 if a->q is better,
3434 // 0 if neither is better
3436 static int BetterExpressionConversion (EmitContext ec, Argument a, Type p, Type q)
3438 Type argument_type = TypeManager.TypeToCoreType (a.Type);
3439 if (argument_type == TypeManager.anonymous_method_type && RootContext.Version > LanguageVersion.ISO_2) {
3441 // Uwrap delegate from Expression<T>
3443 if (TypeManager.DropGenericTypeArguments (p) == TypeManager.expression_type) {
3444 p = TypeManager.GetTypeArguments (p) [0];
3446 if (TypeManager.DropGenericTypeArguments (q) == TypeManager.expression_type) {
3447 q = TypeManager.GetTypeArguments (q) [0];
3450 p = Delegate.GetInvokeMethod (null, p).ReturnType;
3451 q = Delegate.GetInvokeMethod (null, q).ReturnType;
3453 if (argument_type == p)
3456 if (argument_type == q)
3460 return BetterTypeConversion (ec, p, q);
3464 // 7.4.3.4 Better conversion from type
3466 public static int BetterTypeConversion (EmitContext ec, Type p, Type q)
3468 if (p == null || q == null)
3469 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3471 if (p == TypeManager.int32_type) {
3472 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3474 } else if (p == TypeManager.int64_type) {
3475 if (q == TypeManager.uint64_type)
3477 } else if (p == TypeManager.sbyte_type) {
3478 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3479 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3481 } else if (p == TypeManager.short_type) {
3482 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3483 q == TypeManager.uint64_type)
3487 if (q == TypeManager.int32_type) {
3488 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3490 } if (q == TypeManager.int64_type) {
3491 if (p == TypeManager.uint64_type)
3493 } else if (q == TypeManager.sbyte_type) {
3494 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3495 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3497 } if (q == TypeManager.short_type) {
3498 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3499 p == TypeManager.uint64_type)
3503 // TODO: this is expensive
3504 Expression p_tmp = new EmptyExpression (p);
3505 Expression q_tmp = new EmptyExpression (q);
3507 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3508 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3510 if (p_to_q && !q_to_p)
3513 if (q_to_p && !p_to_q)
3520 /// Determines "Better function" between candidate
3521 /// and the current best match
3524 /// Returns a boolean indicating :
3525 /// false if candidate ain't better
3526 /// true if candidate is better than the current best match
3528 static bool BetterFunction (EmitContext ec, ArrayList args, int argument_count,
3529 MethodBase candidate, bool candidate_params,
3530 MethodBase best, bool best_params)
3532 ParameterData candidate_pd = TypeManager.GetParameterData (candidate);
3533 ParameterData best_pd = TypeManager.GetParameterData (best);
3535 bool better_at_least_one = false;
3537 for (int j = 0, c_idx = 0, b_idx = 0; j < argument_count; ++j, ++c_idx, ++b_idx)
3539 Argument a = (Argument) args [j];
3541 Type ct = TypeManager.TypeToCoreType (candidate_pd.ParameterType (c_idx));
3542 Type bt = TypeManager.TypeToCoreType (best_pd.ParameterType (b_idx));
3544 if (candidate_params && candidate_pd.ParameterModifier (c_idx) == Parameter.Modifier.PARAMS)
3546 ct = TypeManager.GetElementType (ct);
3550 if (best_params && best_pd.ParameterModifier (b_idx) == Parameter.Modifier.PARAMS)
3552 bt = TypeManager.GetElementType (bt);
3560 int result = BetterExpressionConversion (ec, a, ct, bt);
3562 // for each argument, the conversion to 'ct' should be no worse than
3563 // the conversion to 'bt'.
3567 // for at least one argument, the conversion to 'ct' should be better than
3568 // the conversion to 'bt'.
3570 better_at_least_one = true;
3573 if (better_at_least_one)
3577 // This handles the case
3579 // Add (float f1, float f2, float f3);
3580 // Add (params decimal [] foo);
3582 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3583 // first candidate would've chosen as better.
3589 // The two methods have equal parameter types. Now apply tie-breaking rules
3591 if (TypeManager.IsGenericMethod (best) && !TypeManager.IsGenericMethod (candidate))
3593 if (!TypeManager.IsGenericMethod (best) && TypeManager.IsGenericMethod (candidate))
3597 // This handles the following cases:
3599 // Trim () is better than Trim (params char[] chars)
3600 // Concat (string s1, string s2, string s3) is better than
3601 // Concat (string s1, params string [] srest)
3602 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3604 if (!candidate_params && best_params)
3606 if (candidate_params && !best_params)
3609 int candidate_param_count = candidate_pd.Count;
3610 int best_param_count = best_pd.Count;
3612 if (candidate_param_count != best_param_count)
3613 // can only happen if (candidate_params && best_params)
3614 return candidate_param_count > best_param_count;
3617 // now, both methods have the same number of parameters, and the parameters have the same types
3618 // Pick the "more specific" signature
3621 MethodBase orig_candidate = TypeManager.DropGenericMethodArguments (candidate);
3622 MethodBase orig_best = TypeManager.DropGenericMethodArguments (best);
3624 ParameterData orig_candidate_pd = TypeManager.GetParameterData (orig_candidate);
3625 ParameterData orig_best_pd = TypeManager.GetParameterData (orig_best);
3627 bool specific_at_least_once = false;
3628 for (int j = 0; j < candidate_param_count; ++j)
3630 Type ct = TypeManager.TypeToCoreType (orig_candidate_pd.ParameterType (j));
3631 Type bt = TypeManager.TypeToCoreType (orig_best_pd.ParameterType (j));
3634 Type specific = MoreSpecific (ct, bt);
3638 specific_at_least_once = true;
3641 if (specific_at_least_once)
3644 // FIXME: handle lifted operators
3650 protected override MemberExpr ResolveExtensionMemberAccess (Expression left)
3653 return base.ResolveExtensionMemberAccess (left);
3656 // When left side is an expression and at least one candidate method is
3657 // static, it can be extension method
3659 InstanceExpression = left;
3663 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3664 SimpleName original)
3666 if (!(left is TypeExpr) &&
3667 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3668 IdenticalTypeName = true;
3670 return base.ResolveMemberAccess (ec, left, loc, original);
3673 public override Expression CreateExpressionTree (EmitContext ec)
3675 if (best_candidate == null) {
3676 Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3680 if (best_candidate.IsConstructor)
3681 return new TypeOfConstructorInfo (best_candidate, loc);
3683 IMethodData md = TypeManager.GetMethod (best_candidate);
3684 if (md != null && md.IsExcluded ())
3685 Report.Error (765, loc,
3686 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3688 return new TypeOfMethodInfo (best_candidate, loc);
3691 override public Expression DoResolve (EmitContext ec)
3693 if (InstanceExpression != null) {
3694 InstanceExpression = InstanceExpression.DoResolve (ec);
3695 if (InstanceExpression == null)
3702 public void ReportUsageError ()
3704 Report.Error (654, loc, "Method `" + DeclaringType + "." +
3705 Name + "()' is referenced without parentheses");
3708 override public void Emit (EmitContext ec)
3710 ReportUsageError ();
3713 public virtual void EmitArguments (EmitContext ec, ArrayList arguments)
3715 Invocation.EmitArguments (ec, arguments, false, null);
3718 public virtual void EmitCall (EmitContext ec, ArrayList arguments)
3720 Invocation.EmitCall (ec, IsBase, InstanceExpression, best_candidate, arguments, loc);
3723 protected virtual void Error_InvalidArguments (EmitContext ec, Location loc, int idx, MethodBase method,
3724 Argument a, ParameterData expected_par, Type paramType)
3726 if (a is CollectionElementInitializer.ElementInitializerArgument) {
3727 Report.SymbolRelatedToPreviousError (method);
3728 if ((expected_par.ParameterModifier (idx) & Parameter.Modifier.ISBYREF) != 0) {
3729 Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
3730 TypeManager.CSharpSignature (method));
3733 Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
3734 TypeManager.CSharpSignature (method));
3735 } else if (delegate_type == null) {
3736 Report.SymbolRelatedToPreviousError (method);
3737 Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
3738 TypeManager.CSharpSignature (method));
3740 Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
3741 TypeManager.CSharpName (delegate_type));
3743 Parameter.Modifier mod = expected_par.ParameterModifier (idx);
3745 string index = (idx + 1).ToString ();
3746 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
3747 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
3748 if ((mod & Parameter.Modifier.ISBYREF) == 0)
3749 Report.Error (1615, loc, "Argument `{0}' should not be passed with the `{1}' keyword",
3750 index, Parameter.GetModifierSignature (a.Modifier));
3752 Report.Error (1620, loc, "Argument `{0}' must be passed with the `{1}' keyword",
3753 index, Parameter.GetModifierSignature (mod));
3755 string p1 = a.GetSignatureForError ();
3756 string p2 = TypeManager.CSharpName (paramType);
3759 Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
3760 Report.SymbolRelatedToPreviousError (a.Expr.Type);
3761 Report.SymbolRelatedToPreviousError (paramType);
3763 Report.Error (1503, loc, "Argument {0}: Cannot convert type `{1}' to `{2}'", index, p1, p2);
3767 public override void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl)
3769 Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3770 Name, TypeManager.CSharpName (target));
3773 protected virtual int GetApplicableParametersCount (MethodBase method, ParameterData parameters)
3775 return parameters.Count;
3778 public static bool IsAncestralType (Type first_type, Type second_type)
3780 return first_type != second_type &&
3781 (TypeManager.IsSubclassOf (second_type, first_type) ||
3782 TypeManager.ImplementsInterface (second_type, first_type));
3786 /// Determines if the candidate method is applicable (section 14.4.2.1)
3787 /// to the given set of arguments
3788 /// A return value rates candidate method compatibility,
3789 /// 0 = the best, int.MaxValue = the worst
3791 public int IsApplicable (EmitContext ec,
3792 ArrayList arguments, int arg_count, ref MethodBase method, ref bool params_expanded_form)
3794 MethodBase candidate = method;
3796 ParameterData pd = TypeManager.GetParameterData (candidate);
3797 int param_count = GetApplicableParametersCount (candidate, pd);
3799 if (arg_count != param_count) {
3801 return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
3802 if (arg_count < param_count - 1)
3803 return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
3808 // 1. Handle generic method using type arguments when specified or type inference
3810 if (TypeManager.IsGenericMethod (candidate)) {
3811 if (type_arguments != null) {
3812 Type [] g_args = candidate.GetGenericArguments ();
3813 if (g_args.Length != type_arguments.Count)
3814 return int.MaxValue - 20000 + Math.Abs (type_arguments.Count - g_args.Length);
3816 // TODO: Don't create new method, create Parameters only
3817 method = ((MethodInfo) candidate).MakeGenericMethod (type_arguments.Arguments);
3819 pd = TypeManager.GetParameterData (candidate);
3821 int score = TypeManager.InferTypeArguments (ec, arguments, ref candidate);
3823 return score - 20000;
3825 if (TypeManager.IsGenericMethodDefinition (candidate))
3826 throw new InternalErrorException ("A generic method `{0}' definition took part in overload resolution",
3827 TypeManager.CSharpSignature (candidate));
3829 pd = TypeManager.GetParameterData (candidate);
3832 if (type_arguments != null)
3833 return int.MaxValue - 15000;
3838 // 2. Each argument has to be implicitly convertible to method parameter
3841 Parameter.Modifier p_mod = 0;
3843 for (int i = 0; i < arg_count; i++) {
3844 Argument a = (Argument) arguments [i];
3845 Parameter.Modifier a_mod = a.Modifier &
3846 ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3848 if (p_mod != Parameter.Modifier.PARAMS) {
3849 p_mod = pd.ParameterModifier (i) & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3851 if (p_mod == Parameter.Modifier.ARGLIST) {
3852 if (a.Type == TypeManager.runtime_argument_handle_type)
3858 pt = pd.ParameterType (i);
3860 params_expanded_form = true;
3864 if (!params_expanded_form)
3865 score = IsArgumentCompatible (ec, a_mod, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
3867 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0) {
3868 // It can be applicable in expanded form
3869 score = IsArgumentCompatible (ec, a_mod, a, 0, pt.GetElementType ());
3871 params_expanded_form = true;
3875 if (params_expanded_form)
3877 return (arg_count - i) * 2 + score;
3881 if (arg_count != param_count)
3882 params_expanded_form = true;
3887 int IsArgumentCompatible (EmitContext ec, Parameter.Modifier arg_mod, Argument argument, Parameter.Modifier param_mod, Type parameter)
3890 // Types have to be identical when ref or out modifer is used
3892 if (arg_mod != 0 || param_mod != 0) {
3893 if (TypeManager.HasElementType (parameter))
3894 parameter = parameter.GetElementType ();
3896 Type a_type = argument.Type;
3897 if (TypeManager.HasElementType (a_type))
3898 a_type = a_type.GetElementType ();
3900 if (a_type != parameter)
3906 if (delegate_type != null ?
3907 !Delegate.IsTypeCovariant (argument.Expr, parameter) :
3908 !Convert.ImplicitConversionExists (ec, argument.Expr, parameter))
3911 if (arg_mod != param_mod)
3917 public static bool IsOverride (MethodBase cand_method, MethodBase base_method)
3919 if (!IsAncestralType (base_method.DeclaringType, cand_method.DeclaringType))
3922 ParameterData cand_pd = TypeManager.GetParameterData (cand_method);
3923 ParameterData base_pd = TypeManager.GetParameterData (base_method);
3925 if (cand_pd.Count != base_pd.Count)
3928 for (int j = 0; j < cand_pd.Count; ++j)
3930 Parameter.Modifier cm = cand_pd.ParameterModifier (j);
3931 Parameter.Modifier bm = base_pd.ParameterModifier (j);
3932 Type ct = TypeManager.TypeToCoreType (cand_pd.ParameterType (j));
3933 Type bt = TypeManager.TypeToCoreType (base_pd.ParameterType (j));
3935 if (cm != bm || ct != bt)
3942 public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2, Location loc)
3944 MemberInfo [] miset;
3945 MethodGroupExpr union;
3950 return (MethodGroupExpr) mg2;
3953 return (MethodGroupExpr) mg1;
3956 MethodGroupExpr left_set = null, right_set = null;
3957 int length1 = 0, length2 = 0;
3959 left_set = (MethodGroupExpr) mg1;
3960 length1 = left_set.Methods.Length;
3962 right_set = (MethodGroupExpr) mg2;
3963 length2 = right_set.Methods.Length;
3965 ArrayList common = new ArrayList ();
3967 foreach (MethodBase r in right_set.Methods){
3968 if (TypeManager.ArrayContainsMethod (left_set.Methods, r))
3972 miset = new MemberInfo [length1 + length2 - common.Count];
3973 left_set.Methods.CopyTo (miset, 0);
3977 foreach (MethodBase r in right_set.Methods) {
3978 if (!common.Contains (r))
3982 union = new MethodGroupExpr (miset, mg1.Type, loc);
3987 static Type MoreSpecific (Type p, Type q)
3989 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
3991 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
3994 if (TypeManager.HasElementType (p))
3996 Type pe = TypeManager.GetElementType (p);
3997 Type qe = TypeManager.GetElementType (q);
3998 Type specific = MoreSpecific (pe, qe);
4004 else if (TypeManager.IsGenericType (p))
4006 Type[] pargs = TypeManager.GetTypeArguments (p);
4007 Type[] qargs = TypeManager.GetTypeArguments (q);
4009 bool p_specific_at_least_once = false;
4010 bool q_specific_at_least_once = false;
4012 for (int i = 0; i < pargs.Length; i++)
4014 Type specific = MoreSpecific (pargs [i], qargs [i]);
4015 if (specific == pargs [i])
4016 p_specific_at_least_once = true;
4017 if (specific == qargs [i])
4018 q_specific_at_least_once = true;
4021 if (p_specific_at_least_once && !q_specific_at_least_once)
4023 if (!p_specific_at_least_once && q_specific_at_least_once)
4030 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4032 base.MutateHoistedGenericType (storey);
4034 MethodInfo mi = best_candidate as MethodInfo;
4036 best_candidate = storey.MutateGenericMethod (mi);
4040 best_candidate = storey.MutateConstructor ((ConstructorInfo) this);
4044 /// Find the Applicable Function Members (7.4.2.1)
4046 /// me: Method Group expression with the members to select.
4047 /// it might contain constructors or methods (or anything
4048 /// that maps to a method).
4050 /// Arguments: ArrayList containing resolved Argument objects.
4052 /// loc: The location if we want an error to be reported, or a Null
4053 /// location for "probing" purposes.
4055 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4056 /// that is the best match of me on Arguments.
4059 public virtual MethodGroupExpr OverloadResolve (EmitContext ec, ref ArrayList Arguments,
4060 bool may_fail, Location loc)
4062 bool method_params = false;
4063 Type applicable_type = null;
4065 ArrayList candidates = new ArrayList (2);
4066 ArrayList candidate_overrides = null;
4069 // Used to keep a map between the candidate
4070 // and whether it is being considered in its
4071 // normal or expanded form
4073 // false is normal form, true is expanded form
4075 Hashtable candidate_to_form = null;
4077 if (Arguments != null)
4078 arg_count = Arguments.Count;
4080 if (RootContext.Version == LanguageVersion.ISO_1 && Name == "Invoke" && TypeManager.IsDelegateType (DeclaringType)) {
4082 Report.Error (1533, loc, "Invoke cannot be called directly on a delegate");
4086 int nmethods = Methods.Length;
4090 // Methods marked 'override' don't take part in 'applicable_type'
4091 // computation, nor in the actual overload resolution.
4092 // However, they still need to be emitted instead of a base virtual method.
4093 // So, we salt them away into the 'candidate_overrides' array.
4095 // In case of reflected methods, we replace each overriding method with
4096 // its corresponding base virtual method. This is to improve compatibility
4097 // with non-C# libraries which change the visibility of overrides (#75636)
4100 for (int i = 0; i < Methods.Length; ++i) {
4101 MethodBase m = Methods [i];
4102 if (TypeManager.IsOverride (m)) {
4103 if (candidate_overrides == null)
4104 candidate_overrides = new ArrayList ();
4105 candidate_overrides.Add (m);
4106 m = TypeManager.TryGetBaseDefinition (m);
4115 // Enable message recording, it's used mainly by lambda expressions
4117 Report.IMessageRecorder msg_recorder = new Report.MessageRecorder ();
4118 Report.IMessageRecorder prev_recorder = Report.SetMessageRecorder (msg_recorder);
4121 // First we construct the set of applicable methods
4123 bool is_sorted = true;
4124 int best_candidate_rate = int.MaxValue;
4125 for (int i = 0; i < nmethods; i++) {
4126 Type decl_type = Methods [i].DeclaringType;
4129 // If we have already found an applicable method
4130 // we eliminate all base types (Section 14.5.5.1)
4132 if (applicable_type != null && IsAncestralType (decl_type, applicable_type))
4136 // Check if candidate is applicable (section 14.4.2.1)
4138 bool params_expanded_form = false;
4139 int candidate_rate = IsApplicable (ec, Arguments, arg_count, ref Methods [i], ref params_expanded_form);
4141 if (candidate_rate < best_candidate_rate) {
4142 best_candidate_rate = candidate_rate;
4143 best_candidate = Methods [i];
4146 if (params_expanded_form) {
4147 if (candidate_to_form == null)
4148 candidate_to_form = new PtrHashtable ();
4149 MethodBase candidate = Methods [i];
4150 candidate_to_form [candidate] = candidate;
4153 if (candidate_rate != 0) {
4154 if (msg_recorder != null)
4155 msg_recorder.EndSession ();
4159 msg_recorder = null;
4160 candidates.Add (Methods [i]);
4162 if (applicable_type == null)
4163 applicable_type = decl_type;
4164 else if (applicable_type != decl_type) {
4166 if (IsAncestralType (applicable_type, decl_type))
4167 applicable_type = decl_type;
4171 Report.SetMessageRecorder (prev_recorder);
4172 if (msg_recorder != null && msg_recorder.PrintMessages ())
4175 int candidate_top = candidates.Count;
4177 if (applicable_type == null) {
4179 // When we found a top level method which does not match and it's
4180 // not an extension method. We start extension methods lookup from here
4182 if (InstanceExpression != null) {
4183 ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (type, Name, loc);
4184 if (ex_method_lookup != null) {
4185 ex_method_lookup.ExtensionExpression = InstanceExpression;
4186 ex_method_lookup.SetTypeArguments (type_arguments);
4187 return ex_method_lookup.OverloadResolve (ec, ref Arguments, may_fail, loc);
4195 // Okay so we have failed to find exact match so we
4196 // return error info about the closest match
4198 if (best_candidate != null) {
4199 if (CustomErrorHandler != null) {
4200 if (CustomErrorHandler.NoExactMatch (ec, best_candidate))
4204 ParameterData pd = TypeManager.GetParameterData (best_candidate);
4205 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4206 if (arg_count == pd.Count || pd.HasParams) {
4207 if (TypeManager.IsGenericMethodDefinition (best_candidate)) {
4208 if (type_arguments == null) {
4209 Report.Error (411, loc,
4210 "The type arguments for method `{0}' cannot be inferred from " +
4211 "the usage. Try specifying the type arguments explicitly",
4212 TypeManager.CSharpSignature (best_candidate));
4216 Type [] g_args = TypeManager.GetGenericArguments (best_candidate);
4217 if (type_arguments.Count != g_args.Length) {
4218 Report.SymbolRelatedToPreviousError (best_candidate);
4219 Report.Error (305, loc, "Using the generic method `{0}' requires `{1}' type argument(s)",
4220 TypeManager.CSharpSignature (best_candidate),
4221 g_args.Length.ToString ());
4225 if (type_arguments != null && !TypeManager.IsGenericMethod (best_candidate)) {
4226 Namespace.Error_TypeArgumentsCannotBeUsed (best_candidate, loc);
4231 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate, cand_params, may_fail, loc))
4236 if (almost_matched_members.Count != 0) {
4237 Error_MemberLookupFailed (ec.ContainerType, type, type, ".ctor",
4238 null, MemberTypes.Constructor, AllBindingFlags);
4243 // We failed to find any method with correct argument count
4245 if (Name == ConstructorInfo.ConstructorName) {
4246 Report.SymbolRelatedToPreviousError (type);
4247 Report.Error (1729, loc,
4248 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4249 TypeManager.CSharpName (type), arg_count);
4251 Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4252 Name, arg_count.ToString ());
4260 // At this point, applicable_type is _one_ of the most derived types
4261 // in the set of types containing the methods in this MethodGroup.
4262 // Filter the candidates so that they only contain methods from the
4263 // most derived types.
4266 int finalized = 0; // Number of finalized candidates
4269 // Invariant: applicable_type is a most derived type
4271 // We'll try to complete Section 14.5.5.1 for 'applicable_type' by
4272 // eliminating all it's base types. At the same time, we'll also move
4273 // every unrelated type to the end of the array, and pick the next
4274 // 'applicable_type'.
4276 Type next_applicable_type = null;
4277 int j = finalized; // where to put the next finalized candidate
4278 int k = finalized; // where to put the next undiscarded candidate
4279 for (int i = finalized; i < candidate_top; ++i) {
4280 MethodBase candidate = (MethodBase) candidates [i];
4281 Type decl_type = candidate.DeclaringType;
4283 if (decl_type == applicable_type) {
4284 candidates [k++] = candidates [j];
4285 candidates [j++] = candidates [i];
4289 if (IsAncestralType (decl_type, applicable_type))
4292 if (next_applicable_type != null &&
4293 IsAncestralType (decl_type, next_applicable_type))
4296 candidates [k++] = candidates [i];
4298 if (next_applicable_type == null ||
4299 IsAncestralType (next_applicable_type, decl_type))
4300 next_applicable_type = decl_type;
4303 applicable_type = next_applicable_type;
4306 } while (applicable_type != null);
4310 // Now we actually find the best method
4313 best_candidate = (MethodBase) candidates [0];
4314 if (delegate_type == null)
4315 method_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4317 for (int ix = 1; ix < candidate_top; ix++) {
4318 MethodBase candidate = (MethodBase) candidates [ix];
4320 if (candidate == best_candidate)
4323 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4325 if (BetterFunction (ec, Arguments, arg_count,
4326 candidate, cand_params,
4327 best_candidate, method_params)) {
4328 best_candidate = candidate;
4329 method_params = cand_params;
4333 // Now check that there are no ambiguities i.e the selected method
4334 // should be better than all the others
4336 MethodBase ambiguous = null;
4337 for (int ix = 1; ix < candidate_top; ix++) {
4338 MethodBase candidate = (MethodBase) candidates [ix];
4340 if (candidate == best_candidate)
4343 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4344 if (!BetterFunction (ec, Arguments, arg_count,
4345 best_candidate, method_params,
4346 candidate, cand_params))
4349 Report.SymbolRelatedToPreviousError (candidate);
4350 ambiguous = candidate;
4354 if (ambiguous != null) {
4355 Report.SymbolRelatedToPreviousError (best_candidate);
4356 Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4357 TypeManager.CSharpSignature (ambiguous), TypeManager.CSharpSignature (best_candidate));
4362 // If the method is a virtual function, pick an override closer to the LHS type.
4364 if (!IsBase && best_candidate.IsVirtual) {
4365 if (TypeManager.IsOverride (best_candidate))
4366 throw new InternalErrorException (
4367 "Should not happen. An 'override' method took part in overload resolution: " + best_candidate);
4369 if (candidate_overrides != null) {
4370 Type[] gen_args = null;
4371 bool gen_override = false;
4372 if (TypeManager.IsGenericMethod (best_candidate))
4373 gen_args = TypeManager.GetGenericArguments (best_candidate);
4375 foreach (MethodBase candidate in candidate_overrides) {
4376 if (TypeManager.IsGenericMethod (candidate)) {
4377 if (gen_args == null)
4380 if (gen_args.Length != TypeManager.GetGenericArguments (candidate).Length)
4383 if (gen_args != null)
4387 if (IsOverride (candidate, best_candidate)) {
4388 gen_override = true;
4389 best_candidate = candidate;
4393 if (gen_override && gen_args != null) {
4395 best_candidate = ((MethodInfo) best_candidate).MakeGenericMethod (gen_args);
4402 // And now check if the arguments are all
4403 // compatible, perform conversions if
4404 // necessary etc. and return if everything is
4407 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate,
4408 method_params, may_fail, loc))
4411 if (best_candidate == null)
4414 MethodBase the_method = TypeManager.DropGenericMethodArguments (best_candidate);
4416 if (the_method.IsGenericMethodDefinition &&
4417 !ConstraintChecker.CheckConstraints (ec, the_method, best_candidate, loc))
4421 IMethodData data = TypeManager.GetMethod (the_method);
4423 data.SetMemberIsUsed ();
4428 public override void SetTypeArguments (TypeArguments ta)
4430 type_arguments = ta;
4433 public bool VerifyArgumentsCompat (EmitContext ec, ref ArrayList arguments,
4434 int arg_count, MethodBase method,
4435 bool chose_params_expanded,
4436 bool may_fail, Location loc)
4438 ParameterData pd = TypeManager.GetParameterData (method);
4440 int errors = Report.Errors;
4441 Parameter.Modifier p_mod = 0;
4443 int a_idx = 0, a_pos = 0;
4445 ArrayList params_initializers = null;
4447 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4448 a = (Argument) arguments [a_idx];
4449 if (p_mod != Parameter.Modifier.PARAMS) {
4450 p_mod = pd.ParameterModifier (a_idx);
4451 pt = pd.ParameterType (a_idx);
4453 if (p_mod == Parameter.Modifier.ARGLIST) {
4454 if (a.Type != TypeManager.runtime_argument_handle_type)
4459 if (pt.IsPointer && !ec.InUnsafe) {
4466 if (p_mod == Parameter.Modifier.PARAMS) {
4467 if (chose_params_expanded) {
4468 params_initializers = new ArrayList (arg_count - a_idx);
4469 pt = TypeManager.GetElementType (pt);
4471 } else if (p_mod != 0) {
4472 pt = TypeManager.GetElementType (pt);
4477 // Types have to be identical when ref or out modifer is used
4479 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4480 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4483 if (!TypeManager.IsEqual (a.Expr.Type, pt))
4490 if (TypeManager.IsEqual (a.Type, pt)) {
4493 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4499 // Convert params arguments to an array initializer
4501 if (params_initializers != null) {
4502 // we choose to use 'a.Expr' rather than 'conv' so that
4503 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
4504 params_initializers.Add (a.Expr);
4505 arguments.RemoveAt (a_idx--);
4510 // Update the argument with the implicit conversion
4515 // Fill not provided arguments required by params modifier
4517 if (params_initializers == null && pd.HasParams && arg_count < pd.Count && a_idx + 1 == pd.Count) {
4518 if (arguments == null)
4519 arguments = new ArrayList (1);
4521 pt = pd.Types [GetApplicableParametersCount (method, pd) - 1];
4522 pt = TypeManager.GetElementType (pt);
4523 params_initializers = new ArrayList (0);
4526 if (a_idx == arg_count) {
4528 // Append an array argument with all params arguments
4530 if (params_initializers != null) {
4531 arguments.Add (new Argument (
4532 new ArrayCreation (new TypeExpression (pt, loc), "[]",
4533 params_initializers, loc).Resolve (ec)));
4538 if (!may_fail && Report.Errors == errors) {
4539 if (CustomErrorHandler != null)
4540 CustomErrorHandler.NoExactMatch (ec, best_candidate);
4542 Error_InvalidArguments (ec, loc, a_pos, method, a, pd, pt);
4548 public class ConstantExpr : MemberExpr
4552 public ConstantExpr (FieldInfo constant, Location loc)
4554 this.constant = constant;
4558 public override string Name {
4559 get { throw new NotImplementedException (); }
4562 public override bool IsInstance {
4563 get { return !IsStatic; }
4566 public override bool IsStatic {
4567 get { return constant.IsStatic; }
4570 public override Type DeclaringType {
4571 get { return constant.DeclaringType; }
4574 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc, SimpleName original)
4576 constant = TypeManager.GetGenericFieldDefinition (constant);
4578 IConstant ic = TypeManager.GetConstant (constant);
4580 if (constant.IsLiteral) {
4581 ic = new ExternalConstant (constant);
4583 ic = ExternalConstant.CreateDecimal (constant);
4584 // HACK: decimal field was not resolved as constant
4586 return new FieldExpr (constant, loc).ResolveMemberAccess (ec, left, loc, original);
4588 TypeManager.RegisterConstant (constant, ic);
4591 return base.ResolveMemberAccess (ec, left, loc, original);
4594 public override Expression CreateExpressionTree (EmitContext ec)
4596 throw new NotSupportedException ("ET");
4599 public override Expression DoResolve (EmitContext ec)
4601 IConstant ic = TypeManager.GetConstant (constant);
4602 if (ic.ResolveValue ()) {
4603 if (!ec.IsInObsoleteScope)
4604 ic.CheckObsoleteness (loc);
4607 return ic.CreateConstantReference (loc);
4610 public override void Emit (EmitContext ec)
4612 throw new NotSupportedException ();
4615 public override string GetSignatureForError ()
4617 return TypeManager.GetFullNameSignature (constant);
4622 /// Fully resolved expression that evaluates to a Field
4624 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariable {
4625 public readonly FieldInfo FieldInfo;
4626 readonly Type constructed_generic_type;
4627 VariableInfo variable_info;
4629 LocalTemporary temp;
4631 bool in_initializer;
4633 public FieldExpr (FieldInfo fi, Location l, bool in_initializer):
4636 this.in_initializer = in_initializer;
4639 public FieldExpr (FieldInfo fi, Location l)
4642 eclass = ExprClass.Variable;
4643 type = TypeManager.TypeToCoreType (fi.FieldType);
4647 public FieldExpr (FieldInfo fi, Type genericType, Location l)
4650 this.constructed_generic_type = genericType;
4653 public override string Name {
4655 return FieldInfo.Name;
4659 public override bool IsInstance {
4661 return !FieldInfo.IsStatic;
4665 public override bool IsStatic {
4667 return FieldInfo.IsStatic;
4671 public override Type DeclaringType {
4673 return FieldInfo.DeclaringType;
4677 public override string GetSignatureForError ()
4679 return TypeManager.GetFullNameSignature (FieldInfo);
4682 public VariableInfo VariableInfo {
4684 return variable_info;
4688 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
4689 SimpleName original)
4691 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
4692 Type t = fi.FieldType;
4694 if (t.IsPointer && !ec.InUnsafe) {
4698 return base.ResolveMemberAccess (ec, left, loc, original);
4701 public override Expression CreateExpressionTree (EmitContext ec)
4703 Expression instance;
4704 if (InstanceExpression == null) {
4705 instance = new NullLiteral (loc);
4707 instance = InstanceExpression.CreateExpressionTree (ec);
4710 ArrayList args = new ArrayList (2);
4711 args.Add (new Argument (instance));
4712 args.Add (new Argument (CreateTypeOfExpression ()));
4713 return CreateExpressionFactoryCall ("Field", args);
4716 public Expression CreateTypeOfExpression ()
4718 return new TypeOfField (FieldInfo, loc);
4721 override public Expression DoResolve (EmitContext ec)
4723 return DoResolve (ec, false, false);
4726 Expression DoResolve (EmitContext ec, bool lvalue_instance, bool out_access)
4728 if (!FieldInfo.IsStatic){
4729 if (InstanceExpression == null){
4731 // This can happen when referencing an instance field using
4732 // a fully qualified type expression: TypeName.InstanceField = xxx
4734 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4738 // Resolve the field's instance expression while flow analysis is turned
4739 // off: when accessing a field "a.b", we must check whether the field
4740 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4742 if (lvalue_instance) {
4743 using (ec.With (EmitContext.Flags.DoFlowAnalysis, false)) {
4744 Expression right_side =
4745 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4746 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side, loc);
4749 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
4750 InstanceExpression = InstanceExpression.Resolve (ec, rf);
4753 if (InstanceExpression == null)
4756 using (ec.Set (EmitContext.Flags.OmitStructFlowAnalysis)) {
4757 InstanceExpression.CheckMarshalByRefAccess (ec);
4761 if (!in_initializer && !ec.IsInFieldInitializer) {
4762 ObsoleteAttribute oa;
4763 FieldBase f = TypeManager.GetField (FieldInfo);
4765 if (!ec.IsInObsoleteScope)
4766 f.CheckObsoleteness (loc);
4768 // To be sure that type is external because we do not register generated fields
4769 } else if (!(FieldInfo.DeclaringType is TypeBuilder)) {
4770 oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
4772 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
4776 IFixedBuffer fb = AttributeTester.GetFixedBuffer (FieldInfo);
4778 if (!ec.InFixedInitializer && ec.ContainerType.IsValueType) {
4779 Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4782 if (InstanceExpression.eclass != ExprClass.Variable) {
4783 Report.SymbolRelatedToPreviousError (FieldInfo);
4784 Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4785 TypeManager.GetFullNameSignature (FieldInfo));
4788 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4791 // If the instance expression is a local variable or parameter.
4792 IVariable var = InstanceExpression as IVariable;
4793 if (var == null || var.VariableInfo == null)
4796 VariableInfo vi = var.VariableInfo;
4797 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
4800 variable_info = vi.GetSubStruct (FieldInfo.Name);
4804 static readonly int [] codes = {
4805 191, // instance, write access
4806 192, // instance, out access
4807 198, // static, write access
4808 199, // static, out access
4809 1648, // member of value instance, write access
4810 1649, // member of value instance, out access
4811 1650, // member of value static, write access
4812 1651 // member of value static, out access
4815 static readonly string [] msgs = {
4816 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4817 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4818 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4819 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4820 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4821 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4822 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4823 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4826 // The return value is always null. Returning a value simplifies calling code.
4827 Expression Report_AssignToReadonly (Expression right_side)
4830 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4834 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4836 Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4841 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4843 IVariable var = InstanceExpression as IVariable;
4844 if (var != null && var.VariableInfo != null)
4845 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
4847 bool lvalue_instance = !FieldInfo.IsStatic && FieldInfo.DeclaringType.IsValueType;
4848 bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
4850 Expression e = DoResolve (ec, lvalue_instance, out_access);
4855 FieldBase fb = TypeManager.GetField (FieldInfo);
4859 if (FieldInfo.IsInitOnly) {
4860 // InitOnly fields can only be assigned in constructors or initializers
4861 if (!ec.IsInFieldInitializer && !ec.IsConstructor)
4862 return Report_AssignToReadonly (right_side);
4864 if (ec.IsConstructor) {
4865 Type ctype = ec.TypeContainer.CurrentType;
4867 ctype = ec.ContainerType;
4869 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4870 if (!TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
4871 return Report_AssignToReadonly (right_side);
4872 // static InitOnly fields cannot be assigned-to in an instance constructor
4873 if (IsStatic && !ec.IsStatic)
4874 return Report_AssignToReadonly (right_side);
4875 // instance constructors can't modify InitOnly fields of other instances of the same type
4876 if (!IsStatic && !(InstanceExpression is This))
4877 return Report_AssignToReadonly (right_side);
4881 if (right_side == EmptyExpression.OutAccess &&
4882 !IsStatic && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type)) {
4883 Report.SymbolRelatedToPreviousError (DeclaringType);
4884 Report.Warning (197, 1, loc,
4885 "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",
4886 GetSignatureForError ());
4892 bool is_marshal_by_ref ()
4894 return !IsStatic && Type.IsValueType && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type);
4897 public override void CheckMarshalByRefAccess (EmitContext ec)
4899 if (is_marshal_by_ref () && !(InstanceExpression is This)) {
4900 Report.SymbolRelatedToPreviousError (DeclaringType);
4901 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",
4902 GetSignatureForError ());
4906 public override int GetHashCode ()
4908 return FieldInfo.GetHashCode ();
4911 public bool IsFixed {
4913 IVariable variable = InstanceExpression as IVariable;
4914 // A variable of the form V.I is fixed when V is a fixed variable of a struct type.
4915 // We defer the InstanceExpression check after the variable check to avoid a
4916 // separate null check on InstanceExpression.
4917 return variable != null && InstanceExpression.Type.IsValueType && variable.IsFixed;
4921 public override bool Equals (object obj)
4923 FieldExpr fe = obj as FieldExpr;
4927 if (FieldInfo != fe.FieldInfo)
4930 if (InstanceExpression == null || fe.InstanceExpression == null)
4933 return InstanceExpression.Equals (fe.InstanceExpression);
4936 public void Emit (EmitContext ec, bool leave_copy)
4938 ILGenerator ig = ec.ig;
4939 bool is_volatile = false;
4941 FieldBase f = TypeManager.GetField (FieldInfo);
4943 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4946 f.SetMemberIsUsed ();
4949 if (FieldInfo.IsStatic){
4951 ig.Emit (OpCodes.Volatile);
4953 ig.Emit (OpCodes.Ldsfld, GetConstructedFieldInfo ());
4956 EmitInstance (ec, false);
4958 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
4960 ig.Emit (OpCodes.Ldflda, GetConstructedFieldInfo ());
4961 ig.Emit (OpCodes.Ldflda, ff.Element);
4964 ig.Emit (OpCodes.Volatile);
4966 ig.Emit (OpCodes.Ldfld, GetConstructedFieldInfo ());
4971 ec.ig.Emit (OpCodes.Dup);
4972 if (!FieldInfo.IsStatic) {
4973 temp = new LocalTemporary (this.Type);
4979 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4981 FieldAttributes fa = FieldInfo.Attributes;
4982 bool is_static = (fa & FieldAttributes.Static) != 0;
4983 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
4984 ILGenerator ig = ec.ig;
4986 if (is_readonly && !ec.IsConstructor){
4987 Report_AssignToReadonly (source);
4991 prepared = prepare_for_load;
4992 EmitInstance (ec, prepared);
4996 ec.ig.Emit (OpCodes.Dup);
4997 if (!FieldInfo.IsStatic) {
4998 temp = new LocalTemporary (this.Type);
5003 FieldBase f = TypeManager.GetField (FieldInfo);
5005 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
5006 ig.Emit (OpCodes.Volatile);
5012 ig.Emit (OpCodes.Stsfld, GetConstructedFieldInfo ());
5014 ig.Emit (OpCodes.Stfld, GetConstructedFieldInfo ());
5023 public override void Emit (EmitContext ec)
5028 public override void EmitSideEffect (EmitContext ec)
5030 FieldBase f = TypeManager.GetField (FieldInfo);
5031 bool is_volatile = f != null && (f.ModFlags & Modifiers.VOLATILE) != 0;
5033 if (is_volatile || is_marshal_by_ref ())
5034 base.EmitSideEffect (ec);
5037 public void AddressOf (EmitContext ec, AddressOp mode)
5039 ILGenerator ig = ec.ig;
5041 FieldBase f = TypeManager.GetField (FieldInfo);
5043 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
5044 Report.Warning (420, 1, loc, "`{0}': A volatile field references will not be treated as volatile",
5045 f.GetSignatureForError ());
5048 if ((mode & AddressOp.Store) != 0)
5050 if ((mode & AddressOp.Load) != 0)
5051 f.SetMemberIsUsed ();
5055 // Handle initonly fields specially: make a copy and then
5056 // get the address of the copy.
5059 if (FieldInfo.IsInitOnly){
5061 if (ec.IsConstructor){
5062 if (FieldInfo.IsStatic){
5074 local = ig.DeclareLocal (type);
5075 ig.Emit (OpCodes.Stloc, local);
5076 ig.Emit (OpCodes.Ldloca, local);
5081 if (FieldInfo.IsStatic){
5082 ig.Emit (OpCodes.Ldsflda, GetConstructedFieldInfo ());
5085 EmitInstance (ec, false);
5086 ig.Emit (OpCodes.Ldflda, GetConstructedFieldInfo ());
5090 FieldInfo GetConstructedFieldInfo ()
5092 if (constructed_generic_type == null)
5095 return TypeBuilder.GetField (constructed_generic_type, FieldInfo);
5097 throw new NotSupportedException ();
5104 /// Expression that evaluates to a Property. The Assign class
5105 /// might set the `Value' expression if we are in an assignment.
5107 /// This is not an LValue because we need to re-write the expression, we
5108 /// can not take data from the stack and store it.
5110 public class PropertyExpr : MemberExpr, IAssignMethod {
5111 public readonly PropertyInfo PropertyInfo;
5112 MethodInfo getter, setter;
5117 LocalTemporary temp;
5120 public PropertyExpr (Type container_type, PropertyInfo pi, Location l)
5123 eclass = ExprClass.PropertyAccess;
5127 type = TypeManager.TypeToCoreType (pi.PropertyType);
5129 ResolveAccessors (container_type);
5132 public override string Name {
5134 return PropertyInfo.Name;
5138 public override bool IsInstance {
5144 public override bool IsStatic {
5150 public override Expression CreateExpressionTree (EmitContext ec)
5153 if (IsSingleDimensionalArrayLength ()) {
5154 args = new ArrayList (1);
5155 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5156 return CreateExpressionFactoryCall ("ArrayLength", args);
5160 Error_BaseAccessInExpressionTree (loc);
5164 args = new ArrayList (2);
5165 if (InstanceExpression == null)
5166 args.Add (new Argument (new NullLiteral (loc)));
5168 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5169 args.Add (new Argument (new TypeOfMethodInfo (getter, loc)));
5170 return CreateExpressionFactoryCall ("Property", args);
5173 public Expression CreateSetterTypeOfExpression ()
5175 return new TypeOfMethodInfo (setter, loc);
5178 public override Type DeclaringType {
5180 return PropertyInfo.DeclaringType;
5184 public override string GetSignatureForError ()
5186 return TypeManager.GetFullNameSignature (PropertyInfo);
5189 void FindAccessors (Type invocation_type)
5191 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
5192 BindingFlags.Static | BindingFlags.Instance |
5193 BindingFlags.DeclaredOnly;
5195 Type current = PropertyInfo.DeclaringType;
5196 for (; current != null; current = current.BaseType) {
5197 MemberInfo[] group = TypeManager.MemberLookup (
5198 invocation_type, invocation_type, current,
5199 MemberTypes.Property, flags, PropertyInfo.Name, null);
5204 if (group.Length != 1)
5205 // Oooops, can this ever happen ?
5208 PropertyInfo pi = (PropertyInfo) group [0];
5211 getter = pi.GetGetMethod (true);
5214 setter = pi.GetSetMethod (true);
5216 MethodInfo accessor = getter != null ? getter : setter;
5218 if (!accessor.IsVirtual)
5224 // We also perform the permission checking here, as the PropertyInfo does not
5225 // hold the information for the accessibility of its setter/getter
5227 // TODO: Refactor to use some kind of cache together with GetPropertyFromAccessor
5228 void ResolveAccessors (Type container_type)
5230 FindAccessors (container_type);
5232 if (getter != null) {
5233 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
5234 IMethodData md = TypeManager.GetMethod (the_getter);
5236 md.SetMemberIsUsed ();
5238 is_static = getter.IsStatic;
5241 if (setter != null) {
5242 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
5243 IMethodData md = TypeManager.GetMethod (the_setter);
5245 md.SetMemberIsUsed ();
5247 is_static = setter.IsStatic;
5251 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5253 if (InstanceExpression != null)
5254 InstanceExpression.MutateHoistedGenericType (storey);
5256 type = storey.MutateType (type);
5257 getter = storey.MutateGenericMethod (getter);
5260 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
5263 InstanceExpression = null;
5267 if (InstanceExpression == null) {
5268 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5272 InstanceExpression = InstanceExpression.DoResolve (ec);
5273 if (lvalue_instance && InstanceExpression != null)
5274 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
5276 if (InstanceExpression == null)
5279 InstanceExpression.CheckMarshalByRefAccess (ec);
5281 if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) &&
5282 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
5283 !TypeManager.IsNestedChildOf (ec.ContainerType, InstanceExpression.Type) &&
5284 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.ContainerType)) {
5285 Report.SymbolRelatedToPreviousError (PropertyInfo);
5286 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
5293 void Error_PropertyNotFound (MethodInfo mi, bool getter)
5295 // TODO: correctly we should compare arguments but it will lead to bigger changes
5296 if (mi is MethodBuilder) {
5297 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
5301 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
5303 ParameterData iparams = TypeManager.GetParameterData (mi);
5304 sig.Append (getter ? "get_" : "set_");
5306 sig.Append (iparams.GetSignatureForError ());
5308 Report.SymbolRelatedToPreviousError (mi);
5309 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
5310 Name, sig.ToString ());
5313 public bool IsAccessibleFrom (Type invocation_type, bool lvalue)
5316 MethodInfo accessor = lvalue ? setter : getter;
5317 if (accessor == null && lvalue)
5319 return accessor != null && IsAccessorAccessible (invocation_type, accessor, out dummy);
5322 bool IsSingleDimensionalArrayLength ()
5324 if (DeclaringType != TypeManager.array_type || getter == null || Name != "Length")
5327 string t_name = InstanceExpression.Type.Name;
5328 int t_name_len = t_name.Length;
5329 return t_name_len > 2 && t_name [t_name_len - 2] == '[';
5332 override public Expression DoResolve (EmitContext ec)
5337 if (getter != null){
5338 if (TypeManager.GetParameterData (getter).Count != 0){
5339 Error_PropertyNotFound (getter, true);
5344 if (getter == null){
5346 // The following condition happens if the PropertyExpr was
5347 // created, but is invalid (ie, the property is inaccessible),
5348 // and we did not want to embed the knowledge about this in
5349 // the caller routine. This only avoids double error reporting.
5354 if (InstanceExpression != EmptyExpression.Null) {
5355 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5356 TypeManager.GetFullNameSignature (PropertyInfo));
5361 bool must_do_cs1540_check = false;
5362 if (getter != null &&
5363 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
5364 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
5365 if (pm != null && pm.HasCustomAccessModifier) {
5366 Report.SymbolRelatedToPreviousError (pm);
5367 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5368 TypeManager.CSharpSignature (getter));
5371 Report.SymbolRelatedToPreviousError (getter);
5372 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
5377 if (!InstanceResolve (ec, false, must_do_cs1540_check))
5381 // Only base will allow this invocation to happen.
5383 if (IsBase && getter.IsAbstract) {
5384 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5388 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
5398 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
5400 if (right_side == EmptyExpression.OutAccess) {
5401 if (ec.CurrentBlock.Toplevel.GetTransparentIdentifier (PropertyInfo.Name) != null) {
5402 Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5405 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as `ref' or `out' parameter",
5406 GetSignatureForError ());
5411 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5412 Error_CannotModifyIntermediateExpressionValue (ec);
5415 if (setter == null){
5417 // The following condition happens if the PropertyExpr was
5418 // created, but is invalid (ie, the property is inaccessible),
5419 // and we did not want to embed the knowledge about this in
5420 // the caller routine. This only avoids double error reporting.
5424 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
5425 GetSignatureForError ());
5429 if (TypeManager.GetParameterData (setter).Count != 1){
5430 Error_PropertyNotFound (setter, false);
5434 bool must_do_cs1540_check;
5435 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
5436 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
5437 if (pm != null && pm.HasCustomAccessModifier) {
5438 Report.SymbolRelatedToPreviousError (pm);
5439 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5440 TypeManager.CSharpSignature (setter));
5443 Report.SymbolRelatedToPreviousError (setter);
5444 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
5449 if (!InstanceResolve (ec, PropertyInfo.DeclaringType.IsValueType, must_do_cs1540_check))
5453 // Only base will allow this invocation to happen.
5455 if (IsBase && setter.IsAbstract){
5456 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5463 public override void Emit (EmitContext ec)
5468 public void Emit (EmitContext ec, bool leave_copy)
5471 // Special case: length of single dimension array property is turned into ldlen
5473 if (IsSingleDimensionalArrayLength ()) {
5475 EmitInstance (ec, false);
5476 ec.ig.Emit (OpCodes.Ldlen);
5477 ec.ig.Emit (OpCodes.Conv_I4);
5481 Invocation.EmitCall (ec, IsBase, InstanceExpression, getter, null, loc, prepared, false);
5484 ec.ig.Emit (OpCodes.Dup);
5486 temp = new LocalTemporary (this.Type);
5493 // Implements the IAssignMethod interface for assignments
5495 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5497 Expression my_source = source;
5499 if (prepare_for_load) {
5504 ec.ig.Emit (OpCodes.Dup);
5506 temp = new LocalTemporary (this.Type);
5510 } else if (leave_copy) {
5512 temp = new LocalTemporary (this.Type);
5517 ArrayList args = new ArrayList (1);
5518 args.Add (new Argument (my_source, Argument.AType.Expression));
5520 Invocation.EmitCall (ec, IsBase, InstanceExpression, setter, args, loc, false, prepared);
5530 /// Fully resolved expression that evaluates to an Event
5532 public class EventExpr : MemberExpr {
5533 public readonly EventInfo EventInfo;
5536 MethodInfo add_accessor, remove_accessor;
5538 public EventExpr (EventInfo ei, Location loc)
5542 eclass = ExprClass.EventAccess;
5544 add_accessor = TypeManager.GetAddMethod (ei);
5545 remove_accessor = TypeManager.GetRemoveMethod (ei);
5546 if (add_accessor.IsStatic || remove_accessor.IsStatic)
5549 if (EventInfo is MyEventBuilder){
5550 MyEventBuilder eb = (MyEventBuilder) EventInfo;
5551 type = eb.EventType;
5554 type = EventInfo.EventHandlerType;
5557 public override string Name {
5559 return EventInfo.Name;
5563 public override bool IsInstance {
5569 public override bool IsStatic {
5575 public override Type DeclaringType {
5577 return EventInfo.DeclaringType;
5581 void Error_AssignmentEventOnly ()
5583 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5584 GetSignatureForError ());
5587 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
5588 SimpleName original)
5591 // If the event is local to this class, we transform ourselves into a FieldExpr
5594 if (EventInfo.DeclaringType == ec.ContainerType ||
5595 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
5596 EventField mi = TypeManager.GetEventField (EventInfo);
5599 if (!ec.IsInObsoleteScope)
5600 mi.CheckObsoleteness (loc);
5602 if ((mi.ModFlags & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0 && !ec.IsInCompoundAssignment)
5603 Error_AssignmentEventOnly ();
5605 FieldExpr ml = new FieldExpr (mi.FieldBuilder, loc);
5607 InstanceExpression = null;
5609 return ml.ResolveMemberAccess (ec, left, loc, original);
5613 if (left is This && !ec.IsInCompoundAssignment)
5614 Error_AssignmentEventOnly ();
5616 return base.ResolveMemberAccess (ec, left, loc, original);
5619 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
5622 InstanceExpression = null;
5626 if (InstanceExpression == null) {
5627 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5631 InstanceExpression = InstanceExpression.DoResolve (ec);
5632 if (InstanceExpression == null)
5635 if (IsBase && add_accessor.IsAbstract) {
5636 Error_CannotCallAbstractBase(TypeManager.CSharpSignature(add_accessor));
5641 // This is using the same mechanism as the CS1540 check in PropertyExpr.
5642 // However, in the Event case, we reported a CS0122 instead.
5644 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
5645 InstanceExpression.Type != ec.ContainerType &&
5646 TypeManager.IsSubclassOf (ec.ContainerType, InstanceExpression.Type)) {
5647 Report.SymbolRelatedToPreviousError (EventInfo);
5648 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5655 public bool IsAccessibleFrom (Type invocation_type)
5658 return IsAccessorAccessible (invocation_type, add_accessor, out dummy) &&
5659 IsAccessorAccessible (invocation_type, remove_accessor, out dummy);
5662 public override Expression CreateExpressionTree (EmitContext ec)
5664 throw new NotSupportedException ("ET");
5667 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5669 // contexts where an LValue is valid have already devolved to FieldExprs
5670 Error_CannotAssign ();
5674 public override Expression DoResolve (EmitContext ec)
5676 bool must_do_cs1540_check;
5677 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
5678 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
5679 Report.SymbolRelatedToPreviousError (EventInfo);
5680 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5684 if (!InstanceResolve (ec, must_do_cs1540_check))
5687 if (!ec.IsInCompoundAssignment) {
5688 Error_CannotAssign ();
5695 public override void Emit (EmitContext ec)
5697 Error_CannotAssign ();
5700 public void Error_CannotAssign ()
5702 Report.Error (70, loc,
5703 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
5704 GetSignatureForError (), TypeManager.CSharpName (EventInfo.DeclaringType));
5707 public override string GetSignatureForError ()
5709 return TypeManager.CSharpSignature (EventInfo);
5712 public void EmitAddOrRemove (EmitContext ec, bool is_add, Expression source)
5714 ArrayList args = new ArrayList (1);
5715 args.Add (new Argument (source, Argument.AType.Expression));
5716 Invocation.EmitCall (ec, IsBase, InstanceExpression, is_add ? add_accessor : remove_accessor, args, loc);
5720 public class TemporaryVariable : VariableReference
5724 public TemporaryVariable (Type type, Location loc)
5728 eclass = ExprClass.Variable;
5731 public override Expression CreateExpressionTree (EmitContext ec)
5733 throw new NotSupportedException ("ET");
5736 public override Expression DoResolve (EmitContext ec)
5741 TypeExpr te = new TypeExpression (type, loc);
5742 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
5743 if (!li.Resolve (ec))
5746 if (ec.MustCaptureVariable (li) && !ec.IsInProbingMode) {
5747 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
5748 storey.CaptureLocalVariable (ec, li);
5754 public override void Emit (EmitContext ec)
5759 public void EmitAssign (EmitContext ec, Expression source)
5761 EmitAssign (ec, source, false, false);
5764 public override HoistedVariable HoistedVariable {
5765 get { return li.HoistedVariableReference; }
5768 public override bool IsFixed {
5769 get { return true; }
5772 public override bool IsRef {
5773 get { return false; }
5776 public override ILocalVariable Variable {
5780 public override VariableInfo VariableInfo {
5781 get { throw new NotImplementedException (); }
5786 /// Handles `var' contextual keyword; var becomes a keyword only
5787 /// if no type called var exists in a variable scope
5789 public class VarExpr : SimpleName
5791 // Used for error reporting only
5792 ArrayList initializer;
5794 public VarExpr (Location loc)
5799 public ArrayList VariableInitializer {
5801 this.initializer = value;
5805 public bool InferType (EmitContext ec, Expression right_side)
5808 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
5810 type = right_side.Type;
5811 if (type == TypeManager.null_type || type == TypeManager.void_type || type == TypeManager.anonymous_method_type) {
5812 Report.Error (815, loc, "An implicitly typed local variable declaration cannot be initialized with `{0}'",
5813 right_side.GetSignatureForError ());
5817 eclass = ExprClass.Variable;
5821 protected override void Error_TypeOrNamespaceNotFound (IResolveContext ec)
5823 Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");
5826 public override TypeExpr ResolveAsContextualType (IResolveContext rc, bool silent)
5828 TypeExpr te = base.ResolveAsContextualType (rc, true);
5832 if (initializer == null)
5835 if (initializer.Count > 1) {
5836 Location loc = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [1]).Location;
5837 Report.Error (819, loc, "An implicitly typed local variable declaration cannot include multiple declarators");
5842 Expression variable_initializer = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [0]).expression_or_array_initializer;
5843 if (variable_initializer == null) {
5844 Report.Error (818, loc, "An implicitly typed local variable declarator must include an initializer");