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 readonly 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)
1389 public override bool IsNull {
1390 get { return child.IsNull; }
1394 public class EmptyCast : TypeCast {
1395 EmptyCast (Expression child, Type target_type)
1396 : base (child, target_type)
1400 public static Expression Create (Expression child, Type type)
1402 Constant c = child as Constant;
1404 return new EmptyConstantCast (c, type);
1406 EmptyCast e = child as EmptyCast;
1408 return new EmptyCast (e.child, type);
1410 return new EmptyCast (child, type);
1413 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1415 child.EmitBranchable (ec, label, on_true);
1418 public override void EmitSideEffect (EmitContext ec)
1420 child.EmitSideEffect (ec);
1425 /// Performs a cast using an operator (op_Explicit or op_Implicit)
1427 public class OperatorCast : TypeCast {
1428 MethodInfo conversion_operator;
1431 public OperatorCast (Expression child, Type target_type) : this (child, target_type, false) {}
1433 public OperatorCast (Expression child, Type target_type, bool find_explicit)
1434 : base (child, target_type)
1436 this.find_explicit = find_explicit;
1439 // Returns the implicit operator that converts from
1440 // 'child.Type' to our target type (type)
1441 MethodInfo GetConversionOperator (bool find_explicit)
1443 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1447 mi = TypeManager.MemberLookup (child.Type, child.Type, child.Type, MemberTypes.Method,
1448 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1451 mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1452 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1455 foreach (MethodInfo oper in mi) {
1456 ParameterData pd = TypeManager.GetParameterData (oper);
1458 if (pd.ParameterType (0) == child.Type && TypeManager.TypeToCoreType (oper.ReturnType) == type)
1466 public override void Emit (EmitContext ec)
1468 ILGenerator ig = ec.ig;
1471 conversion_operator = GetConversionOperator (find_explicit);
1473 if (conversion_operator == null)
1474 throw new InternalErrorException ("Outer conversion routine is out of sync");
1476 ig.Emit (OpCodes.Call, conversion_operator);
1482 /// This is a numeric cast to a Decimal
1484 public class CastToDecimal : TypeCast {
1485 MethodInfo conversion_operator;
1487 public CastToDecimal (Expression child)
1488 : this (child, false)
1492 public CastToDecimal (Expression child, bool find_explicit)
1493 : base (child, TypeManager.decimal_type)
1495 conversion_operator = GetConversionOperator (find_explicit);
1497 if (conversion_operator == null)
1498 throw new InternalErrorException ("Outer conversion routine is out of sync");
1501 // Returns the implicit operator that converts from
1502 // 'child.Type' to System.Decimal.
1503 MethodInfo GetConversionOperator (bool find_explicit)
1505 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1507 MemberInfo [] mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1508 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1510 foreach (MethodInfo oper in mi) {
1511 ParameterData pd = TypeManager.GetParameterData (oper);
1513 if (pd.ParameterType (0) == child.Type && TypeManager.TypeToCoreType (oper.ReturnType) == type)
1519 public override void Emit (EmitContext ec)
1521 ILGenerator ig = ec.ig;
1524 ig.Emit (OpCodes.Call, conversion_operator);
1529 /// This is an explicit numeric cast from a Decimal
1531 public class CastFromDecimal : TypeCast
1533 static IDictionary operators;
1535 public CastFromDecimal (Expression child, Type return_type)
1536 : base (child, return_type)
1538 if (child.Type != TypeManager.decimal_type)
1539 throw new InternalErrorException (
1540 "The expected type is Decimal, instead it is " + child.Type.FullName);
1543 // Returns the explicit operator that converts from an
1544 // express of type System.Decimal to 'type'.
1545 public Expression Resolve ()
1547 if (operators == null) {
1548 MemberInfo[] all_oper = TypeManager.MemberLookup (TypeManager.decimal_type,
1549 TypeManager.decimal_type, TypeManager.decimal_type, MemberTypes.Method,
1550 BindingFlags.Static | BindingFlags.Public, "op_Explicit", null);
1552 operators = new System.Collections.Specialized.HybridDictionary ();
1553 foreach (MethodInfo oper in all_oper) {
1554 ParameterData pd = TypeManager.GetParameterData (oper);
1555 if (pd.ParameterType (0) == TypeManager.decimal_type)
1556 operators.Add (TypeManager.TypeToCoreType (oper.ReturnType), oper);
1560 return operators.Contains (type) ? this : null;
1563 public override void Emit (EmitContext ec)
1565 ILGenerator ig = ec.ig;
1568 ig.Emit (OpCodes.Call, (MethodInfo)operators [type]);
1574 // Constant specialization of EmptyCast.
1575 // We need to special case this since an empty cast of
1576 // a constant is still a constant.
1578 public class EmptyConstantCast : Constant
1580 public readonly Constant child;
1582 public EmptyConstantCast(Constant child, Type type)
1583 : base (child.Location)
1585 eclass = child.eclass;
1590 public override string AsString ()
1592 return child.AsString ();
1595 public override object GetValue ()
1597 return child.GetValue ();
1600 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
1602 // FIXME: check that 'type' can be converted to 'target_type' first
1603 return child.ConvertExplicitly (in_checked_context, target_type);
1606 public override Expression CreateExpressionTree (EmitContext ec)
1608 ArrayList args = new ArrayList (2);
1609 args.Add (new Argument (child.CreateExpressionTree (ec)));
1610 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1612 Error_PointerInsideExpressionTree ();
1614 return CreateExpressionFactoryCall ("Convert", args);
1617 public override Constant Increment ()
1619 return child.Increment ();
1622 public override bool IsDefaultValue {
1623 get { return child.IsDefaultValue; }
1626 public override bool IsNegative {
1627 get { return child.IsNegative; }
1630 public override bool IsNull {
1631 get { return child.IsNull; }
1634 public override bool IsZeroInteger {
1635 get { return child.IsZeroInteger; }
1638 public override void Emit (EmitContext ec)
1643 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1645 child.EmitBranchable (ec, label, on_true);
1648 public override void EmitSideEffect (EmitContext ec)
1650 child.EmitSideEffect (ec);
1653 public override Constant ConvertImplicitly (Type target_type)
1655 // FIXME: Do we need to check user conversions?
1656 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1658 return child.ConvertImplicitly (target_type);
1664 /// This class is used to wrap literals which belong inside Enums
1666 public class EnumConstant : Constant {
1667 public Constant Child;
1669 public EnumConstant (Constant child, Type enum_type):
1670 base (child.Location)
1672 eclass = child.eclass;
1677 public override Expression DoResolve (EmitContext ec)
1679 // This should never be invoked, we are born in fully
1680 // initialized state.
1685 public override void Emit (EmitContext ec)
1690 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1692 Child.EmitBranchable (ec, label, on_true);
1695 public override void EmitSideEffect (EmitContext ec)
1697 Child.EmitSideEffect (ec);
1700 public override bool GetAttributableValue (Type value_type, out object value)
1702 value = GetTypedValue ();
1706 public override string GetSignatureForError()
1708 return TypeManager.CSharpName (Type);
1711 public override object GetValue ()
1713 return Child.GetValue ();
1716 public override object GetTypedValue ()
1718 // FIXME: runtime is not ready to work with just emited enums
1719 if (!RootContext.StdLib) {
1720 return Child.GetValue ();
1723 return System.Enum.ToObject (type, Child.GetValue ());
1726 public override string AsString ()
1728 return TypeManager.CSharpEnumValue (type, Child.GetValue ());
1731 public override Constant Increment()
1733 return new EnumConstant (Child.Increment (), type);
1736 public override bool IsDefaultValue {
1738 return Child.IsDefaultValue;
1742 public override bool IsZeroInteger {
1743 get { return Child.IsZeroInteger; }
1746 public override bool IsNegative {
1748 return Child.IsNegative;
1752 public override Constant ConvertExplicitly(bool in_checked_context, Type target_type)
1754 if (Child.Type == target_type)
1757 return Child.ConvertExplicitly (in_checked_context, target_type);
1760 public override Constant ConvertImplicitly (Type type)
1762 Type this_type = TypeManager.DropGenericTypeArguments (Type);
1763 type = TypeManager.DropGenericTypeArguments (type);
1765 if (this_type == type) {
1766 // This is workaround of mono bug. It can be removed when the latest corlib spreads enough
1767 if (TypeManager.IsEnumType (type.UnderlyingSystemType))
1770 Type child_type = TypeManager.DropGenericTypeArguments (Child.Type);
1771 if (type.UnderlyingSystemType != child_type)
1772 Child = Child.ConvertImplicitly (type.UnderlyingSystemType);
1776 if (!Convert.ImplicitStandardConversionExists (this, type)){
1780 return Child.ConvertImplicitly(type);
1786 /// This kind of cast is used to encapsulate Value Types in objects.
1788 /// The effect of it is to box the value type emitted by the previous
1791 public class BoxedCast : TypeCast {
1793 public BoxedCast (Expression expr, Type target_type)
1794 : base (expr, target_type)
1796 eclass = ExprClass.Value;
1799 public override Expression DoResolve (EmitContext ec)
1801 // This should never be invoked, we are born in fully
1802 // initialized state.
1807 public override void Emit (EmitContext ec)
1811 ec.ig.Emit (OpCodes.Box, child.Type);
1814 public override void EmitSideEffect (EmitContext ec)
1816 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1817 // so, we need to emit the box+pop instructions in most cases
1818 if (child.Type.IsValueType &&
1819 (type == TypeManager.object_type || type == TypeManager.value_type))
1820 child.EmitSideEffect (ec);
1822 base.EmitSideEffect (ec);
1826 public class UnboxCast : TypeCast {
1827 public UnboxCast (Expression expr, Type return_type)
1828 : base (expr, return_type)
1832 public override Expression DoResolve (EmitContext ec)
1834 // This should never be invoked, we are born in fully
1835 // initialized state.
1840 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1842 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
1843 Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
1844 return base.DoResolveLValue (ec, right_side);
1847 public override void Emit (EmitContext ec)
1850 ILGenerator ig = ec.ig;
1854 if (t.IsGenericParameter || t.IsGenericType && t.IsValueType)
1855 ig.Emit (OpCodes.Unbox_Any, t);
1859 ig.Emit (OpCodes.Unbox, t);
1861 LoadFromPtr (ig, t);
1865 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1867 type = storey.MutateType (type);
1872 /// This is used to perform explicit numeric conversions.
1874 /// Explicit numeric conversions might trigger exceptions in a checked
1875 /// context, so they should generate the conv.ovf opcodes instead of
1878 public class ConvCast : TypeCast {
1879 public enum Mode : byte {
1880 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1882 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1883 U2_I1, U2_U1, U2_I2, U2_CH,
1884 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1885 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1886 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH,
1887 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH,
1888 CH_I1, CH_U1, CH_I2,
1889 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1890 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4
1895 public ConvCast (Expression child, Type return_type, Mode m)
1896 : base (child, return_type)
1901 public override Expression DoResolve (EmitContext ec)
1903 // This should never be invoked, we are born in fully
1904 // initialized state.
1909 public override string ToString ()
1911 return String.Format ("ConvCast ({0}, {1})", mode, child);
1914 public override void Emit (EmitContext ec)
1916 ILGenerator ig = ec.ig;
1922 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1923 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1924 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1925 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1926 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1928 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1929 case Mode.U1_CH: /* nothing */ break;
1931 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1932 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1933 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1934 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1935 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1936 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1938 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1939 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1940 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1941 case Mode.U2_CH: /* nothing */ break;
1943 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1944 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1945 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1946 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1947 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1948 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1949 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1951 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1952 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1953 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1954 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1955 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1956 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1958 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1959 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1960 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1961 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1962 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1963 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1964 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1965 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1967 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1968 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1969 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1970 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1971 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1972 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1973 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1974 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1976 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1977 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1978 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1980 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1981 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1982 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1983 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1984 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1985 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1986 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1987 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1988 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1990 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1991 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1992 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1993 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1994 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1995 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1996 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1997 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1998 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1999 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
2003 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
2004 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
2005 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
2006 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
2007 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
2009 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
2010 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
2012 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
2013 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
2014 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
2015 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
2016 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
2017 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
2019 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
2020 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
2021 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
2022 case Mode.U2_CH: /* nothing */ break;
2024 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
2025 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
2026 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
2027 case Mode.I4_U4: /* nothing */ break;
2028 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
2029 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
2030 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
2032 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
2033 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
2034 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
2035 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
2036 case Mode.U4_I4: /* nothing */ break;
2037 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
2039 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
2040 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
2041 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
2042 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
2043 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
2044 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
2045 case Mode.I8_U8: /* nothing */ break;
2046 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
2048 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
2049 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
2050 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
2051 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
2052 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
2053 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
2054 case Mode.U8_I8: /* nothing */ break;
2055 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
2057 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
2058 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
2059 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
2061 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
2062 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
2063 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
2064 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
2065 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
2066 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
2067 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
2068 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
2069 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
2071 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
2072 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
2073 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
2074 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
2075 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
2076 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
2077 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
2078 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
2079 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
2080 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
2086 public class OpcodeCast : TypeCast {
2090 public OpcodeCast (Expression child, Type return_type, OpCode op)
2091 : base (child, return_type)
2095 second_valid = false;
2098 public OpcodeCast (Expression child, Type return_type, OpCode op, OpCode op2)
2099 : base (child, return_type)
2104 second_valid = true;
2107 public override Expression DoResolve (EmitContext ec)
2109 // This should never be invoked, we are born in fully
2110 // initialized state.
2115 public override void Emit (EmitContext ec)
2124 public Type UnderlyingType {
2125 get { return child.Type; }
2130 /// This kind of cast is used to encapsulate a child and cast it
2131 /// to the class requested
2133 public sealed class ClassCast : TypeCast {
2134 Type child_generic_parameter;
2136 public ClassCast (Expression child, Type return_type)
2137 : base (child, return_type)
2140 if (TypeManager.IsGenericParameter (child.Type))
2141 child_generic_parameter = child.Type;
2144 public override Expression DoResolve (EmitContext ec)
2146 // This should never be invoked, we are born in fully
2147 // initialized state.
2152 public override void Emit (EmitContext ec)
2156 if (child_generic_parameter != null)
2157 ec.ig.Emit (OpCodes.Box, child_generic_parameter);
2160 if (type.IsGenericParameter)
2161 ec.ig.Emit (OpCodes.Unbox_Any, type);
2164 ec.ig.Emit (OpCodes.Castclass, type);
2167 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2169 type = storey.MutateType (type);
2170 if (child_generic_parameter != null)
2171 child_generic_parameter = storey.MutateGenericArgument (child_generic_parameter);
2173 base.MutateHoistedGenericType (storey);
2178 // Used when resolved expression has different representations for
2179 // expression trees and emit phase
2181 public class ReducedExpression : Expression
2183 class ReducedConstantExpression : Constant
2185 readonly Constant expr;
2186 readonly Expression orig_expr;
2188 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2189 : base (expr.Location)
2192 this.orig_expr = orig_expr;
2193 eclass = expr.eclass;
2197 public override string AsString ()
2199 return expr.AsString ();
2202 public override Expression CreateExpressionTree (EmitContext ec)
2204 return orig_expr.CreateExpressionTree (ec);
2207 public override object GetValue ()
2209 return expr.GetValue ();
2212 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
2214 throw new NotImplementedException ();
2217 public override Expression DoResolve (EmitContext ec)
2222 public override Constant Increment ()
2224 throw new NotImplementedException ();
2227 public override bool IsDefaultValue {
2229 return expr.IsDefaultValue;
2233 public override bool IsNegative {
2235 return expr.IsNegative;
2239 public override void Emit (EmitContext ec)
2245 readonly Expression expr, orig_expr;
2247 private ReducedExpression (Expression expr, Expression orig_expr)
2250 this.orig_expr = orig_expr;
2251 this.loc = orig_expr.Location;
2254 public static Expression Create (Constant expr, Expression original_expr)
2256 return new ReducedConstantExpression (expr, original_expr);
2259 public static Expression Create (Expression expr, Expression original_expr)
2261 Constant c = expr as Constant;
2263 return Create (c, original_expr);
2265 return new ReducedExpression (expr, original_expr);
2268 public override Expression CreateExpressionTree (EmitContext ec)
2270 return orig_expr.CreateExpressionTree (ec);
2273 public override Expression DoResolve (EmitContext ec)
2275 eclass = expr.eclass;
2280 public override void Emit (EmitContext ec)
2285 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2287 expr.EmitBranchable (ec, target, on_true);
2292 // Unresolved type name expressions
2294 public abstract class ATypeNameExpression : FullNamedExpression
2296 public readonly string Name;
2297 protected TypeArguments targs;
2299 protected ATypeNameExpression (string name, Location l)
2305 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2312 public bool HasTypeArguments {
2314 return targs != null;
2318 public override string GetSignatureForError ()
2320 if (targs != null) {
2321 return TypeManager.RemoveGenericArity (Name) + "<" +
2322 targs.GetSignatureForError () + ">";
2330 /// SimpleName expressions are formed of a single word and only happen at the beginning
2331 /// of a dotted-name.
2333 public class SimpleName : ATypeNameExpression {
2336 public SimpleName (string name, Location l)
2341 public SimpleName (string name, TypeArguments args, Location l)
2342 : base (name, args, l)
2346 public SimpleName (string name, TypeParameter[] type_params, Location l)
2349 targs = new TypeArguments (l);
2350 foreach (TypeParameter type_param in type_params)
2351 targs.Add (new TypeParameterExpr (type_param, l));
2354 public static string RemoveGenericArity (string name)
2357 StringBuilder sb = null;
2359 int pos = name.IndexOf ('`', start);
2364 sb.Append (name.Substring (start));
2369 sb = new StringBuilder ();
2370 sb.Append (name.Substring (start, pos-start));
2373 while ((pos < name.Length) && Char.IsNumber (name [pos]))
2377 } while (start < name.Length);
2379 return sb.ToString ();
2382 public SimpleName GetMethodGroup ()
2384 return new SimpleName (RemoveGenericArity (Name), targs, loc);
2387 public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
2389 if (ec.IsInFieldInitializer)
2390 Report.Error (236, l,
2391 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2395 120, l, "`{0}': An object reference is required for the nonstatic field, method or property",
2399 public bool IdenticalNameAndTypeName (EmitContext ec, Expression resolved_to, Location loc)
2401 return resolved_to != null && resolved_to.Type != null &&
2402 resolved_to.Type.Name == Name &&
2403 (ec.DeclContainer.LookupNamespaceOrType (Name, loc, /* ignore_cs0104 = */ true) != null);
2406 public override Expression DoResolve (EmitContext ec)
2408 return SimpleNameResolve (ec, null, false);
2411 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
2413 return SimpleNameResolve (ec, right_side, false);
2417 public Expression DoResolve (EmitContext ec, bool intermediate)
2419 return SimpleNameResolve (ec, null, intermediate);
2422 static bool IsNestedChild (Type t, Type parent)
2424 while (parent != null) {
2425 if (TypeManager.IsNestedChildOf (t, TypeManager.DropGenericTypeArguments (parent)))
2428 parent = parent.BaseType;
2434 FullNamedExpression ResolveNested (IResolveContext ec, Type t)
2436 if (!TypeManager.IsGenericTypeDefinition (t) && !TypeManager.IsGenericType (t))
2439 DeclSpace ds = ec.DeclContainer;
2440 while (ds != null && !IsNestedChild (t, ds.TypeBuilder))
2446 Type[] gen_params = TypeManager.GetTypeArguments (t);
2448 int arg_count = targs != null ? targs.Count : 0;
2450 for (; (ds != null) && ds.IsGeneric; ds = ds.Parent) {
2451 if (arg_count + ds.CountTypeParameters == gen_params.Length) {
2452 TypeArguments new_args = new TypeArguments (loc);
2453 foreach (TypeParameter param in ds.TypeParameters)
2454 new_args.Add (new TypeParameterExpr (param, loc));
2457 new_args.Add (targs);
2459 return new ConstructedType (t, new_args, loc);
2466 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2468 FullNamedExpression fne = ec.GenericDeclContainer.LookupGeneric (Name, loc);
2470 return fne.ResolveAsTypeStep (ec, silent);
2472 int errors = Report.Errors;
2473 fne = ec.DeclContainer.LookupNamespaceOrType (Name, loc, /*ignore_cs0104=*/ false);
2476 if (fne.Type == null)
2479 FullNamedExpression nested = ResolveNested (ec, fne.Type);
2481 return nested.ResolveAsTypeStep (ec, false);
2483 if (targs != null) {
2484 ConstructedType ct = new ConstructedType (fne, targs, loc);
2485 return ct.ResolveAsTypeStep (ec, false);
2491 if (silent || errors != Report.Errors)
2494 Error_TypeOrNamespaceNotFound (ec);
2498 protected virtual void Error_TypeOrNamespaceNotFound (IResolveContext ec)
2500 MemberCore mc = ec.DeclContainer.GetDefinition (Name);
2502 Error_UnexpectedKind (ec.DeclContainer, "type", GetMemberType (mc), loc);
2506 string ns = ec.DeclContainer.NamespaceEntry.NS.Name;
2507 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2508 foreach (Assembly a in RootNamespace.Global.Assemblies) {
2509 Type type = a.GetType (fullname);
2511 Report.SymbolRelatedToPreviousError (type);
2512 Expression.ErrorIsInaccesible (loc, TypeManager.CSharpName (type));
2517 Type t = ec.DeclContainer.LookupAnyGeneric (Name);
2519 Namespace.Error_InvalidNumberOfTypeArguments (t, loc);
2523 if (targs != null) {
2524 FullNamedExpression retval = ec.DeclContainer.LookupNamespaceOrType (SimpleName.RemoveGenericArity (Name), loc, true);
2525 if (retval != null) {
2526 Namespace.Error_TypeArgumentsCannotBeUsed (retval.Type, loc);
2531 NamespaceEntry.Error_NamespaceNotFound (loc, Name);
2534 // TODO: I am still not convinced about this. If someone else will need it
2535 // implement this as virtual property in MemberCore hierarchy
2536 public static string GetMemberType (MemberCore mc)
2542 if (mc is FieldBase)
2544 if (mc is MethodCore)
2546 if (mc is EnumMember)
2554 Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2560 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2566 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2573 /// 7.5.2: Simple Names.
2575 /// Local Variables and Parameters are handled at
2576 /// parse time, so they never occur as SimpleNames.
2578 /// The `intermediate' flag is used by MemberAccess only
2579 /// and it is used to inform us that it is ok for us to
2580 /// avoid the static check, because MemberAccess might end
2581 /// up resolving the Name as a Type name and the access as
2582 /// a static type access.
2584 /// ie: Type Type; .... { Type.GetType (""); }
2586 /// Type is both an instance variable and a Type; Type.GetType
2587 /// is the static method not an instance method of type.
2589 Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2591 Expression e = null;
2594 // Stage 1: Performed by the parser (binding to locals or parameters).
2596 Block current_block = ec.CurrentBlock;
2597 if (current_block != null){
2598 LocalInfo vi = current_block.GetLocalInfo (Name);
2600 if (targs != null) {
2601 Report.Error (307, loc,
2602 "The variable `{0}' cannot be used with type arguments",
2607 LocalVariableReference var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2608 if (right_side != null) {
2609 return var.ResolveLValue (ec, right_side, loc);
2611 ResolveFlags rf = ResolveFlags.VariableOrValue;
2613 rf |= ResolveFlags.DisableFlowAnalysis;
2614 return var.Resolve (ec, rf);
2618 ParameterReference pref = current_block.Toplevel.GetParameterReference (Name, loc);
2620 if (targs != null) {
2621 Report.Error (307, loc,
2622 "The variable `{0}' cannot be used with type arguments",
2627 if (right_side != null)
2628 return pref.ResolveLValue (ec, right_side, loc);
2630 return pref.Resolve (ec);
2633 Expression expr = current_block.Toplevel.GetTransparentIdentifier (Name);
2635 if (right_side != null)
2636 return expr.ResolveLValue (ec, right_side, loc);
2637 return expr.Resolve (ec);
2642 // Stage 2: Lookup members
2645 Type almost_matched_type = null;
2646 ArrayList almost_matched = null;
2647 for (DeclSpace lookup_ds = ec.DeclContainer; lookup_ds != null; lookup_ds = lookup_ds.Parent) {
2648 // either RootDeclSpace or GenericMethod
2649 if (lookup_ds.TypeBuilder == null)
2652 e = MemberLookup (ec.ContainerType, lookup_ds.TypeBuilder, Name, loc);
2654 if (e is PropertyExpr) {
2655 // since TypeManager.MemberLookup doesn't know if we're doing a lvalue access or not,
2656 // it doesn't know which accessor to check permissions against
2657 if (((PropertyExpr) e).IsAccessibleFrom (ec.ContainerType, right_side != null))
2659 } else if (e is EventExpr) {
2660 if (((EventExpr) e).IsAccessibleFrom (ec.ContainerType))
2668 if (almost_matched == null && almost_matched_members.Count > 0) {
2669 almost_matched_type = lookup_ds.TypeBuilder;
2670 almost_matched = (ArrayList) almost_matched_members.Clone ();
2675 if (almost_matched == null && almost_matched_members.Count > 0) {
2676 almost_matched_type = ec.ContainerType;
2677 almost_matched = (ArrayList) almost_matched_members.Clone ();
2679 e = ResolveAsTypeStep (ec, true);
2683 if (current_block != null) {
2684 IKnownVariable ikv = current_block.Explicit.GetKnownVariable (Name);
2686 LocalInfo li = ikv as LocalInfo;
2687 // Supress CS0219 warning
2691 Error_VariableIsUsedBeforeItIsDeclared (Name);
2696 if (almost_matched != null)
2697 almost_matched_members = almost_matched;
2698 if (almost_matched_type == null)
2699 almost_matched_type = ec.ContainerType;
2700 Error_MemberLookupFailed (ec.ContainerType, null, almost_matched_type, Name,
2701 ec.DeclContainer.Name, AllMemberTypes, AllBindingFlags);
2705 if (e is TypeExpr) {
2709 ConstructedType ct = new ConstructedType (
2710 e.Type, targs, loc);
2711 return ct.ResolveAsTypeStep (ec, false);
2714 if (e is MemberExpr) {
2715 MemberExpr me = (MemberExpr) e;
2718 if (me.IsInstance) {
2719 if (ec.IsStatic || ec.IsInFieldInitializer) {
2721 // Note that an MemberExpr can be both IsInstance and IsStatic.
2722 // An unresolved MethodGroupExpr can contain both kinds of methods
2723 // and each predicate is true if the MethodGroupExpr contains
2724 // at least one of that kind of method.
2728 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2729 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2734 // Pass the buck to MemberAccess and Invocation.
2736 left = EmptyExpression.Null;
2738 left = ec.GetThis (loc);
2741 left = new TypeExpression (ec.ContainerType, loc);
2744 me = me.ResolveMemberAccess (ec, left, loc, null);
2748 if (targs != null) {
2750 me.SetTypeArguments (targs);
2753 if (!me.IsStatic && (me.InstanceExpression != null) &&
2754 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2755 me.InstanceExpression.Type != me.DeclaringType &&
2756 !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2757 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2758 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2759 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2763 return (right_side != null)
2764 ? me.DoResolveLValue (ec, right_side)
2765 : me.DoResolve (ec);
2771 protected override void CloneTo (CloneContext clonectx, Expression target)
2773 // CloneTo: Nothing, we do not keep any state on this expression
2778 /// Represents a namespace or a type. The name of the class was inspired by
2779 /// section 10.8.1 (Fully Qualified Names).
2781 public abstract class FullNamedExpression : Expression {
2783 public override Expression CreateExpressionTree (EmitContext ec)
2785 throw new NotSupportedException ("ET");
2788 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2793 public override void Emit (EmitContext ec)
2795 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2796 GetSignatureForError ());
2801 /// Expression that evaluates to a type
2803 public abstract class TypeExpr : FullNamedExpression {
2804 override public FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2806 TypeExpr t = DoResolveAsTypeStep (ec);
2810 eclass = ExprClass.Type;
2814 override public Expression DoResolve (EmitContext ec)
2816 return ResolveAsTypeTerminal (ec, false);
2819 public virtual bool CheckAccessLevel (DeclSpace ds)
2821 return ds.CheckAccessLevel (Type);
2824 public virtual bool AsAccessible (DeclSpace ds)
2826 return ds.IsAccessibleAs (Type);
2829 public virtual bool IsClass {
2830 get { return Type.IsClass; }
2833 public virtual bool IsValueType {
2834 get { return Type.IsValueType; }
2837 public virtual bool IsInterface {
2838 get { return Type.IsInterface; }
2841 public virtual bool IsSealed {
2842 get { return Type.IsSealed; }
2845 public virtual bool CanInheritFrom ()
2847 if (Type == TypeManager.enum_type ||
2848 (Type == TypeManager.value_type && RootContext.StdLib) ||
2849 Type == TypeManager.multicast_delegate_type ||
2850 Type == TypeManager.delegate_type ||
2851 Type == TypeManager.array_type)
2857 protected abstract TypeExpr DoResolveAsTypeStep (IResolveContext ec);
2859 public override bool Equals (object obj)
2861 TypeExpr tobj = obj as TypeExpr;
2865 return Type == tobj.Type;
2868 public override int GetHashCode ()
2870 return Type.GetHashCode ();
2873 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2875 type = storey.MutateType (type);
2880 /// Fully resolved Expression that already evaluated to a type
2882 public class TypeExpression : TypeExpr {
2883 public TypeExpression (Type t, Location l)
2886 eclass = ExprClass.Type;
2890 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2895 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2902 /// Used to create types from a fully qualified name. These are just used
2903 /// by the parser to setup the core types. A TypeLookupExpression is always
2904 /// classified as a type.
2906 public sealed class TypeLookupExpression : TypeExpr {
2907 readonly string name;
2909 public TypeLookupExpression (string name)
2912 eclass = ExprClass.Type;
2915 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2917 // It's null for corlib compilation only
2919 return DoResolveAsTypeStep (ec);
2924 private class UnexpectedType
2928 // This performes recursive type lookup, providing support for generic types.
2929 // For example, given the type:
2931 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]]
2933 // The types will be checked in the following order:
2936 // System.Collections |
2937 // System.Collections.Generic |
2939 // System | recursive call 1 |
2940 // System.Int32 _| | main method call
2942 // System | recursive call 2 |
2943 // System.String _| |
2945 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]] _|
2947 private Type TypeLookup (IResolveContext ec, string name)
2952 FullNamedExpression resolved = null;
2954 Type recursive_type = null;
2955 while (index < name.Length) {
2956 if (name[index] == '[') {
2961 if (name[index] == '[')
2963 else if (name[index] == ']')
2965 } while (braces > 0);
2966 recursive_type = TypeLookup (ec, name.Substring (open + 1, index - open - 1));
2967 if (recursive_type == null || (recursive_type == typeof(UnexpectedType)))
2968 return recursive_type;
2971 if (name[index] == ',')
2973 else if ((name[index] == '.' && !done) || (index == name.Length && name[0] != '[')) {
2974 string substring = name.Substring(dot, index - dot);
2976 if (resolved == null)
2977 resolved = RootNamespace.Global.Lookup (ec.DeclContainer, substring, Location.Null);
2978 else if (resolved is Namespace)
2979 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
2980 else if (type != null)
2981 type = TypeManager.GetNestedType (type, substring);
2985 if (resolved == null)
2987 else if (type == null && resolved is TypeExpr)
2988 type = resolved.Type;
2995 if (name[0] != '[') {
2996 string substring = name.Substring(dot, index - dot);
2999 return TypeManager.GetNestedType (type, substring);
3001 if (resolved != null) {
3002 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
3003 if (resolved is TypeExpr)
3004 return resolved.Type;
3006 if (resolved == null)
3009 resolved.Error_UnexpectedKind (ec.DeclContainer, "type", loc);
3010 return typeof (UnexpectedType);
3016 return recursive_type;
3019 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
3021 Type t = TypeLookup (ec, name);
3023 NamespaceEntry.Error_NamespaceNotFound (loc, name);
3026 if (t == typeof(UnexpectedType))
3032 protected override void CloneTo (CloneContext clonectx, Expression target)
3034 // CloneTo: Nothing, we do not keep any state on this expression
3037 public override string GetSignatureForError ()
3040 return TypeManager.CSharpName (name);
3042 return base.GetSignatureForError ();
3047 /// Represents an "unbound generic type", ie. typeof (Foo<>).
3050 public class UnboundTypeExpression : TypeExpr
3054 public UnboundTypeExpression (MemberName name, Location l)
3060 protected override void CloneTo (CloneContext clonectx, Expression target)
3065 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
3068 if (name.Left != null) {
3069 Expression lexpr = name.Left.GetTypeExpression ();
3070 expr = new MemberAccess (lexpr, name.Basename);
3072 expr = new SimpleName (name.Basename, loc);
3075 FullNamedExpression fne = expr.ResolveAsTypeStep (ec, false);
3080 return new TypeExpression (type, loc);
3085 /// This class denotes an expression which evaluates to a member
3086 /// of a struct or a class.
3088 public abstract class MemberExpr : Expression
3090 protected bool is_base;
3093 /// The name of this member.
3095 public abstract string Name {
3100 // When base.member is used
3102 public bool IsBase {
3103 get { return is_base; }
3104 set { is_base = value; }
3108 /// Whether this is an instance member.
3110 public abstract bool IsInstance {
3115 /// Whether this is a static member.
3117 public abstract bool IsStatic {
3122 /// The type which declares this member.
3124 public abstract Type DeclaringType {
3129 /// The instance expression associated with this member, if it's a
3130 /// non-static member.
3132 public Expression InstanceExpression;
3134 public static void error176 (Location loc, string name)
3136 Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
3137 "with an instance reference, qualify it with a type name instead", name);
3140 public static void Error_BaseAccessInExpressionTree (Location loc)
3142 Report.Error (831, loc, "An expression tree may not contain a base access");
3145 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3147 if (InstanceExpression != null)
3148 InstanceExpression.MutateHoistedGenericType (storey);
3151 // TODO: possible optimalization
3152 // Cache resolved constant result in FieldBuilder <-> expression map
3153 public virtual MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3154 SimpleName original)
3158 // original == null || original.Resolve (...) ==> left
3161 if (left is TypeExpr) {
3162 left = left.ResolveAsTypeTerminal (ec, true);
3167 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3175 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3178 return ResolveExtensionMemberAccess (left);
3181 InstanceExpression = left;
3185 protected virtual MemberExpr ResolveExtensionMemberAccess (Expression left)
3187 error176 (loc, GetSignatureForError ());
3191 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3196 if (InstanceExpression == EmptyExpression.Null) {
3197 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3201 if (InstanceExpression.Type.IsValueType) {
3202 if (InstanceExpression is IMemoryLocation) {
3203 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
3205 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
3206 InstanceExpression.Emit (ec);
3208 t.AddressOf (ec, AddressOp.Store);
3211 InstanceExpression.Emit (ec);
3213 if (prepare_for_load)
3214 ec.ig.Emit (OpCodes.Dup);
3217 public virtual void SetTypeArguments (TypeArguments ta)
3219 // TODO: need to get correct member type
3220 Report.Error (307, loc, "The property `{0}' cannot be used with type arguments",
3221 GetSignatureForError ());
3226 /// Represents group of extension methods
3228 public class ExtensionMethodGroupExpr : MethodGroupExpr
3230 readonly NamespaceEntry namespace_entry;
3231 public Expression ExtensionExpression;
3232 Argument extension_argument;
3234 public ExtensionMethodGroupExpr (ArrayList list, NamespaceEntry n, Type extensionType, Location l)
3235 : base (list, extensionType, l)
3237 this.namespace_entry = n;
3240 public override bool IsStatic {
3241 get { return true; }
3244 public bool IsTopLevel {
3245 get { return namespace_entry == null; }
3248 public override void EmitArguments (EmitContext ec, ArrayList arguments)
3250 if (arguments == null)
3251 arguments = new ArrayList (1);
3252 arguments.Insert (0, extension_argument);
3253 base.EmitArguments (ec, arguments);
3256 public override void EmitCall (EmitContext ec, ArrayList arguments)
3258 if (arguments == null)
3259 arguments = new ArrayList (1);
3260 arguments.Insert (0, extension_argument);
3261 base.EmitCall (ec, arguments);
3264 public override MethodGroupExpr OverloadResolve (EmitContext ec, ref ArrayList arguments, bool may_fail, Location loc)
3266 if (arguments == null)
3267 arguments = new ArrayList (1);
3269 arguments.Insert (0, new Argument (ExtensionExpression));
3270 MethodGroupExpr mg = ResolveOverloadExtensions (ec, arguments, namespace_entry, loc);
3272 // Store resolved argument and restore original arguments
3274 ((ExtensionMethodGroupExpr)mg).extension_argument = (Argument)arguments [0];
3275 arguments.RemoveAt (0);
3280 MethodGroupExpr ResolveOverloadExtensions (EmitContext ec, ArrayList arguments, NamespaceEntry ns, Location loc)
3282 // Use normal resolve rules
3283 MethodGroupExpr mg = base.OverloadResolve (ec, ref arguments, ns != null, loc);
3291 ExtensionMethodGroupExpr e = ns.LookupExtensionMethod (type, null, Name, loc);
3293 return base.OverloadResolve (ec, ref arguments, false, loc);
3295 e.ExtensionExpression = ExtensionExpression;
3296 e.SetTypeArguments (type_arguments);
3297 return e.ResolveOverloadExtensions (ec, arguments, e.namespace_entry, loc);
3302 /// MethodGroupExpr represents a group of method candidates which
3303 /// can be resolved to the best method overload
3305 public class MethodGroupExpr : MemberExpr
3307 public interface IErrorHandler
3309 bool NoExactMatch (EmitContext ec, MethodBase method);
3312 public IErrorHandler CustomErrorHandler;
3313 public MethodBase [] Methods;
3314 MethodBase best_candidate;
3315 // TODO: make private
3316 public TypeArguments type_arguments;
3317 bool identical_type_name;
3320 public MethodGroupExpr (MemberInfo [] mi, Type type, Location l)
3323 Methods = new MethodBase [mi.Length];
3324 mi.CopyTo (Methods, 0);
3327 public MethodGroupExpr (ArrayList list, Type type, Location l)
3331 Methods = (MethodBase[])list.ToArray (typeof (MethodBase));
3333 foreach (MemberInfo m in list){
3334 if (!(m is MethodBase)){
3335 Console.WriteLine ("Name " + m.Name);
3336 Console.WriteLine ("Found a: " + m.GetType ().FullName);
3345 protected MethodGroupExpr (Type type, Location loc)
3348 eclass = ExprClass.MethodGroup;
3352 public override Type DeclaringType {
3355 // We assume that the top-level type is in the end
3357 return Methods [Methods.Length - 1].DeclaringType;
3358 //return Methods [0].DeclaringType;
3362 public Type DelegateType {
3364 delegate_type = value;
3368 public bool IdenticalTypeName {
3370 return identical_type_name;
3374 identical_type_name = value;
3378 public override string GetSignatureForError ()
3380 if (best_candidate != null)
3381 return TypeManager.CSharpSignature (best_candidate);
3383 return TypeManager.CSharpSignature (Methods [0]);
3386 public override string Name {
3388 return Methods [0].Name;
3392 public override bool IsInstance {
3394 if (best_candidate != null)
3395 return !best_candidate.IsStatic;
3397 foreach (MethodBase mb in Methods)
3405 public override bool IsStatic {
3407 if (best_candidate != null)
3408 return best_candidate.IsStatic;
3410 foreach (MethodBase mb in Methods)
3418 public static explicit operator ConstructorInfo (MethodGroupExpr mg)
3420 return (ConstructorInfo)mg.best_candidate;
3423 public static explicit operator MethodInfo (MethodGroupExpr mg)
3425 return (MethodInfo)mg.best_candidate;
3429 // 7.4.3.3 Better conversion from expression
3430 // Returns : 1 if a->p is better,
3431 // 2 if a->q is better,
3432 // 0 if neither is better
3434 static int BetterExpressionConversion (EmitContext ec, Argument a, Type p, Type q)
3436 Type argument_type = TypeManager.TypeToCoreType (a.Type);
3437 if (argument_type == TypeManager.anonymous_method_type && RootContext.Version > LanguageVersion.ISO_2) {
3439 // Uwrap delegate from Expression<T>
3441 if (TypeManager.DropGenericTypeArguments (p) == TypeManager.expression_type) {
3442 p = TypeManager.GetTypeArguments (p) [0];
3444 if (TypeManager.DropGenericTypeArguments (q) == TypeManager.expression_type) {
3445 q = TypeManager.GetTypeArguments (q) [0];
3448 p = Delegate.GetInvokeMethod (null, p).ReturnType;
3449 q = Delegate.GetInvokeMethod (null, q).ReturnType;
3451 if (argument_type == p)
3454 if (argument_type == q)
3458 return BetterTypeConversion (ec, p, q);
3462 // 7.4.3.4 Better conversion from type
3464 public static int BetterTypeConversion (EmitContext ec, Type p, Type q)
3466 if (p == null || q == null)
3467 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3469 if (p == TypeManager.int32_type) {
3470 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3472 } else if (p == TypeManager.int64_type) {
3473 if (q == TypeManager.uint64_type)
3475 } else if (p == TypeManager.sbyte_type) {
3476 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3477 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3479 } else if (p == TypeManager.short_type) {
3480 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3481 q == TypeManager.uint64_type)
3485 if (q == TypeManager.int32_type) {
3486 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3488 } if (q == TypeManager.int64_type) {
3489 if (p == TypeManager.uint64_type)
3491 } else if (q == TypeManager.sbyte_type) {
3492 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3493 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3495 } if (q == TypeManager.short_type) {
3496 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3497 p == TypeManager.uint64_type)
3501 // TODO: this is expensive
3502 Expression p_tmp = new EmptyExpression (p);
3503 Expression q_tmp = new EmptyExpression (q);
3505 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3506 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3508 if (p_to_q && !q_to_p)
3511 if (q_to_p && !p_to_q)
3518 /// Determines "Better function" between candidate
3519 /// and the current best match
3522 /// Returns a boolean indicating :
3523 /// false if candidate ain't better
3524 /// true if candidate is better than the current best match
3526 static bool BetterFunction (EmitContext ec, ArrayList args, int argument_count,
3527 MethodBase candidate, bool candidate_params,
3528 MethodBase best, bool best_params)
3530 ParameterData candidate_pd = TypeManager.GetParameterData (candidate);
3531 ParameterData best_pd = TypeManager.GetParameterData (best);
3533 bool better_at_least_one = false;
3535 for (int j = 0, c_idx = 0, b_idx = 0; j < argument_count; ++j, ++c_idx, ++b_idx)
3537 Argument a = (Argument) args [j];
3539 Type ct = TypeManager.TypeToCoreType (candidate_pd.ParameterType (c_idx));
3540 Type bt = TypeManager.TypeToCoreType (best_pd.ParameterType (b_idx));
3542 if (candidate_params && candidate_pd.ParameterModifier (c_idx) == Parameter.Modifier.PARAMS)
3544 ct = TypeManager.GetElementType (ct);
3548 if (best_params && best_pd.ParameterModifier (b_idx) == Parameter.Modifier.PARAMS)
3550 bt = TypeManager.GetElementType (bt);
3558 int result = BetterExpressionConversion (ec, a, ct, bt);
3560 // for each argument, the conversion to 'ct' should be no worse than
3561 // the conversion to 'bt'.
3565 // for at least one argument, the conversion to 'ct' should be better than
3566 // the conversion to 'bt'.
3568 better_at_least_one = true;
3571 if (better_at_least_one)
3575 // This handles the case
3577 // Add (float f1, float f2, float f3);
3578 // Add (params decimal [] foo);
3580 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3581 // first candidate would've chosen as better.
3587 // The two methods have equal parameter types. Now apply tie-breaking rules
3589 if (TypeManager.IsGenericMethod (best) && !TypeManager.IsGenericMethod (candidate))
3591 if (!TypeManager.IsGenericMethod (best) && TypeManager.IsGenericMethod (candidate))
3595 // This handles the following cases:
3597 // Trim () is better than Trim (params char[] chars)
3598 // Concat (string s1, string s2, string s3) is better than
3599 // Concat (string s1, params string [] srest)
3600 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3602 if (!candidate_params && best_params)
3604 if (candidate_params && !best_params)
3607 int candidate_param_count = candidate_pd.Count;
3608 int best_param_count = best_pd.Count;
3610 if (candidate_param_count != best_param_count)
3611 // can only happen if (candidate_params && best_params)
3612 return candidate_param_count > best_param_count;
3615 // now, both methods have the same number of parameters, and the parameters have the same types
3616 // Pick the "more specific" signature
3619 MethodBase orig_candidate = TypeManager.DropGenericMethodArguments (candidate);
3620 MethodBase orig_best = TypeManager.DropGenericMethodArguments (best);
3622 ParameterData orig_candidate_pd = TypeManager.GetParameterData (orig_candidate);
3623 ParameterData orig_best_pd = TypeManager.GetParameterData (orig_best);
3625 bool specific_at_least_once = false;
3626 for (int j = 0; j < candidate_param_count; ++j)
3628 Type ct = TypeManager.TypeToCoreType (orig_candidate_pd.ParameterType (j));
3629 Type bt = TypeManager.TypeToCoreType (orig_best_pd.ParameterType (j));
3632 Type specific = MoreSpecific (ct, bt);
3636 specific_at_least_once = true;
3639 if (specific_at_least_once)
3642 // FIXME: handle lifted operators
3648 protected override MemberExpr ResolveExtensionMemberAccess (Expression left)
3651 return base.ResolveExtensionMemberAccess (left);
3654 // When left side is an expression and at least one candidate method is
3655 // static, it can be extension method
3657 InstanceExpression = left;
3661 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3662 SimpleName original)
3664 if (!(left is TypeExpr) &&
3665 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3666 IdenticalTypeName = true;
3668 return base.ResolveMemberAccess (ec, left, loc, original);
3671 public override Expression CreateExpressionTree (EmitContext ec)
3673 if (best_candidate == null) {
3674 Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3678 if (best_candidate.IsConstructor)
3679 return new TypeOfConstructorInfo (best_candidate, loc);
3681 IMethodData md = TypeManager.GetMethod (best_candidate);
3682 if (md != null && md.IsExcluded ())
3683 Report.Error (765, loc,
3684 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3686 return new TypeOfMethodInfo (best_candidate, loc);
3689 override public Expression DoResolve (EmitContext ec)
3691 if (InstanceExpression != null) {
3692 InstanceExpression = InstanceExpression.DoResolve (ec);
3693 if (InstanceExpression == null)
3700 public void ReportUsageError ()
3702 Report.Error (654, loc, "Method `" + DeclaringType + "." +
3703 Name + "()' is referenced without parentheses");
3706 override public void Emit (EmitContext ec)
3708 ReportUsageError ();
3711 public virtual void EmitArguments (EmitContext ec, ArrayList arguments)
3713 Invocation.EmitArguments (ec, arguments, false, null);
3716 public virtual void EmitCall (EmitContext ec, ArrayList arguments)
3718 Invocation.EmitCall (ec, IsBase, InstanceExpression, best_candidate, arguments, loc);
3721 protected virtual void Error_InvalidArguments (EmitContext ec, Location loc, int idx, MethodBase method,
3722 Argument a, ParameterData expected_par, Type paramType)
3724 if (a is CollectionElementInitializer.ElementInitializerArgument) {
3725 Report.SymbolRelatedToPreviousError (method);
3726 if ((expected_par.ParameterModifier (idx) & Parameter.Modifier.ISBYREF) != 0) {
3727 Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
3728 TypeManager.CSharpSignature (method));
3731 Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
3732 TypeManager.CSharpSignature (method));
3733 } else if (delegate_type == null) {
3734 Report.SymbolRelatedToPreviousError (method);
3735 Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
3736 TypeManager.CSharpSignature (method));
3738 Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
3739 TypeManager.CSharpName (delegate_type));
3741 Parameter.Modifier mod = expected_par.ParameterModifier (idx);
3743 string index = (idx + 1).ToString ();
3744 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
3745 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
3746 if ((mod & Parameter.Modifier.ISBYREF) == 0)
3747 Report.Error (1615, loc, "Argument `{0}' should not be passed with the `{1}' keyword",
3748 index, Parameter.GetModifierSignature (a.Modifier));
3750 Report.Error (1620, loc, "Argument `{0}' must be passed with the `{1}' keyword",
3751 index, Parameter.GetModifierSignature (mod));
3753 string p1 = a.GetSignatureForError ();
3754 string p2 = TypeManager.CSharpName (paramType);
3757 Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
3758 Report.SymbolRelatedToPreviousError (a.Expr.Type);
3759 Report.SymbolRelatedToPreviousError (paramType);
3761 Report.Error (1503, loc, "Argument {0}: Cannot convert type `{1}' to `{2}'", index, p1, p2);
3765 public override void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl)
3767 Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3768 Name, TypeManager.CSharpName (target));
3771 protected virtual int GetApplicableParametersCount (MethodBase method, ParameterData parameters)
3773 return parameters.Count;
3776 public static bool IsAncestralType (Type first_type, Type second_type)
3778 return first_type != second_type &&
3779 (TypeManager.IsSubclassOf (second_type, first_type) ||
3780 TypeManager.ImplementsInterface (second_type, first_type));
3784 /// Determines if the candidate method is applicable (section 14.4.2.1)
3785 /// to the given set of arguments
3786 /// A return value rates candidate method compatibility,
3787 /// 0 = the best, int.MaxValue = the worst
3789 public int IsApplicable (EmitContext ec,
3790 ArrayList arguments, int arg_count, ref MethodBase method, ref bool params_expanded_form)
3792 MethodBase candidate = method;
3794 ParameterData pd = TypeManager.GetParameterData (candidate);
3795 int param_count = GetApplicableParametersCount (candidate, pd);
3797 if (arg_count != param_count) {
3799 return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
3800 if (arg_count < param_count - 1)
3801 return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
3806 // 1. Handle generic method using type arguments when specified or type inference
3808 if (TypeManager.IsGenericMethod (candidate)) {
3809 if (type_arguments != null) {
3810 Type [] g_args = candidate.GetGenericArguments ();
3811 if (g_args.Length != type_arguments.Count)
3812 return int.MaxValue - 20000 + Math.Abs (type_arguments.Count - g_args.Length);
3814 // TODO: Don't create new method, create Parameters only
3815 method = ((MethodInfo) candidate).MakeGenericMethod (type_arguments.Arguments);
3817 pd = TypeManager.GetParameterData (candidate);
3819 int score = TypeManager.InferTypeArguments (ec, arguments, ref candidate);
3821 return score - 20000;
3823 if (TypeManager.IsGenericMethodDefinition (candidate))
3824 throw new InternalErrorException ("A generic method `{0}' definition took part in overload resolution",
3825 TypeManager.CSharpSignature (candidate));
3827 pd = TypeManager.GetParameterData (candidate);
3830 if (type_arguments != null)
3831 return int.MaxValue - 15000;
3836 // 2. Each argument has to be implicitly convertible to method parameter
3839 Parameter.Modifier p_mod = 0;
3841 for (int i = 0; i < arg_count; i++) {
3842 Argument a = (Argument) arguments [i];
3843 Parameter.Modifier a_mod = a.Modifier &
3844 ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3846 if (p_mod != Parameter.Modifier.PARAMS) {
3847 p_mod = pd.ParameterModifier (i) & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3849 if (p_mod == Parameter.Modifier.ARGLIST) {
3850 if (a.Type == TypeManager.runtime_argument_handle_type)
3856 pt = pd.ParameterType (i);
3858 params_expanded_form = true;
3862 if (!params_expanded_form)
3863 score = IsArgumentCompatible (ec, a_mod, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
3865 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0) {
3866 // It can be applicable in expanded form
3867 score = IsArgumentCompatible (ec, a_mod, a, 0, pt.GetElementType ());
3869 params_expanded_form = true;
3873 if (params_expanded_form)
3875 return (arg_count - i) * 2 + score;
3879 if (arg_count != param_count)
3880 params_expanded_form = true;
3885 int IsArgumentCompatible (EmitContext ec, Parameter.Modifier arg_mod, Argument argument, Parameter.Modifier param_mod, Type parameter)
3888 // Types have to be identical when ref or out modifer is used
3890 if (arg_mod != 0 || param_mod != 0) {
3891 if (TypeManager.HasElementType (parameter))
3892 parameter = parameter.GetElementType ();
3894 Type a_type = argument.Type;
3895 if (TypeManager.HasElementType (a_type))
3896 a_type = a_type.GetElementType ();
3898 if (a_type != parameter)
3904 if (delegate_type != null ?
3905 !Delegate.IsTypeCovariant (argument.Expr, parameter) :
3906 !Convert.ImplicitConversionExists (ec, argument.Expr, parameter))
3909 if (arg_mod != param_mod)
3915 public static bool IsOverride (MethodBase cand_method, MethodBase base_method)
3917 if (!IsAncestralType (base_method.DeclaringType, cand_method.DeclaringType))
3920 ParameterData cand_pd = TypeManager.GetParameterData (cand_method);
3921 ParameterData base_pd = TypeManager.GetParameterData (base_method);
3923 if (cand_pd.Count != base_pd.Count)
3926 for (int j = 0; j < cand_pd.Count; ++j)
3928 Parameter.Modifier cm = cand_pd.ParameterModifier (j);
3929 Parameter.Modifier bm = base_pd.ParameterModifier (j);
3930 Type ct = TypeManager.TypeToCoreType (cand_pd.ParameterType (j));
3931 Type bt = TypeManager.TypeToCoreType (base_pd.ParameterType (j));
3933 if (cm != bm || ct != bt)
3940 public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2, Location loc)
3942 MemberInfo [] miset;
3943 MethodGroupExpr union;
3948 return (MethodGroupExpr) mg2;
3951 return (MethodGroupExpr) mg1;
3954 MethodGroupExpr left_set = null, right_set = null;
3955 int length1 = 0, length2 = 0;
3957 left_set = (MethodGroupExpr) mg1;
3958 length1 = left_set.Methods.Length;
3960 right_set = (MethodGroupExpr) mg2;
3961 length2 = right_set.Methods.Length;
3963 ArrayList common = new ArrayList ();
3965 foreach (MethodBase r in right_set.Methods){
3966 if (TypeManager.ArrayContainsMethod (left_set.Methods, r))
3970 miset = new MemberInfo [length1 + length2 - common.Count];
3971 left_set.Methods.CopyTo (miset, 0);
3975 foreach (MethodBase r in right_set.Methods) {
3976 if (!common.Contains (r))
3980 union = new MethodGroupExpr (miset, mg1.Type, loc);
3985 static Type MoreSpecific (Type p, Type q)
3987 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
3989 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
3992 if (TypeManager.HasElementType (p))
3994 Type pe = TypeManager.GetElementType (p);
3995 Type qe = TypeManager.GetElementType (q);
3996 Type specific = MoreSpecific (pe, qe);
4002 else if (TypeManager.IsGenericType (p))
4004 Type[] pargs = TypeManager.GetTypeArguments (p);
4005 Type[] qargs = TypeManager.GetTypeArguments (q);
4007 bool p_specific_at_least_once = false;
4008 bool q_specific_at_least_once = false;
4010 for (int i = 0; i < pargs.Length; i++)
4012 Type specific = MoreSpecific (pargs [i], qargs [i]);
4013 if (specific == pargs [i])
4014 p_specific_at_least_once = true;
4015 if (specific == qargs [i])
4016 q_specific_at_least_once = true;
4019 if (p_specific_at_least_once && !q_specific_at_least_once)
4021 if (!p_specific_at_least_once && q_specific_at_least_once)
4028 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4030 base.MutateHoistedGenericType (storey);
4032 MethodInfo mi = best_candidate as MethodInfo;
4034 best_candidate = storey.MutateGenericMethod (mi);
4038 best_candidate = storey.MutateConstructor ((ConstructorInfo) this);
4042 /// Find the Applicable Function Members (7.4.2.1)
4044 /// me: Method Group expression with the members to select.
4045 /// it might contain constructors or methods (or anything
4046 /// that maps to a method).
4048 /// Arguments: ArrayList containing resolved Argument objects.
4050 /// loc: The location if we want an error to be reported, or a Null
4051 /// location for "probing" purposes.
4053 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4054 /// that is the best match of me on Arguments.
4057 public virtual MethodGroupExpr OverloadResolve (EmitContext ec, ref ArrayList Arguments,
4058 bool may_fail, Location loc)
4060 bool method_params = false;
4061 Type applicable_type = null;
4063 ArrayList candidates = new ArrayList (2);
4064 ArrayList candidate_overrides = null;
4067 // Used to keep a map between the candidate
4068 // and whether it is being considered in its
4069 // normal or expanded form
4071 // false is normal form, true is expanded form
4073 Hashtable candidate_to_form = null;
4075 if (Arguments != null)
4076 arg_count = Arguments.Count;
4078 if (RootContext.Version == LanguageVersion.ISO_1 && Name == "Invoke" && TypeManager.IsDelegateType (DeclaringType)) {
4080 Report.Error (1533, loc, "Invoke cannot be called directly on a delegate");
4084 int nmethods = Methods.Length;
4088 // Methods marked 'override' don't take part in 'applicable_type'
4089 // computation, nor in the actual overload resolution.
4090 // However, they still need to be emitted instead of a base virtual method.
4091 // So, we salt them away into the 'candidate_overrides' array.
4093 // In case of reflected methods, we replace each overriding method with
4094 // its corresponding base virtual method. This is to improve compatibility
4095 // with non-C# libraries which change the visibility of overrides (#75636)
4098 for (int i = 0; i < Methods.Length; ++i) {
4099 MethodBase m = Methods [i];
4100 if (TypeManager.IsOverride (m)) {
4101 if (candidate_overrides == null)
4102 candidate_overrides = new ArrayList ();
4103 candidate_overrides.Add (m);
4104 m = TypeManager.TryGetBaseDefinition (m);
4113 // Enable message recording, it's used mainly by lambda expressions
4115 Report.IMessageRecorder msg_recorder = new Report.MessageRecorder ();
4116 Report.IMessageRecorder prev_recorder = Report.SetMessageRecorder (msg_recorder);
4119 // First we construct the set of applicable methods
4121 bool is_sorted = true;
4122 int best_candidate_rate = int.MaxValue;
4123 for (int i = 0; i < nmethods; i++) {
4124 Type decl_type = Methods [i].DeclaringType;
4127 // If we have already found an applicable method
4128 // we eliminate all base types (Section 14.5.5.1)
4130 if (applicable_type != null && IsAncestralType (decl_type, applicable_type))
4134 // Check if candidate is applicable (section 14.4.2.1)
4136 bool params_expanded_form = false;
4137 int candidate_rate = IsApplicable (ec, Arguments, arg_count, ref Methods [i], ref params_expanded_form);
4139 if (candidate_rate < best_candidate_rate) {
4140 best_candidate_rate = candidate_rate;
4141 best_candidate = Methods [i];
4144 if (params_expanded_form) {
4145 if (candidate_to_form == null)
4146 candidate_to_form = new PtrHashtable ();
4147 MethodBase candidate = Methods [i];
4148 candidate_to_form [candidate] = candidate;
4151 if (candidate_rate != 0) {
4152 if (msg_recorder != null)
4153 msg_recorder.EndSession ();
4157 msg_recorder = null;
4158 candidates.Add (Methods [i]);
4160 if (applicable_type == null)
4161 applicable_type = decl_type;
4162 else if (applicable_type != decl_type) {
4164 if (IsAncestralType (applicable_type, decl_type))
4165 applicable_type = decl_type;
4169 Report.SetMessageRecorder (prev_recorder);
4170 if (msg_recorder != null && msg_recorder.PrintMessages ())
4173 int candidate_top = candidates.Count;
4175 if (applicable_type == null) {
4177 // When we found a top level method which does not match and it's
4178 // not an extension method. We start extension methods lookup from here
4180 if (InstanceExpression != null) {
4181 ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (type, Name, loc);
4182 if (ex_method_lookup != null) {
4183 ex_method_lookup.ExtensionExpression = InstanceExpression;
4184 ex_method_lookup.SetTypeArguments (type_arguments);
4185 return ex_method_lookup.OverloadResolve (ec, ref Arguments, may_fail, loc);
4193 // Okay so we have failed to find exact match so we
4194 // return error info about the closest match
4196 if (best_candidate != null) {
4197 if (CustomErrorHandler != null) {
4198 if (CustomErrorHandler.NoExactMatch (ec, best_candidate))
4202 ParameterData pd = TypeManager.GetParameterData (best_candidate);
4203 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4204 if (arg_count == pd.Count || pd.HasParams) {
4205 if (TypeManager.IsGenericMethodDefinition (best_candidate)) {
4206 if (type_arguments == null) {
4207 Report.Error (411, loc,
4208 "The type arguments for method `{0}' cannot be inferred from " +
4209 "the usage. Try specifying the type arguments explicitly",
4210 TypeManager.CSharpSignature (best_candidate));
4214 Type [] g_args = TypeManager.GetGenericArguments (best_candidate);
4215 if (type_arguments.Count != g_args.Length) {
4216 Report.SymbolRelatedToPreviousError (best_candidate);
4217 Report.Error (305, loc, "Using the generic method `{0}' requires `{1}' type argument(s)",
4218 TypeManager.CSharpSignature (best_candidate),
4219 g_args.Length.ToString ());
4223 if (type_arguments != null && !TypeManager.IsGenericMethod (best_candidate)) {
4224 Namespace.Error_TypeArgumentsCannotBeUsed (best_candidate, loc);
4229 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate, cand_params, may_fail, loc))
4234 if (almost_matched_members.Count != 0) {
4235 Error_MemberLookupFailed (ec.ContainerType, type, type, ".ctor",
4236 null, MemberTypes.Constructor, AllBindingFlags);
4241 // We failed to find any method with correct argument count
4243 if (Name == ConstructorInfo.ConstructorName) {
4244 Report.SymbolRelatedToPreviousError (type);
4245 Report.Error (1729, loc,
4246 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4247 TypeManager.CSharpName (type), arg_count);
4249 Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4250 Name, arg_count.ToString ());
4258 // At this point, applicable_type is _one_ of the most derived types
4259 // in the set of types containing the methods in this MethodGroup.
4260 // Filter the candidates so that they only contain methods from the
4261 // most derived types.
4264 int finalized = 0; // Number of finalized candidates
4267 // Invariant: applicable_type is a most derived type
4269 // We'll try to complete Section 14.5.5.1 for 'applicable_type' by
4270 // eliminating all it's base types. At the same time, we'll also move
4271 // every unrelated type to the end of the array, and pick the next
4272 // 'applicable_type'.
4274 Type next_applicable_type = null;
4275 int j = finalized; // where to put the next finalized candidate
4276 int k = finalized; // where to put the next undiscarded candidate
4277 for (int i = finalized; i < candidate_top; ++i) {
4278 MethodBase candidate = (MethodBase) candidates [i];
4279 Type decl_type = candidate.DeclaringType;
4281 if (decl_type == applicable_type) {
4282 candidates [k++] = candidates [j];
4283 candidates [j++] = candidates [i];
4287 if (IsAncestralType (decl_type, applicable_type))
4290 if (next_applicable_type != null &&
4291 IsAncestralType (decl_type, next_applicable_type))
4294 candidates [k++] = candidates [i];
4296 if (next_applicable_type == null ||
4297 IsAncestralType (next_applicable_type, decl_type))
4298 next_applicable_type = decl_type;
4301 applicable_type = next_applicable_type;
4304 } while (applicable_type != null);
4308 // Now we actually find the best method
4311 best_candidate = (MethodBase) candidates [0];
4312 if (delegate_type == null)
4313 method_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4315 for (int ix = 1; ix < candidate_top; ix++) {
4316 MethodBase candidate = (MethodBase) candidates [ix];
4318 if (candidate == best_candidate)
4321 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4323 if (BetterFunction (ec, Arguments, arg_count,
4324 candidate, cand_params,
4325 best_candidate, method_params)) {
4326 best_candidate = candidate;
4327 method_params = cand_params;
4331 // Now check that there are no ambiguities i.e the selected method
4332 // should be better than all the others
4334 MethodBase ambiguous = null;
4335 for (int ix = 1; ix < candidate_top; ix++) {
4336 MethodBase candidate = (MethodBase) candidates [ix];
4338 if (candidate == best_candidate)
4341 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4342 if (!BetterFunction (ec, Arguments, arg_count,
4343 best_candidate, method_params,
4344 candidate, cand_params))
4347 Report.SymbolRelatedToPreviousError (candidate);
4348 ambiguous = candidate;
4352 if (ambiguous != null) {
4353 Report.SymbolRelatedToPreviousError (best_candidate);
4354 Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4355 TypeManager.CSharpSignature (ambiguous), TypeManager.CSharpSignature (best_candidate));
4360 // If the method is a virtual function, pick an override closer to the LHS type.
4362 if (!IsBase && best_candidate.IsVirtual) {
4363 if (TypeManager.IsOverride (best_candidate))
4364 throw new InternalErrorException (
4365 "Should not happen. An 'override' method took part in overload resolution: " + best_candidate);
4367 if (candidate_overrides != null) {
4368 Type[] gen_args = null;
4369 bool gen_override = false;
4370 if (TypeManager.IsGenericMethod (best_candidate))
4371 gen_args = TypeManager.GetGenericArguments (best_candidate);
4373 foreach (MethodBase candidate in candidate_overrides) {
4374 if (TypeManager.IsGenericMethod (candidate)) {
4375 if (gen_args == null)
4378 if (gen_args.Length != TypeManager.GetGenericArguments (candidate).Length)
4381 if (gen_args != null)
4385 if (IsOverride (candidate, best_candidate)) {
4386 gen_override = true;
4387 best_candidate = candidate;
4391 if (gen_override && gen_args != null) {
4393 best_candidate = ((MethodInfo) best_candidate).MakeGenericMethod (gen_args);
4400 // And now check if the arguments are all
4401 // compatible, perform conversions if
4402 // necessary etc. and return if everything is
4405 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate,
4406 method_params, may_fail, loc))
4409 if (best_candidate == null)
4412 MethodBase the_method = TypeManager.DropGenericMethodArguments (best_candidate);
4414 if (the_method.IsGenericMethodDefinition &&
4415 !ConstraintChecker.CheckConstraints (ec, the_method, best_candidate, loc))
4419 IMethodData data = TypeManager.GetMethod (the_method);
4421 data.SetMemberIsUsed ();
4426 public override void SetTypeArguments (TypeArguments ta)
4428 type_arguments = ta;
4431 public bool VerifyArgumentsCompat (EmitContext ec, ref ArrayList arguments,
4432 int arg_count, MethodBase method,
4433 bool chose_params_expanded,
4434 bool may_fail, Location loc)
4436 ParameterData pd = TypeManager.GetParameterData (method);
4438 int errors = Report.Errors;
4439 Parameter.Modifier p_mod = 0;
4441 int a_idx = 0, a_pos = 0;
4443 ArrayList params_initializers = null;
4445 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4446 a = (Argument) arguments [a_idx];
4447 if (p_mod != Parameter.Modifier.PARAMS) {
4448 p_mod = pd.ParameterModifier (a_idx);
4449 pt = pd.ParameterType (a_idx);
4451 if (p_mod == Parameter.Modifier.ARGLIST) {
4452 if (a.Type != TypeManager.runtime_argument_handle_type)
4457 if (pt.IsPointer && !ec.InUnsafe) {
4464 if (p_mod == Parameter.Modifier.PARAMS) {
4465 if (chose_params_expanded) {
4466 params_initializers = new ArrayList (arg_count - a_idx);
4467 pt = TypeManager.GetElementType (pt);
4469 } else if (p_mod != 0) {
4470 pt = TypeManager.GetElementType (pt);
4475 // Types have to be identical when ref or out modifer is used
4477 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4478 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4481 if (!TypeManager.IsEqual (a.Expr.Type, pt))
4488 if (TypeManager.IsEqual (a.Type, pt)) {
4491 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4497 // Convert params arguments to an array initializer
4499 if (params_initializers != null) {
4500 // we choose to use 'a.Expr' rather than 'conv' so that
4501 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
4502 params_initializers.Add (a.Expr);
4503 arguments.RemoveAt (a_idx--);
4508 // Update the argument with the implicit conversion
4513 // Fill not provided arguments required by params modifier
4515 if (params_initializers == null && pd.HasParams && arg_count < pd.Count && a_idx + 1 == pd.Count) {
4516 if (arguments == null)
4517 arguments = new ArrayList (1);
4519 pt = pd.Types [GetApplicableParametersCount (method, pd) - 1];
4520 pt = TypeManager.GetElementType (pt);
4521 params_initializers = new ArrayList (0);
4524 if (a_idx == arg_count) {
4526 // Append an array argument with all params arguments
4528 if (params_initializers != null) {
4529 arguments.Add (new Argument (
4530 new ArrayCreation (new TypeExpression (pt, loc), "[]",
4531 params_initializers, loc).Resolve (ec)));
4536 if (!may_fail && Report.Errors == errors) {
4537 if (CustomErrorHandler != null)
4538 CustomErrorHandler.NoExactMatch (ec, best_candidate);
4540 Error_InvalidArguments (ec, loc, a_pos, method, a, pd, pt);
4546 public class ConstantExpr : MemberExpr
4550 public ConstantExpr (FieldInfo constant, Location loc)
4552 this.constant = constant;
4556 public override string Name {
4557 get { throw new NotImplementedException (); }
4560 public override bool IsInstance {
4561 get { return !IsStatic; }
4564 public override bool IsStatic {
4565 get { return constant.IsStatic; }
4568 public override Type DeclaringType {
4569 get { return constant.DeclaringType; }
4572 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc, SimpleName original)
4574 constant = TypeManager.GetGenericFieldDefinition (constant);
4576 IConstant ic = TypeManager.GetConstant (constant);
4578 if (constant.IsLiteral) {
4579 ic = new ExternalConstant (constant);
4581 ic = ExternalConstant.CreateDecimal (constant);
4582 // HACK: decimal field was not resolved as constant
4584 return new FieldExpr (constant, loc).ResolveMemberAccess (ec, left, loc, original);
4586 TypeManager.RegisterConstant (constant, ic);
4589 return base.ResolveMemberAccess (ec, left, loc, original);
4592 public override Expression CreateExpressionTree (EmitContext ec)
4594 throw new NotSupportedException ("ET");
4597 public override Expression DoResolve (EmitContext ec)
4599 IConstant ic = TypeManager.GetConstant (constant);
4600 if (ic.ResolveValue ()) {
4601 if (!ec.IsInObsoleteScope)
4602 ic.CheckObsoleteness (loc);
4605 return ic.CreateConstantReference (loc);
4608 public override void Emit (EmitContext ec)
4610 throw new NotSupportedException ();
4613 public override string GetSignatureForError ()
4615 return TypeManager.GetFullNameSignature (constant);
4620 /// Fully resolved expression that evaluates to a Field
4622 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariable {
4623 public readonly FieldInfo FieldInfo;
4624 readonly Type constructed_generic_type;
4625 VariableInfo variable_info;
4627 LocalTemporary temp;
4629 bool in_initializer;
4631 public FieldExpr (FieldInfo fi, Location l, bool in_initializer):
4634 this.in_initializer = in_initializer;
4637 public FieldExpr (FieldInfo fi, Location l)
4640 eclass = ExprClass.Variable;
4641 type = TypeManager.TypeToCoreType (fi.FieldType);
4645 public FieldExpr (FieldInfo fi, Type genericType, Location l)
4648 this.constructed_generic_type = genericType;
4651 public override string Name {
4653 return FieldInfo.Name;
4657 public override bool IsInstance {
4659 return !FieldInfo.IsStatic;
4663 public override bool IsStatic {
4665 return FieldInfo.IsStatic;
4669 public override Type DeclaringType {
4671 return FieldInfo.DeclaringType;
4675 public override string GetSignatureForError ()
4677 return TypeManager.GetFullNameSignature (FieldInfo);
4680 public VariableInfo VariableInfo {
4682 return variable_info;
4686 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
4687 SimpleName original)
4689 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
4690 Type t = fi.FieldType;
4692 if (t.IsPointer && !ec.InUnsafe) {
4696 return base.ResolveMemberAccess (ec, left, loc, original);
4699 public override Expression CreateExpressionTree (EmitContext ec)
4701 Expression instance;
4702 if (InstanceExpression == null) {
4703 instance = new NullLiteral (loc);
4705 instance = InstanceExpression.CreateExpressionTree (ec);
4708 ArrayList args = new ArrayList (2);
4709 args.Add (new Argument (instance));
4710 args.Add (new Argument (CreateTypeOfExpression ()));
4711 return CreateExpressionFactoryCall ("Field", args);
4714 public Expression CreateTypeOfExpression ()
4716 return new TypeOfField (FieldInfo, loc);
4719 override public Expression DoResolve (EmitContext ec)
4721 return DoResolve (ec, false, false);
4724 Expression DoResolve (EmitContext ec, bool lvalue_instance, bool out_access)
4726 if (!FieldInfo.IsStatic){
4727 if (InstanceExpression == null){
4729 // This can happen when referencing an instance field using
4730 // a fully qualified type expression: TypeName.InstanceField = xxx
4732 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4736 // Resolve the field's instance expression while flow analysis is turned
4737 // off: when accessing a field "a.b", we must check whether the field
4738 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4740 if (lvalue_instance) {
4741 using (ec.With (EmitContext.Flags.DoFlowAnalysis, false)) {
4742 Expression right_side =
4743 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4744 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side, loc);
4747 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
4748 InstanceExpression = InstanceExpression.Resolve (ec, rf);
4751 if (InstanceExpression == null)
4754 using (ec.Set (EmitContext.Flags.OmitStructFlowAnalysis)) {
4755 InstanceExpression.CheckMarshalByRefAccess (ec);
4759 if (!in_initializer && !ec.IsInFieldInitializer) {
4760 ObsoleteAttribute oa;
4761 FieldBase f = TypeManager.GetField (FieldInfo);
4763 if (!ec.IsInObsoleteScope)
4764 f.CheckObsoleteness (loc);
4766 // To be sure that type is external because we do not register generated fields
4767 } else if (!(FieldInfo.DeclaringType is TypeBuilder)) {
4768 oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
4770 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
4774 IFixedBuffer fb = AttributeTester.GetFixedBuffer (FieldInfo);
4776 if (!ec.InFixedInitializer && ec.ContainerType.IsValueType) {
4777 Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4780 if (InstanceExpression.eclass != ExprClass.Variable) {
4781 Report.SymbolRelatedToPreviousError (FieldInfo);
4782 Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4783 TypeManager.GetFullNameSignature (FieldInfo));
4786 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4789 // If the instance expression is a local variable or parameter.
4790 IVariable var = InstanceExpression as IVariable;
4791 if (var == null || var.VariableInfo == null)
4794 VariableInfo vi = var.VariableInfo;
4795 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
4798 variable_info = vi.GetSubStruct (FieldInfo.Name);
4802 static readonly int [] codes = {
4803 191, // instance, write access
4804 192, // instance, out access
4805 198, // static, write access
4806 199, // static, out access
4807 1648, // member of value instance, write access
4808 1649, // member of value instance, out access
4809 1650, // member of value static, write access
4810 1651 // member of value static, out access
4813 static readonly string [] msgs = {
4814 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4815 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4816 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4817 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4818 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4819 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4820 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4821 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4824 // The return value is always null. Returning a value simplifies calling code.
4825 Expression Report_AssignToReadonly (Expression right_side)
4828 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4832 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4834 Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4839 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4841 IVariable var = InstanceExpression as IVariable;
4842 if (var != null && var.VariableInfo != null)
4843 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
4845 bool lvalue_instance = !FieldInfo.IsStatic && FieldInfo.DeclaringType.IsValueType;
4846 bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
4848 Expression e = DoResolve (ec, lvalue_instance, out_access);
4853 FieldBase fb = TypeManager.GetField (FieldInfo);
4857 if (FieldInfo.IsInitOnly) {
4858 // InitOnly fields can only be assigned in constructors or initializers
4859 if (!ec.IsInFieldInitializer && !ec.IsConstructor)
4860 return Report_AssignToReadonly (right_side);
4862 if (ec.IsConstructor) {
4863 Type ctype = ec.TypeContainer.CurrentType;
4865 ctype = ec.ContainerType;
4867 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4868 if (!TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
4869 return Report_AssignToReadonly (right_side);
4870 // static InitOnly fields cannot be assigned-to in an instance constructor
4871 if (IsStatic && !ec.IsStatic)
4872 return Report_AssignToReadonly (right_side);
4873 // instance constructors can't modify InitOnly fields of other instances of the same type
4874 if (!IsStatic && !(InstanceExpression is This))
4875 return Report_AssignToReadonly (right_side);
4879 if (right_side == EmptyExpression.OutAccess &&
4880 !IsStatic && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type)) {
4881 Report.SymbolRelatedToPreviousError (DeclaringType);
4882 Report.Warning (197, 1, loc,
4883 "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",
4884 GetSignatureForError ());
4890 bool is_marshal_by_ref ()
4892 return !IsStatic && Type.IsValueType && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type);
4895 public override void CheckMarshalByRefAccess (EmitContext ec)
4897 if (is_marshal_by_ref () && !(InstanceExpression is This)) {
4898 Report.SymbolRelatedToPreviousError (DeclaringType);
4899 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",
4900 GetSignatureForError ());
4904 public override int GetHashCode ()
4906 return FieldInfo.GetHashCode ();
4909 public bool IsFixed {
4911 IVariable variable = InstanceExpression as IVariable;
4912 // A variable of the form V.I is fixed when V is a fixed variable of a struct type.
4913 // We defer the InstanceExpression check after the variable check to avoid a
4914 // separate null check on InstanceExpression.
4915 return variable != null && InstanceExpression.Type.IsValueType && variable.IsFixed;
4919 public override bool Equals (object obj)
4921 FieldExpr fe = obj as FieldExpr;
4925 if (FieldInfo != fe.FieldInfo)
4928 if (InstanceExpression == null || fe.InstanceExpression == null)
4931 return InstanceExpression.Equals (fe.InstanceExpression);
4934 public void Emit (EmitContext ec, bool leave_copy)
4936 ILGenerator ig = ec.ig;
4937 bool is_volatile = false;
4939 FieldBase f = TypeManager.GetField (FieldInfo);
4941 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4944 f.SetMemberIsUsed ();
4947 if (FieldInfo.IsStatic){
4949 ig.Emit (OpCodes.Volatile);
4951 ig.Emit (OpCodes.Ldsfld, GetConstructedFieldInfo ());
4954 EmitInstance (ec, false);
4956 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
4958 ig.Emit (OpCodes.Ldflda, GetConstructedFieldInfo ());
4959 ig.Emit (OpCodes.Ldflda, ff.Element);
4962 ig.Emit (OpCodes.Volatile);
4964 ig.Emit (OpCodes.Ldfld, GetConstructedFieldInfo ());
4969 ec.ig.Emit (OpCodes.Dup);
4970 if (!FieldInfo.IsStatic) {
4971 temp = new LocalTemporary (this.Type);
4977 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4979 FieldAttributes fa = FieldInfo.Attributes;
4980 bool is_static = (fa & FieldAttributes.Static) != 0;
4981 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
4982 ILGenerator ig = ec.ig;
4984 if (is_readonly && !ec.IsConstructor){
4985 Report_AssignToReadonly (source);
4989 prepared = prepare_for_load;
4990 EmitInstance (ec, prepared);
4994 ec.ig.Emit (OpCodes.Dup);
4995 if (!FieldInfo.IsStatic) {
4996 temp = new LocalTemporary (this.Type);
5001 FieldBase f = TypeManager.GetField (FieldInfo);
5003 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
5004 ig.Emit (OpCodes.Volatile);
5010 ig.Emit (OpCodes.Stsfld, GetConstructedFieldInfo ());
5012 ig.Emit (OpCodes.Stfld, GetConstructedFieldInfo ());
5021 public override void Emit (EmitContext ec)
5026 public override void EmitSideEffect (EmitContext ec)
5028 FieldBase f = TypeManager.GetField (FieldInfo);
5029 bool is_volatile = f != null && (f.ModFlags & Modifiers.VOLATILE) != 0;
5031 if (is_volatile || is_marshal_by_ref ())
5032 base.EmitSideEffect (ec);
5035 public void AddressOf (EmitContext ec, AddressOp mode)
5037 ILGenerator ig = ec.ig;
5039 FieldBase f = TypeManager.GetField (FieldInfo);
5041 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
5042 Report.Warning (420, 1, loc, "`{0}': A volatile field references will not be treated as volatile",
5043 f.GetSignatureForError ());
5046 if ((mode & AddressOp.Store) != 0)
5048 if ((mode & AddressOp.Load) != 0)
5049 f.SetMemberIsUsed ();
5053 // Handle initonly fields specially: make a copy and then
5054 // get the address of the copy.
5057 if (FieldInfo.IsInitOnly){
5059 if (ec.IsConstructor){
5060 if (FieldInfo.IsStatic){
5072 local = ig.DeclareLocal (type);
5073 ig.Emit (OpCodes.Stloc, local);
5074 ig.Emit (OpCodes.Ldloca, local);
5079 if (FieldInfo.IsStatic){
5080 ig.Emit (OpCodes.Ldsflda, GetConstructedFieldInfo ());
5083 EmitInstance (ec, false);
5084 ig.Emit (OpCodes.Ldflda, GetConstructedFieldInfo ());
5088 FieldInfo GetConstructedFieldInfo ()
5090 if (constructed_generic_type == null)
5093 return TypeBuilder.GetField (constructed_generic_type, FieldInfo);
5095 throw new NotSupportedException ();
5102 /// Expression that evaluates to a Property. The Assign class
5103 /// might set the `Value' expression if we are in an assignment.
5105 /// This is not an LValue because we need to re-write the expression, we
5106 /// can not take data from the stack and store it.
5108 public class PropertyExpr : MemberExpr, IAssignMethod {
5109 public readonly PropertyInfo PropertyInfo;
5110 MethodInfo getter, setter;
5115 LocalTemporary temp;
5118 public PropertyExpr (Type container_type, PropertyInfo pi, Location l)
5121 eclass = ExprClass.PropertyAccess;
5125 type = TypeManager.TypeToCoreType (pi.PropertyType);
5127 ResolveAccessors (container_type);
5130 public override string Name {
5132 return PropertyInfo.Name;
5136 public override bool IsInstance {
5142 public override bool IsStatic {
5148 public override Expression CreateExpressionTree (EmitContext ec)
5151 if (IsSingleDimensionalArrayLength ()) {
5152 args = new ArrayList (1);
5153 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5154 return CreateExpressionFactoryCall ("ArrayLength", args);
5158 Error_BaseAccessInExpressionTree (loc);
5162 args = new ArrayList (2);
5163 if (InstanceExpression == null)
5164 args.Add (new Argument (new NullLiteral (loc)));
5166 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5167 args.Add (new Argument (new TypeOfMethodInfo (getter, loc)));
5168 return CreateExpressionFactoryCall ("Property", args);
5171 public Expression CreateSetterTypeOfExpression ()
5173 return new TypeOfMethodInfo (setter, loc);
5176 public override Type DeclaringType {
5178 return PropertyInfo.DeclaringType;
5182 public override string GetSignatureForError ()
5184 return TypeManager.GetFullNameSignature (PropertyInfo);
5187 void FindAccessors (Type invocation_type)
5189 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
5190 BindingFlags.Static | BindingFlags.Instance |
5191 BindingFlags.DeclaredOnly;
5193 Type current = PropertyInfo.DeclaringType;
5194 for (; current != null; current = current.BaseType) {
5195 MemberInfo[] group = TypeManager.MemberLookup (
5196 invocation_type, invocation_type, current,
5197 MemberTypes.Property, flags, PropertyInfo.Name, null);
5202 if (group.Length != 1)
5203 // Oooops, can this ever happen ?
5206 PropertyInfo pi = (PropertyInfo) group [0];
5209 getter = pi.GetGetMethod (true);
5212 setter = pi.GetSetMethod (true);
5214 MethodInfo accessor = getter != null ? getter : setter;
5216 if (!accessor.IsVirtual)
5222 // We also perform the permission checking here, as the PropertyInfo does not
5223 // hold the information for the accessibility of its setter/getter
5225 // TODO: Refactor to use some kind of cache together with GetPropertyFromAccessor
5226 void ResolveAccessors (Type container_type)
5228 FindAccessors (container_type);
5230 if (getter != null) {
5231 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
5232 IMethodData md = TypeManager.GetMethod (the_getter);
5234 md.SetMemberIsUsed ();
5236 is_static = getter.IsStatic;
5239 if (setter != null) {
5240 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
5241 IMethodData md = TypeManager.GetMethod (the_setter);
5243 md.SetMemberIsUsed ();
5245 is_static = setter.IsStatic;
5249 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5251 if (InstanceExpression != null)
5252 InstanceExpression.MutateHoistedGenericType (storey);
5254 type = storey.MutateType (type);
5255 getter = storey.MutateGenericMethod (getter);
5258 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
5261 InstanceExpression = null;
5265 if (InstanceExpression == null) {
5266 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5270 InstanceExpression = InstanceExpression.DoResolve (ec);
5271 if (lvalue_instance && InstanceExpression != null)
5272 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
5274 if (InstanceExpression == null)
5277 InstanceExpression.CheckMarshalByRefAccess (ec);
5279 if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) &&
5280 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
5281 !TypeManager.IsNestedChildOf (ec.ContainerType, InstanceExpression.Type) &&
5282 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.ContainerType)) {
5283 Report.SymbolRelatedToPreviousError (PropertyInfo);
5284 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
5291 void Error_PropertyNotFound (MethodInfo mi, bool getter)
5293 // TODO: correctly we should compare arguments but it will lead to bigger changes
5294 if (mi is MethodBuilder) {
5295 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
5299 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
5301 ParameterData iparams = TypeManager.GetParameterData (mi);
5302 sig.Append (getter ? "get_" : "set_");
5304 sig.Append (iparams.GetSignatureForError ());
5306 Report.SymbolRelatedToPreviousError (mi);
5307 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
5308 Name, sig.ToString ());
5311 public bool IsAccessibleFrom (Type invocation_type, bool lvalue)
5314 MethodInfo accessor = lvalue ? setter : getter;
5315 if (accessor == null && lvalue)
5317 return accessor != null && IsAccessorAccessible (invocation_type, accessor, out dummy);
5320 bool IsSingleDimensionalArrayLength ()
5322 if (DeclaringType != TypeManager.array_type || getter == null || Name != "Length")
5325 string t_name = InstanceExpression.Type.Name;
5326 int t_name_len = t_name.Length;
5327 return t_name_len > 2 && t_name [t_name_len - 2] == '[';
5330 override public Expression DoResolve (EmitContext ec)
5335 if (getter != null){
5336 if (TypeManager.GetParameterData (getter).Count != 0){
5337 Error_PropertyNotFound (getter, true);
5342 if (getter == null){
5344 // The following condition happens if the PropertyExpr was
5345 // created, but is invalid (ie, the property is inaccessible),
5346 // and we did not want to embed the knowledge about this in
5347 // the caller routine. This only avoids double error reporting.
5352 if (InstanceExpression != EmptyExpression.Null) {
5353 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5354 TypeManager.GetFullNameSignature (PropertyInfo));
5359 bool must_do_cs1540_check = false;
5360 if (getter != null &&
5361 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
5362 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
5363 if (pm != null && pm.HasCustomAccessModifier) {
5364 Report.SymbolRelatedToPreviousError (pm);
5365 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5366 TypeManager.CSharpSignature (getter));
5369 Report.SymbolRelatedToPreviousError (getter);
5370 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
5375 if (!InstanceResolve (ec, false, must_do_cs1540_check))
5379 // Only base will allow this invocation to happen.
5381 if (IsBase && getter.IsAbstract) {
5382 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5386 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
5396 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
5398 if (right_side == EmptyExpression.OutAccess) {
5399 if (ec.CurrentBlock.Toplevel.GetTransparentIdentifier (PropertyInfo.Name) != null) {
5400 Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5403 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as `ref' or `out' parameter",
5404 GetSignatureForError ());
5409 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5410 Error_CannotModifyIntermediateExpressionValue (ec);
5413 if (setter == null){
5415 // The following condition happens if the PropertyExpr was
5416 // created, but is invalid (ie, the property is inaccessible),
5417 // and we did not want to embed the knowledge about this in
5418 // the caller routine. This only avoids double error reporting.
5422 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
5423 GetSignatureForError ());
5427 if (TypeManager.GetParameterData (setter).Count != 1){
5428 Error_PropertyNotFound (setter, false);
5432 bool must_do_cs1540_check;
5433 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
5434 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
5435 if (pm != null && pm.HasCustomAccessModifier) {
5436 Report.SymbolRelatedToPreviousError (pm);
5437 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5438 TypeManager.CSharpSignature (setter));
5441 Report.SymbolRelatedToPreviousError (setter);
5442 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
5447 if (!InstanceResolve (ec, PropertyInfo.DeclaringType.IsValueType, must_do_cs1540_check))
5451 // Only base will allow this invocation to happen.
5453 if (IsBase && setter.IsAbstract){
5454 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5461 public override void Emit (EmitContext ec)
5466 public void Emit (EmitContext ec, bool leave_copy)
5469 // Special case: length of single dimension array property is turned into ldlen
5471 if (IsSingleDimensionalArrayLength ()) {
5473 EmitInstance (ec, false);
5474 ec.ig.Emit (OpCodes.Ldlen);
5475 ec.ig.Emit (OpCodes.Conv_I4);
5479 Invocation.EmitCall (ec, IsBase, InstanceExpression, getter, null, loc, prepared, false);
5482 ec.ig.Emit (OpCodes.Dup);
5484 temp = new LocalTemporary (this.Type);
5491 // Implements the IAssignMethod interface for assignments
5493 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5495 Expression my_source = source;
5497 if (prepare_for_load) {
5502 ec.ig.Emit (OpCodes.Dup);
5504 temp = new LocalTemporary (this.Type);
5508 } else if (leave_copy) {
5510 temp = new LocalTemporary (this.Type);
5515 ArrayList args = new ArrayList (1);
5516 args.Add (new Argument (my_source, Argument.AType.Expression));
5518 Invocation.EmitCall (ec, IsBase, InstanceExpression, setter, args, loc, false, prepared);
5528 /// Fully resolved expression that evaluates to an Event
5530 public class EventExpr : MemberExpr {
5531 public readonly EventInfo EventInfo;
5534 MethodInfo add_accessor, remove_accessor;
5536 public EventExpr (EventInfo ei, Location loc)
5540 eclass = ExprClass.EventAccess;
5542 add_accessor = TypeManager.GetAddMethod (ei);
5543 remove_accessor = TypeManager.GetRemoveMethod (ei);
5544 if (add_accessor.IsStatic || remove_accessor.IsStatic)
5547 if (EventInfo is MyEventBuilder){
5548 MyEventBuilder eb = (MyEventBuilder) EventInfo;
5549 type = eb.EventType;
5552 type = EventInfo.EventHandlerType;
5555 public override string Name {
5557 return EventInfo.Name;
5561 public override bool IsInstance {
5567 public override bool IsStatic {
5573 public override Type DeclaringType {
5575 return EventInfo.DeclaringType;
5579 void Error_AssignmentEventOnly ()
5581 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5582 GetSignatureForError ());
5585 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
5586 SimpleName original)
5589 // If the event is local to this class, we transform ourselves into a FieldExpr
5592 if (EventInfo.DeclaringType == ec.ContainerType ||
5593 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
5594 EventField mi = TypeManager.GetEventField (EventInfo);
5597 if (!ec.IsInObsoleteScope)
5598 mi.CheckObsoleteness (loc);
5600 if ((mi.ModFlags & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0 && !ec.IsInCompoundAssignment)
5601 Error_AssignmentEventOnly ();
5603 FieldExpr ml = new FieldExpr (mi.FieldBuilder, loc);
5605 InstanceExpression = null;
5607 return ml.ResolveMemberAccess (ec, left, loc, original);
5611 if (left is This && !ec.IsInCompoundAssignment)
5612 Error_AssignmentEventOnly ();
5614 return base.ResolveMemberAccess (ec, left, loc, original);
5617 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
5620 InstanceExpression = null;
5624 if (InstanceExpression == null) {
5625 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5629 InstanceExpression = InstanceExpression.DoResolve (ec);
5630 if (InstanceExpression == null)
5633 if (IsBase && add_accessor.IsAbstract) {
5634 Error_CannotCallAbstractBase(TypeManager.CSharpSignature(add_accessor));
5639 // This is using the same mechanism as the CS1540 check in PropertyExpr.
5640 // However, in the Event case, we reported a CS0122 instead.
5642 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
5643 InstanceExpression.Type != ec.ContainerType &&
5644 TypeManager.IsSubclassOf (ec.ContainerType, InstanceExpression.Type)) {
5645 Report.SymbolRelatedToPreviousError (EventInfo);
5646 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5653 public bool IsAccessibleFrom (Type invocation_type)
5656 return IsAccessorAccessible (invocation_type, add_accessor, out dummy) &&
5657 IsAccessorAccessible (invocation_type, remove_accessor, out dummy);
5660 public override Expression CreateExpressionTree (EmitContext ec)
5662 throw new NotSupportedException ("ET");
5665 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5667 // contexts where an LValue is valid have already devolved to FieldExprs
5668 Error_CannotAssign ();
5672 public override Expression DoResolve (EmitContext ec)
5674 bool must_do_cs1540_check;
5675 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
5676 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
5677 Report.SymbolRelatedToPreviousError (EventInfo);
5678 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5682 if (!InstanceResolve (ec, must_do_cs1540_check))
5685 if (!ec.IsInCompoundAssignment) {
5686 Error_CannotAssign ();
5693 public override void Emit (EmitContext ec)
5695 Error_CannotAssign ();
5698 public void Error_CannotAssign ()
5700 Report.Error (70, loc,
5701 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
5702 GetSignatureForError (), TypeManager.CSharpName (EventInfo.DeclaringType));
5705 public override string GetSignatureForError ()
5707 return TypeManager.CSharpSignature (EventInfo);
5710 public void EmitAddOrRemove (EmitContext ec, bool is_add, Expression source)
5712 ArrayList args = new ArrayList (1);
5713 args.Add (new Argument (source, Argument.AType.Expression));
5714 Invocation.EmitCall (ec, IsBase, InstanceExpression, is_add ? add_accessor : remove_accessor, args, loc);
5718 public class TemporaryVariable : VariableReference
5722 public TemporaryVariable (Type type, Location loc)
5726 eclass = ExprClass.Variable;
5729 public override Expression CreateExpressionTree (EmitContext ec)
5731 throw new NotSupportedException ("ET");
5734 public override Expression DoResolve (EmitContext ec)
5739 TypeExpr te = new TypeExpression (type, loc);
5740 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
5741 if (!li.Resolve (ec))
5744 if (ec.MustCaptureVariable (li) && !ec.IsInProbingMode) {
5745 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
5746 storey.CaptureLocalVariable (ec, li);
5752 public override void Emit (EmitContext ec)
5757 public void EmitAssign (EmitContext ec, Expression source)
5759 EmitAssign (ec, source, false, false);
5762 public override HoistedVariable HoistedVariable {
5763 get { return li.HoistedVariableReference; }
5766 public override bool IsFixed {
5767 get { return true; }
5770 public override bool IsRef {
5771 get { return false; }
5774 public override ILocalVariable Variable {
5778 public override VariableInfo VariableInfo {
5779 get { throw new NotImplementedException (); }
5784 /// Handles `var' contextual keyword; var becomes a keyword only
5785 /// if no type called var exists in a variable scope
5787 public class VarExpr : SimpleName
5789 // Used for error reporting only
5790 ArrayList initializer;
5792 public VarExpr (Location loc)
5797 public ArrayList VariableInitializer {
5799 this.initializer = value;
5803 public bool InferType (EmitContext ec, Expression right_side)
5806 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
5808 type = right_side.Type;
5809 if (type == TypeManager.null_type || type == TypeManager.void_type || type == TypeManager.anonymous_method_type) {
5810 Report.Error (815, loc, "An implicitly typed local variable declaration cannot be initialized with `{0}'",
5811 right_side.GetSignatureForError ());
5815 eclass = ExprClass.Variable;
5819 protected override void Error_TypeOrNamespaceNotFound (IResolveContext ec)
5821 Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");
5824 public override TypeExpr ResolveAsContextualType (IResolveContext rc, bool silent)
5826 TypeExpr te = base.ResolveAsContextualType (rc, true);
5830 if (initializer == null)
5833 if (initializer.Count > 1) {
5834 Location loc = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [1]).Location;
5835 Report.Error (819, loc, "An implicitly typed local variable declaration cannot include multiple declarators");
5840 Expression variable_initializer = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [0]).expression_or_array_initializer;
5841 if (variable_initializer == null) {
5842 Report.Error (818, loc, "An implicitly typed local variable declarator must include an initializer");