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 {
2089 public OpcodeCast (Expression child, Type return_type, OpCode op)
2090 : base (child, return_type)
2095 public override Expression DoResolve (EmitContext ec)
2097 // This should never be invoked, we are born in fully
2098 // initialized state.
2103 public override void Emit (EmitContext ec)
2109 public Type UnderlyingType {
2110 get { return child.Type; }
2115 /// This kind of cast is used to encapsulate a child and cast it
2116 /// to the class requested
2118 public sealed class ClassCast : TypeCast {
2119 Type child_generic_parameter;
2121 public ClassCast (Expression child, Type return_type)
2122 : base (child, return_type)
2125 if (TypeManager.IsGenericParameter (child.Type))
2126 child_generic_parameter = child.Type;
2129 public override Expression DoResolve (EmitContext ec)
2131 // This should never be invoked, we are born in fully
2132 // initialized state.
2137 public override void Emit (EmitContext ec)
2141 if (child_generic_parameter != null)
2142 ec.ig.Emit (OpCodes.Box, child_generic_parameter);
2145 if (type.IsGenericParameter)
2146 ec.ig.Emit (OpCodes.Unbox_Any, type);
2149 ec.ig.Emit (OpCodes.Castclass, type);
2152 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2154 type = storey.MutateType (type);
2155 if (child_generic_parameter != null)
2156 child_generic_parameter = storey.MutateGenericArgument (child_generic_parameter);
2158 base.MutateHoistedGenericType (storey);
2163 // Used when resolved expression has different representations for
2164 // expression trees and emit phase
2166 public class ReducedExpression : Expression
2168 class ReducedConstantExpression : Constant
2170 readonly Constant expr;
2171 readonly Expression orig_expr;
2173 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2174 : base (expr.Location)
2177 this.orig_expr = orig_expr;
2178 eclass = expr.eclass;
2182 public override string AsString ()
2184 return expr.AsString ();
2187 public override Expression CreateExpressionTree (EmitContext ec)
2189 return orig_expr.CreateExpressionTree (ec);
2192 public override object GetValue ()
2194 return expr.GetValue ();
2197 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
2199 throw new NotImplementedException ();
2202 public override Expression DoResolve (EmitContext ec)
2207 public override Constant Increment ()
2209 throw new NotImplementedException ();
2212 public override bool IsDefaultValue {
2214 return expr.IsDefaultValue;
2218 public override bool IsNegative {
2220 return expr.IsNegative;
2224 public override void Emit (EmitContext ec)
2230 readonly Expression expr, orig_expr;
2232 private ReducedExpression (Expression expr, Expression orig_expr)
2235 this.orig_expr = orig_expr;
2236 this.loc = orig_expr.Location;
2239 public static Expression Create (Constant expr, Expression original_expr)
2241 return new ReducedConstantExpression (expr, original_expr);
2244 public static Expression Create (Expression expr, Expression original_expr)
2246 Constant c = expr as Constant;
2248 return Create (c, original_expr);
2250 return new ReducedExpression (expr, original_expr);
2253 public override Expression CreateExpressionTree (EmitContext ec)
2255 return orig_expr.CreateExpressionTree (ec);
2258 public override Expression DoResolve (EmitContext ec)
2260 eclass = expr.eclass;
2265 public override void Emit (EmitContext ec)
2270 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2272 expr.EmitBranchable (ec, target, on_true);
2277 // Unresolved type name expressions
2279 public abstract class ATypeNameExpression : FullNamedExpression
2281 public readonly string Name;
2282 protected TypeArguments targs;
2284 protected ATypeNameExpression (string name, Location l)
2290 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2297 public bool HasTypeArguments {
2299 return targs != null;
2303 public override string GetSignatureForError ()
2305 if (targs != null) {
2306 return TypeManager.RemoveGenericArity (Name) + "<" +
2307 targs.GetSignatureForError () + ">";
2315 /// SimpleName expressions are formed of a single word and only happen at the beginning
2316 /// of a dotted-name.
2318 public class SimpleName : ATypeNameExpression {
2321 public SimpleName (string name, Location l)
2326 public SimpleName (string name, TypeArguments args, Location l)
2327 : base (name, args, l)
2331 public SimpleName (string name, TypeParameter[] type_params, Location l)
2334 targs = new TypeArguments (l);
2335 foreach (TypeParameter type_param in type_params)
2336 targs.Add (new TypeParameterExpr (type_param, l));
2339 public static string RemoveGenericArity (string name)
2342 StringBuilder sb = null;
2344 int pos = name.IndexOf ('`', start);
2349 sb.Append (name.Substring (start));
2354 sb = new StringBuilder ();
2355 sb.Append (name.Substring (start, pos-start));
2358 while ((pos < name.Length) && Char.IsNumber (name [pos]))
2362 } while (start < name.Length);
2364 return sb.ToString ();
2367 public SimpleName GetMethodGroup ()
2369 return new SimpleName (RemoveGenericArity (Name), targs, loc);
2372 public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
2374 if (ec.IsInFieldInitializer)
2375 Report.Error (236, l,
2376 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2380 120, l, "`{0}': An object reference is required for the nonstatic field, method or property",
2384 public bool IdenticalNameAndTypeName (EmitContext ec, Expression resolved_to, Location loc)
2386 return resolved_to != null && resolved_to.Type != null &&
2387 resolved_to.Type.Name == Name &&
2388 (ec.DeclContainer.LookupNamespaceOrType (Name, loc, /* ignore_cs0104 = */ true) != null);
2391 public override Expression DoResolve (EmitContext ec)
2393 return SimpleNameResolve (ec, null, false);
2396 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
2398 return SimpleNameResolve (ec, right_side, false);
2402 public Expression DoResolve (EmitContext ec, bool intermediate)
2404 return SimpleNameResolve (ec, null, intermediate);
2407 static bool IsNestedChild (Type t, Type parent)
2409 while (parent != null) {
2410 if (TypeManager.IsNestedChildOf (t, TypeManager.DropGenericTypeArguments (parent)))
2413 parent = parent.BaseType;
2419 FullNamedExpression ResolveNested (IResolveContext ec, Type t)
2421 if (!TypeManager.IsGenericTypeDefinition (t) && !TypeManager.IsGenericType (t))
2424 DeclSpace ds = ec.DeclContainer;
2425 while (ds != null && !IsNestedChild (t, ds.TypeBuilder))
2431 Type[] gen_params = TypeManager.GetTypeArguments (t);
2433 int arg_count = targs != null ? targs.Count : 0;
2435 for (; (ds != null) && ds.IsGeneric; ds = ds.Parent) {
2436 if (arg_count + ds.CountTypeParameters == gen_params.Length) {
2437 TypeArguments new_args = new TypeArguments (loc);
2438 foreach (TypeParameter param in ds.TypeParameters)
2439 new_args.Add (new TypeParameterExpr (param, loc));
2442 new_args.Add (targs);
2444 return new ConstructedType (t, new_args, loc);
2451 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2453 FullNamedExpression fne = ec.GenericDeclContainer.LookupGeneric (Name, loc);
2455 return fne.ResolveAsTypeStep (ec, silent);
2457 int errors = Report.Errors;
2458 fne = ec.DeclContainer.LookupNamespaceOrType (Name, loc, /*ignore_cs0104=*/ false);
2461 if (fne.Type == null)
2464 FullNamedExpression nested = ResolveNested (ec, fne.Type);
2466 return nested.ResolveAsTypeStep (ec, false);
2468 if (targs != null) {
2469 ConstructedType ct = new ConstructedType (fne, targs, loc);
2470 return ct.ResolveAsTypeStep (ec, false);
2476 if (silent || errors != Report.Errors)
2479 Error_TypeOrNamespaceNotFound (ec);
2483 protected virtual void Error_TypeOrNamespaceNotFound (IResolveContext ec)
2485 MemberCore mc = ec.DeclContainer.GetDefinition (Name);
2487 Error_UnexpectedKind (ec.DeclContainer, "type", GetMemberType (mc), loc);
2491 string ns = ec.DeclContainer.NamespaceEntry.NS.Name;
2492 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2493 foreach (Assembly a in RootNamespace.Global.Assemblies) {
2494 Type type = a.GetType (fullname);
2496 Report.SymbolRelatedToPreviousError (type);
2497 Expression.ErrorIsInaccesible (loc, TypeManager.CSharpName (type));
2502 Type t = ec.DeclContainer.LookupAnyGeneric (Name);
2504 Namespace.Error_InvalidNumberOfTypeArguments (t, loc);
2508 if (targs != null) {
2509 FullNamedExpression retval = ec.DeclContainer.LookupNamespaceOrType (SimpleName.RemoveGenericArity (Name), loc, true);
2510 if (retval != null) {
2511 Namespace.Error_TypeArgumentsCannotBeUsed (retval.Type, loc);
2516 NamespaceEntry.Error_NamespaceNotFound (loc, Name);
2519 // TODO: I am still not convinced about this. If someone else will need it
2520 // implement this as virtual property in MemberCore hierarchy
2521 public static string GetMemberType (MemberCore mc)
2527 if (mc is FieldBase)
2529 if (mc is MethodCore)
2531 if (mc is EnumMember)
2539 Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2545 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2551 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2558 /// 7.5.2: Simple Names.
2560 /// Local Variables and Parameters are handled at
2561 /// parse time, so they never occur as SimpleNames.
2563 /// The `intermediate' flag is used by MemberAccess only
2564 /// and it is used to inform us that it is ok for us to
2565 /// avoid the static check, because MemberAccess might end
2566 /// up resolving the Name as a Type name and the access as
2567 /// a static type access.
2569 /// ie: Type Type; .... { Type.GetType (""); }
2571 /// Type is both an instance variable and a Type; Type.GetType
2572 /// is the static method not an instance method of type.
2574 Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2576 Expression e = null;
2579 // Stage 1: Performed by the parser (binding to locals or parameters).
2581 Block current_block = ec.CurrentBlock;
2582 if (current_block != null){
2583 LocalInfo vi = current_block.GetLocalInfo (Name);
2585 if (targs != null) {
2586 Report.Error (307, loc,
2587 "The variable `{0}' cannot be used with type arguments",
2592 LocalVariableReference var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2593 if (right_side != null) {
2594 return var.ResolveLValue (ec, right_side, loc);
2596 ResolveFlags rf = ResolveFlags.VariableOrValue;
2598 rf |= ResolveFlags.DisableFlowAnalysis;
2599 return var.Resolve (ec, rf);
2603 ParameterReference pref = current_block.Toplevel.GetParameterReference (Name, loc);
2605 if (targs != null) {
2606 Report.Error (307, loc,
2607 "The variable `{0}' cannot be used with type arguments",
2612 if (right_side != null)
2613 return pref.ResolveLValue (ec, right_side, loc);
2615 return pref.Resolve (ec);
2618 Expression expr = current_block.Toplevel.GetTransparentIdentifier (Name);
2620 if (right_side != null)
2621 return expr.ResolveLValue (ec, right_side, loc);
2622 return expr.Resolve (ec);
2627 // Stage 2: Lookup members
2630 Type almost_matched_type = null;
2631 ArrayList almost_matched = null;
2632 for (DeclSpace lookup_ds = ec.DeclContainer; lookup_ds != null; lookup_ds = lookup_ds.Parent) {
2633 // either RootDeclSpace or GenericMethod
2634 if (lookup_ds.TypeBuilder == null)
2637 e = MemberLookup (ec.ContainerType, lookup_ds.TypeBuilder, Name, loc);
2639 if (e is PropertyExpr) {
2640 // since TypeManager.MemberLookup doesn't know if we're doing a lvalue access or not,
2641 // it doesn't know which accessor to check permissions against
2642 if (((PropertyExpr) e).IsAccessibleFrom (ec.ContainerType, right_side != null))
2644 } else if (e is EventExpr) {
2645 if (((EventExpr) e).IsAccessibleFrom (ec.ContainerType))
2653 if (almost_matched == null && almost_matched_members.Count > 0) {
2654 almost_matched_type = lookup_ds.TypeBuilder;
2655 almost_matched = (ArrayList) almost_matched_members.Clone ();
2660 if (almost_matched == null && almost_matched_members.Count > 0) {
2661 almost_matched_type = ec.ContainerType;
2662 almost_matched = (ArrayList) almost_matched_members.Clone ();
2664 e = ResolveAsTypeStep (ec, true);
2668 if (current_block != null) {
2669 IKnownVariable ikv = current_block.Explicit.GetKnownVariable (Name);
2671 LocalInfo li = ikv as LocalInfo;
2672 // Supress CS0219 warning
2676 Error_VariableIsUsedBeforeItIsDeclared (Name);
2681 if (almost_matched != null)
2682 almost_matched_members = almost_matched;
2683 if (almost_matched_type == null)
2684 almost_matched_type = ec.ContainerType;
2685 Error_MemberLookupFailed (ec.ContainerType, null, almost_matched_type, Name,
2686 ec.DeclContainer.Name, AllMemberTypes, AllBindingFlags);
2690 if (e is TypeExpr) {
2694 ConstructedType ct = new ConstructedType (
2695 e.Type, targs, loc);
2696 return ct.ResolveAsTypeStep (ec, false);
2699 if (e is MemberExpr) {
2700 MemberExpr me = (MemberExpr) e;
2703 if (me.IsInstance) {
2704 if (ec.IsStatic || ec.IsInFieldInitializer) {
2706 // Note that an MemberExpr can be both IsInstance and IsStatic.
2707 // An unresolved MethodGroupExpr can contain both kinds of methods
2708 // and each predicate is true if the MethodGroupExpr contains
2709 // at least one of that kind of method.
2713 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2714 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2719 // Pass the buck to MemberAccess and Invocation.
2721 left = EmptyExpression.Null;
2723 left = ec.GetThis (loc);
2726 left = new TypeExpression (ec.ContainerType, loc);
2729 me = me.ResolveMemberAccess (ec, left, loc, null);
2733 if (targs != null) {
2735 me.SetTypeArguments (targs);
2738 if (!me.IsStatic && (me.InstanceExpression != null) &&
2739 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2740 me.InstanceExpression.Type != me.DeclaringType &&
2741 !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2742 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2743 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2744 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2748 return (right_side != null)
2749 ? me.DoResolveLValue (ec, right_side)
2750 : me.DoResolve (ec);
2756 protected override void CloneTo (CloneContext clonectx, Expression target)
2758 // CloneTo: Nothing, we do not keep any state on this expression
2763 /// Represents a namespace or a type. The name of the class was inspired by
2764 /// section 10.8.1 (Fully Qualified Names).
2766 public abstract class FullNamedExpression : Expression {
2768 public override Expression CreateExpressionTree (EmitContext ec)
2770 throw new NotSupportedException ("ET");
2773 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2778 public override void Emit (EmitContext ec)
2780 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2781 GetSignatureForError ());
2786 /// Expression that evaluates to a type
2788 public abstract class TypeExpr : FullNamedExpression {
2789 override public FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2791 TypeExpr t = DoResolveAsTypeStep (ec);
2795 eclass = ExprClass.Type;
2799 override public Expression DoResolve (EmitContext ec)
2801 return ResolveAsTypeTerminal (ec, false);
2804 public virtual bool CheckAccessLevel (DeclSpace ds)
2806 return ds.CheckAccessLevel (Type);
2809 public virtual bool AsAccessible (DeclSpace ds)
2811 return ds.IsAccessibleAs (Type);
2814 public virtual bool IsClass {
2815 get { return Type.IsClass; }
2818 public virtual bool IsValueType {
2819 get { return Type.IsValueType; }
2822 public virtual bool IsInterface {
2823 get { return Type.IsInterface; }
2826 public virtual bool IsSealed {
2827 get { return Type.IsSealed; }
2830 public virtual bool CanInheritFrom ()
2832 if (Type == TypeManager.enum_type ||
2833 (Type == TypeManager.value_type && RootContext.StdLib) ||
2834 Type == TypeManager.multicast_delegate_type ||
2835 Type == TypeManager.delegate_type ||
2836 Type == TypeManager.array_type)
2842 protected abstract TypeExpr DoResolveAsTypeStep (IResolveContext ec);
2844 public override bool Equals (object obj)
2846 TypeExpr tobj = obj as TypeExpr;
2850 return Type == tobj.Type;
2853 public override int GetHashCode ()
2855 return Type.GetHashCode ();
2858 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2860 type = storey.MutateType (type);
2865 /// Fully resolved Expression that already evaluated to a type
2867 public class TypeExpression : TypeExpr {
2868 public TypeExpression (Type t, Location l)
2871 eclass = ExprClass.Type;
2875 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2880 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2887 /// Used to create types from a fully qualified name. These are just used
2888 /// by the parser to setup the core types. A TypeLookupExpression is always
2889 /// classified as a type.
2891 public sealed class TypeLookupExpression : TypeExpr {
2892 readonly string name;
2894 public TypeLookupExpression (string name)
2897 eclass = ExprClass.Type;
2900 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2902 // It's null for corlib compilation only
2904 return DoResolveAsTypeStep (ec);
2909 private class UnexpectedType
2913 // This performes recursive type lookup, providing support for generic types.
2914 // For example, given the type:
2916 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]]
2918 // The types will be checked in the following order:
2921 // System.Collections |
2922 // System.Collections.Generic |
2924 // System | recursive call 1 |
2925 // System.Int32 _| | main method call
2927 // System | recursive call 2 |
2928 // System.String _| |
2930 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]] _|
2932 private Type TypeLookup (IResolveContext ec, string name)
2937 FullNamedExpression resolved = null;
2939 Type recursive_type = null;
2940 while (index < name.Length) {
2941 if (name[index] == '[') {
2946 if (name[index] == '[')
2948 else if (name[index] == ']')
2950 } while (braces > 0);
2951 recursive_type = TypeLookup (ec, name.Substring (open + 1, index - open - 1));
2952 if (recursive_type == null || (recursive_type == typeof(UnexpectedType)))
2953 return recursive_type;
2956 if (name[index] == ',')
2958 else if ((name[index] == '.' && !done) || (index == name.Length && name[0] != '[')) {
2959 string substring = name.Substring(dot, index - dot);
2961 if (resolved == null)
2962 resolved = RootNamespace.Global.Lookup (ec.DeclContainer, substring, Location.Null);
2963 else if (resolved is Namespace)
2964 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
2965 else if (type != null)
2966 type = TypeManager.GetNestedType (type, substring);
2970 if (resolved == null)
2972 else if (type == null && resolved is TypeExpr)
2973 type = resolved.Type;
2980 if (name[0] != '[') {
2981 string substring = name.Substring(dot, index - dot);
2984 return TypeManager.GetNestedType (type, substring);
2986 if (resolved != null) {
2987 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
2988 if (resolved is TypeExpr)
2989 return resolved.Type;
2991 if (resolved == null)
2994 resolved.Error_UnexpectedKind (ec.DeclContainer, "type", loc);
2995 return typeof (UnexpectedType);
3001 return recursive_type;
3004 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
3006 Type t = TypeLookup (ec, name);
3008 NamespaceEntry.Error_NamespaceNotFound (loc, name);
3011 if (t == typeof(UnexpectedType))
3017 protected override void CloneTo (CloneContext clonectx, Expression target)
3019 // CloneTo: Nothing, we do not keep any state on this expression
3022 public override string GetSignatureForError ()
3025 return TypeManager.CSharpName (name);
3027 return base.GetSignatureForError ();
3032 /// Represents an "unbound generic type", ie. typeof (Foo<>).
3035 public class UnboundTypeExpression : TypeExpr
3039 public UnboundTypeExpression (MemberName name, Location l)
3045 protected override void CloneTo (CloneContext clonectx, Expression target)
3050 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
3053 if (name.Left != null) {
3054 Expression lexpr = name.Left.GetTypeExpression ();
3055 expr = new MemberAccess (lexpr, name.Basename);
3057 expr = new SimpleName (name.Basename, loc);
3060 FullNamedExpression fne = expr.ResolveAsTypeStep (ec, false);
3065 return new TypeExpression (type, loc);
3070 /// This class denotes an expression which evaluates to a member
3071 /// of a struct or a class.
3073 public abstract class MemberExpr : Expression
3075 protected bool is_base;
3078 /// The name of this member.
3080 public abstract string Name {
3085 // When base.member is used
3087 public bool IsBase {
3088 get { return is_base; }
3089 set { is_base = value; }
3093 /// Whether this is an instance member.
3095 public abstract bool IsInstance {
3100 /// Whether this is a static member.
3102 public abstract bool IsStatic {
3107 /// The type which declares this member.
3109 public abstract Type DeclaringType {
3114 /// The instance expression associated with this member, if it's a
3115 /// non-static member.
3117 public Expression InstanceExpression;
3119 public static void error176 (Location loc, string name)
3121 Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
3122 "with an instance reference, qualify it with a type name instead", name);
3125 public static void Error_BaseAccessInExpressionTree (Location loc)
3127 Report.Error (831, loc, "An expression tree may not contain a base access");
3130 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3132 if (InstanceExpression != null)
3133 InstanceExpression.MutateHoistedGenericType (storey);
3136 // TODO: possible optimalization
3137 // Cache resolved constant result in FieldBuilder <-> expression map
3138 public virtual MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3139 SimpleName original)
3143 // original == null || original.Resolve (...) ==> left
3146 if (left is TypeExpr) {
3147 left = left.ResolveAsTypeTerminal (ec, true);
3152 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3160 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3163 return ResolveExtensionMemberAccess (left);
3166 InstanceExpression = left;
3170 protected virtual MemberExpr ResolveExtensionMemberAccess (Expression left)
3172 error176 (loc, GetSignatureForError ());
3176 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3181 if (InstanceExpression == EmptyExpression.Null) {
3182 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3186 if (InstanceExpression.Type.IsValueType) {
3187 if (InstanceExpression is IMemoryLocation) {
3188 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
3190 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
3191 InstanceExpression.Emit (ec);
3193 t.AddressOf (ec, AddressOp.Store);
3196 InstanceExpression.Emit (ec);
3198 if (prepare_for_load)
3199 ec.ig.Emit (OpCodes.Dup);
3202 public virtual void SetTypeArguments (TypeArguments ta)
3204 // TODO: need to get correct member type
3205 Report.Error (307, loc, "The property `{0}' cannot be used with type arguments",
3206 GetSignatureForError ());
3211 /// Represents group of extension methods
3213 public class ExtensionMethodGroupExpr : MethodGroupExpr
3215 readonly NamespaceEntry namespace_entry;
3216 public Expression ExtensionExpression;
3217 Argument extension_argument;
3219 public ExtensionMethodGroupExpr (ArrayList list, NamespaceEntry n, Type extensionType, Location l)
3220 : base (list, extensionType, l)
3222 this.namespace_entry = n;
3225 public override bool IsStatic {
3226 get { return true; }
3229 public bool IsTopLevel {
3230 get { return namespace_entry == null; }
3233 public override void EmitArguments (EmitContext ec, ArrayList arguments)
3235 if (arguments == null)
3236 arguments = new ArrayList (1);
3237 arguments.Insert (0, extension_argument);
3238 base.EmitArguments (ec, arguments);
3241 public override void EmitCall (EmitContext ec, ArrayList arguments)
3243 if (arguments == null)
3244 arguments = new ArrayList (1);
3245 arguments.Insert (0, extension_argument);
3246 base.EmitCall (ec, arguments);
3249 public override MethodGroupExpr OverloadResolve (EmitContext ec, ref ArrayList arguments, bool may_fail, Location loc)
3251 if (arguments == null)
3252 arguments = new ArrayList (1);
3254 arguments.Insert (0, new Argument (ExtensionExpression));
3255 MethodGroupExpr mg = ResolveOverloadExtensions (ec, arguments, namespace_entry, loc);
3257 // Store resolved argument and restore original arguments
3259 ((ExtensionMethodGroupExpr)mg).extension_argument = (Argument)arguments [0];
3260 arguments.RemoveAt (0);
3265 MethodGroupExpr ResolveOverloadExtensions (EmitContext ec, ArrayList arguments, NamespaceEntry ns, Location loc)
3267 // Use normal resolve rules
3268 MethodGroupExpr mg = base.OverloadResolve (ec, ref arguments, ns != null, loc);
3276 ExtensionMethodGroupExpr e = ns.LookupExtensionMethod (type, null, Name, loc);
3278 return base.OverloadResolve (ec, ref arguments, false, loc);
3280 e.ExtensionExpression = ExtensionExpression;
3281 e.SetTypeArguments (type_arguments);
3282 return e.ResolveOverloadExtensions (ec, arguments, e.namespace_entry, loc);
3287 /// MethodGroupExpr represents a group of method candidates which
3288 /// can be resolved to the best method overload
3290 public class MethodGroupExpr : MemberExpr
3292 public interface IErrorHandler
3294 bool NoExactMatch (EmitContext ec, MethodBase method);
3297 public IErrorHandler CustomErrorHandler;
3298 public MethodBase [] Methods;
3299 MethodBase best_candidate;
3300 // TODO: make private
3301 public TypeArguments type_arguments;
3302 bool identical_type_name;
3305 public MethodGroupExpr (MemberInfo [] mi, Type type, Location l)
3308 Methods = new MethodBase [mi.Length];
3309 mi.CopyTo (Methods, 0);
3312 public MethodGroupExpr (ArrayList list, Type type, Location l)
3316 Methods = (MethodBase[])list.ToArray (typeof (MethodBase));
3318 foreach (MemberInfo m in list){
3319 if (!(m is MethodBase)){
3320 Console.WriteLine ("Name " + m.Name);
3321 Console.WriteLine ("Found a: " + m.GetType ().FullName);
3330 protected MethodGroupExpr (Type type, Location loc)
3333 eclass = ExprClass.MethodGroup;
3337 public override Type DeclaringType {
3340 // We assume that the top-level type is in the end
3342 return Methods [Methods.Length - 1].DeclaringType;
3343 //return Methods [0].DeclaringType;
3347 public Type DelegateType {
3349 delegate_type = value;
3353 public bool IdenticalTypeName {
3355 return identical_type_name;
3359 identical_type_name = value;
3363 public override string GetSignatureForError ()
3365 if (best_candidate != null)
3366 return TypeManager.CSharpSignature (best_candidate);
3368 return TypeManager.CSharpSignature (Methods [0]);
3371 public override string Name {
3373 return Methods [0].Name;
3377 public override bool IsInstance {
3379 if (best_candidate != null)
3380 return !best_candidate.IsStatic;
3382 foreach (MethodBase mb in Methods)
3390 public override bool IsStatic {
3392 if (best_candidate != null)
3393 return best_candidate.IsStatic;
3395 foreach (MethodBase mb in Methods)
3403 public static explicit operator ConstructorInfo (MethodGroupExpr mg)
3405 return (ConstructorInfo)mg.best_candidate;
3408 public static explicit operator MethodInfo (MethodGroupExpr mg)
3410 return (MethodInfo)mg.best_candidate;
3414 // 7.4.3.3 Better conversion from expression
3415 // Returns : 1 if a->p is better,
3416 // 2 if a->q is better,
3417 // 0 if neither is better
3419 static int BetterExpressionConversion (EmitContext ec, Argument a, Type p, Type q)
3421 Type argument_type = TypeManager.TypeToCoreType (a.Type);
3422 if (argument_type == TypeManager.anonymous_method_type && RootContext.Version > LanguageVersion.ISO_2) {
3424 // Uwrap delegate from Expression<T>
3426 if (TypeManager.DropGenericTypeArguments (p) == TypeManager.expression_type) {
3427 p = TypeManager.GetTypeArguments (p) [0];
3429 if (TypeManager.DropGenericTypeArguments (q) == TypeManager.expression_type) {
3430 q = TypeManager.GetTypeArguments (q) [0];
3433 p = Delegate.GetInvokeMethod (null, p).ReturnType;
3434 q = Delegate.GetInvokeMethod (null, q).ReturnType;
3436 if (argument_type == p)
3439 if (argument_type == q)
3443 return BetterTypeConversion (ec, p, q);
3447 // 7.4.3.4 Better conversion from type
3449 public static int BetterTypeConversion (EmitContext ec, Type p, Type q)
3451 if (p == null || q == null)
3452 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3454 if (p == TypeManager.int32_type) {
3455 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3457 } else if (p == TypeManager.int64_type) {
3458 if (q == TypeManager.uint64_type)
3460 } else if (p == TypeManager.sbyte_type) {
3461 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3462 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3464 } else if (p == TypeManager.short_type) {
3465 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3466 q == TypeManager.uint64_type)
3470 if (q == TypeManager.int32_type) {
3471 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3473 } if (q == TypeManager.int64_type) {
3474 if (p == TypeManager.uint64_type)
3476 } else if (q == TypeManager.sbyte_type) {
3477 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3478 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3480 } if (q == TypeManager.short_type) {
3481 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3482 p == TypeManager.uint64_type)
3486 // TODO: this is expensive
3487 Expression p_tmp = new EmptyExpression (p);
3488 Expression q_tmp = new EmptyExpression (q);
3490 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3491 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3493 if (p_to_q && !q_to_p)
3496 if (q_to_p && !p_to_q)
3503 /// Determines "Better function" between candidate
3504 /// and the current best match
3507 /// Returns a boolean indicating :
3508 /// false if candidate ain't better
3509 /// true if candidate is better than the current best match
3511 static bool BetterFunction (EmitContext ec, ArrayList args, int argument_count,
3512 MethodBase candidate, bool candidate_params,
3513 MethodBase best, bool best_params)
3515 ParameterData candidate_pd = TypeManager.GetParameterData (candidate);
3516 ParameterData best_pd = TypeManager.GetParameterData (best);
3518 bool better_at_least_one = false;
3520 for (int j = 0, c_idx = 0, b_idx = 0; j < argument_count; ++j, ++c_idx, ++b_idx)
3522 Argument a = (Argument) args [j];
3524 Type ct = TypeManager.TypeToCoreType (candidate_pd.ParameterType (c_idx));
3525 Type bt = TypeManager.TypeToCoreType (best_pd.ParameterType (b_idx));
3527 if (candidate_params && candidate_pd.ParameterModifier (c_idx) == Parameter.Modifier.PARAMS)
3529 ct = TypeManager.GetElementType (ct);
3533 if (best_params && best_pd.ParameterModifier (b_idx) == Parameter.Modifier.PARAMS)
3535 bt = TypeManager.GetElementType (bt);
3543 int result = BetterExpressionConversion (ec, a, ct, bt);
3545 // for each argument, the conversion to 'ct' should be no worse than
3546 // the conversion to 'bt'.
3550 // for at least one argument, the conversion to 'ct' should be better than
3551 // the conversion to 'bt'.
3553 better_at_least_one = true;
3556 if (better_at_least_one)
3560 // This handles the case
3562 // Add (float f1, float f2, float f3);
3563 // Add (params decimal [] foo);
3565 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3566 // first candidate would've chosen as better.
3572 // The two methods have equal parameter types. Now apply tie-breaking rules
3574 if (TypeManager.IsGenericMethod (best) && !TypeManager.IsGenericMethod (candidate))
3576 if (!TypeManager.IsGenericMethod (best) && TypeManager.IsGenericMethod (candidate))
3580 // This handles the following cases:
3582 // Trim () is better than Trim (params char[] chars)
3583 // Concat (string s1, string s2, string s3) is better than
3584 // Concat (string s1, params string [] srest)
3585 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3587 if (!candidate_params && best_params)
3589 if (candidate_params && !best_params)
3592 int candidate_param_count = candidate_pd.Count;
3593 int best_param_count = best_pd.Count;
3595 if (candidate_param_count != best_param_count)
3596 // can only happen if (candidate_params && best_params)
3597 return candidate_param_count > best_param_count;
3600 // now, both methods have the same number of parameters, and the parameters have the same types
3601 // Pick the "more specific" signature
3604 MethodBase orig_candidate = TypeManager.DropGenericMethodArguments (candidate);
3605 MethodBase orig_best = TypeManager.DropGenericMethodArguments (best);
3607 ParameterData orig_candidate_pd = TypeManager.GetParameterData (orig_candidate);
3608 ParameterData orig_best_pd = TypeManager.GetParameterData (orig_best);
3610 bool specific_at_least_once = false;
3611 for (int j = 0; j < candidate_param_count; ++j)
3613 Type ct = TypeManager.TypeToCoreType (orig_candidate_pd.ParameterType (j));
3614 Type bt = TypeManager.TypeToCoreType (orig_best_pd.ParameterType (j));
3617 Type specific = MoreSpecific (ct, bt);
3621 specific_at_least_once = true;
3624 if (specific_at_least_once)
3627 // FIXME: handle lifted operators
3633 protected override MemberExpr ResolveExtensionMemberAccess (Expression left)
3636 return base.ResolveExtensionMemberAccess (left);
3639 // When left side is an expression and at least one candidate method is
3640 // static, it can be extension method
3642 InstanceExpression = left;
3646 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3647 SimpleName original)
3649 if (!(left is TypeExpr) &&
3650 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3651 IdenticalTypeName = true;
3653 return base.ResolveMemberAccess (ec, left, loc, original);
3656 public override Expression CreateExpressionTree (EmitContext ec)
3658 if (best_candidate == null) {
3659 Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3663 if (best_candidate.IsConstructor)
3664 return new TypeOfConstructorInfo (best_candidate, loc);
3666 IMethodData md = TypeManager.GetMethod (best_candidate);
3667 if (md != null && md.IsExcluded ())
3668 Report.Error (765, loc,
3669 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3671 return new TypeOfMethodInfo (best_candidate, loc);
3674 override public Expression DoResolve (EmitContext ec)
3676 if (InstanceExpression != null) {
3677 InstanceExpression = InstanceExpression.DoResolve (ec);
3678 if (InstanceExpression == null)
3685 public void ReportUsageError ()
3687 Report.Error (654, loc, "Method `" + DeclaringType + "." +
3688 Name + "()' is referenced without parentheses");
3691 override public void Emit (EmitContext ec)
3693 ReportUsageError ();
3696 public virtual void EmitArguments (EmitContext ec, ArrayList arguments)
3698 Invocation.EmitArguments (ec, arguments, false, null);
3701 public virtual void EmitCall (EmitContext ec, ArrayList arguments)
3703 Invocation.EmitCall (ec, IsBase, InstanceExpression, best_candidate, arguments, loc);
3706 protected virtual void Error_InvalidArguments (EmitContext ec, Location loc, int idx, MethodBase method,
3707 Argument a, ParameterData expected_par, Type paramType)
3709 if (a is CollectionElementInitializer.ElementInitializerArgument) {
3710 Report.SymbolRelatedToPreviousError (method);
3711 if ((expected_par.ParameterModifier (idx) & Parameter.Modifier.ISBYREF) != 0) {
3712 Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
3713 TypeManager.CSharpSignature (method));
3716 Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
3717 TypeManager.CSharpSignature (method));
3718 } else if (delegate_type == null) {
3719 Report.SymbolRelatedToPreviousError (method);
3720 Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
3721 TypeManager.CSharpSignature (method));
3723 Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
3724 TypeManager.CSharpName (delegate_type));
3726 Parameter.Modifier mod = expected_par.ParameterModifier (idx);
3728 string index = (idx + 1).ToString ();
3729 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
3730 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
3731 if ((mod & Parameter.Modifier.ISBYREF) == 0)
3732 Report.Error (1615, loc, "Argument `{0}' should not be passed with the `{1}' keyword",
3733 index, Parameter.GetModifierSignature (a.Modifier));
3735 Report.Error (1620, loc, "Argument `{0}' must be passed with the `{1}' keyword",
3736 index, Parameter.GetModifierSignature (mod));
3738 string p1 = a.GetSignatureForError ();
3739 string p2 = TypeManager.CSharpName (paramType);
3742 Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
3743 Report.SymbolRelatedToPreviousError (a.Expr.Type);
3744 Report.SymbolRelatedToPreviousError (paramType);
3746 Report.Error (1503, loc, "Argument {0}: Cannot convert type `{1}' to `{2}'", index, p1, p2);
3750 public override void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl)
3752 Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3753 Name, TypeManager.CSharpName (target));
3756 protected virtual int GetApplicableParametersCount (MethodBase method, ParameterData parameters)
3758 return parameters.Count;
3761 public static bool IsAncestralType (Type first_type, Type second_type)
3763 return first_type != second_type &&
3764 (TypeManager.IsSubclassOf (second_type, first_type) ||
3765 TypeManager.ImplementsInterface (second_type, first_type));
3769 /// Determines if the candidate method is applicable (section 14.4.2.1)
3770 /// to the given set of arguments
3771 /// A return value rates candidate method compatibility,
3772 /// 0 = the best, int.MaxValue = the worst
3774 public int IsApplicable (EmitContext ec,
3775 ArrayList arguments, int arg_count, ref MethodBase method, ref bool params_expanded_form)
3777 MethodBase candidate = method;
3779 ParameterData pd = TypeManager.GetParameterData (candidate);
3780 int param_count = GetApplicableParametersCount (candidate, pd);
3782 if (arg_count != param_count) {
3784 return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
3785 if (arg_count < param_count - 1)
3786 return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
3791 // 1. Handle generic method using type arguments when specified or type inference
3793 if (TypeManager.IsGenericMethod (candidate)) {
3794 if (type_arguments != null) {
3795 Type [] g_args = candidate.GetGenericArguments ();
3796 if (g_args.Length != type_arguments.Count)
3797 return int.MaxValue - 20000 + Math.Abs (type_arguments.Count - g_args.Length);
3799 // TODO: Don't create new method, create Parameters only
3800 method = ((MethodInfo) candidate).MakeGenericMethod (type_arguments.Arguments);
3802 pd = TypeManager.GetParameterData (candidate);
3804 int score = TypeManager.InferTypeArguments (ec, arguments, ref candidate);
3806 return score - 20000;
3808 if (TypeManager.IsGenericMethodDefinition (candidate))
3809 throw new InternalErrorException ("A generic method `{0}' definition took part in overload resolution",
3810 TypeManager.CSharpSignature (candidate));
3812 pd = TypeManager.GetParameterData (candidate);
3815 if (type_arguments != null)
3816 return int.MaxValue - 15000;
3821 // 2. Each argument has to be implicitly convertible to method parameter
3824 Parameter.Modifier p_mod = 0;
3826 for (int i = 0; i < arg_count; i++) {
3827 Argument a = (Argument) arguments [i];
3828 Parameter.Modifier a_mod = a.Modifier &
3829 ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3831 if (p_mod != Parameter.Modifier.PARAMS) {
3832 p_mod = pd.ParameterModifier (i) & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3834 if (p_mod == Parameter.Modifier.ARGLIST) {
3835 if (a.Type == TypeManager.runtime_argument_handle_type)
3841 pt = pd.ParameterType (i);
3843 params_expanded_form = true;
3847 if (!params_expanded_form)
3848 score = IsArgumentCompatible (ec, a_mod, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
3850 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0) {
3851 // It can be applicable in expanded form
3852 score = IsArgumentCompatible (ec, a_mod, a, 0, pt.GetElementType ());
3854 params_expanded_form = true;
3858 if (params_expanded_form)
3860 return (arg_count - i) * 2 + score;
3864 if (arg_count != param_count)
3865 params_expanded_form = true;
3870 int IsArgumentCompatible (EmitContext ec, Parameter.Modifier arg_mod, Argument argument, Parameter.Modifier param_mod, Type parameter)
3873 // Types have to be identical when ref or out modifer is used
3875 if (arg_mod != 0 || param_mod != 0) {
3876 if (TypeManager.HasElementType (parameter))
3877 parameter = parameter.GetElementType ();
3879 Type a_type = argument.Type;
3880 if (TypeManager.HasElementType (a_type))
3881 a_type = a_type.GetElementType ();
3883 if (a_type != parameter)
3886 if (delegate_type != null ?
3887 !Delegate.IsTypeCovariant (argument.Expr, parameter) :
3888 !Convert.ImplicitConversionExists (ec, argument.Expr, parameter))
3892 if (arg_mod != param_mod)
3898 public static bool IsOverride (MethodBase cand_method, MethodBase base_method)
3900 if (!IsAncestralType (base_method.DeclaringType, cand_method.DeclaringType))
3903 ParameterData cand_pd = TypeManager.GetParameterData (cand_method);
3904 ParameterData base_pd = TypeManager.GetParameterData (base_method);
3906 if (cand_pd.Count != base_pd.Count)
3909 for (int j = 0; j < cand_pd.Count; ++j)
3911 Parameter.Modifier cm = cand_pd.ParameterModifier (j);
3912 Parameter.Modifier bm = base_pd.ParameterModifier (j);
3913 Type ct = TypeManager.TypeToCoreType (cand_pd.ParameterType (j));
3914 Type bt = TypeManager.TypeToCoreType (base_pd.ParameterType (j));
3916 if (cm != bm || ct != bt)
3923 public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2, Location loc)
3925 MemberInfo [] miset;
3926 MethodGroupExpr union;
3931 return (MethodGroupExpr) mg2;
3934 return (MethodGroupExpr) mg1;
3937 MethodGroupExpr left_set = null, right_set = null;
3938 int length1 = 0, length2 = 0;
3940 left_set = (MethodGroupExpr) mg1;
3941 length1 = left_set.Methods.Length;
3943 right_set = (MethodGroupExpr) mg2;
3944 length2 = right_set.Methods.Length;
3946 ArrayList common = new ArrayList ();
3948 foreach (MethodBase r in right_set.Methods){
3949 if (TypeManager.ArrayContainsMethod (left_set.Methods, r))
3953 miset = new MemberInfo [length1 + length2 - common.Count];
3954 left_set.Methods.CopyTo (miset, 0);
3958 foreach (MethodBase r in right_set.Methods) {
3959 if (!common.Contains (r))
3963 union = new MethodGroupExpr (miset, mg1.Type, loc);
3968 static Type MoreSpecific (Type p, Type q)
3970 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
3972 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
3975 if (TypeManager.HasElementType (p))
3977 Type pe = TypeManager.GetElementType (p);
3978 Type qe = TypeManager.GetElementType (q);
3979 Type specific = MoreSpecific (pe, qe);
3985 else if (TypeManager.IsGenericType (p))
3987 Type[] pargs = TypeManager.GetTypeArguments (p);
3988 Type[] qargs = TypeManager.GetTypeArguments (q);
3990 bool p_specific_at_least_once = false;
3991 bool q_specific_at_least_once = false;
3993 for (int i = 0; i < pargs.Length; i++)
3995 Type specific = MoreSpecific (pargs [i], qargs [i]);
3996 if (specific == pargs [i])
3997 p_specific_at_least_once = true;
3998 if (specific == qargs [i])
3999 q_specific_at_least_once = true;
4002 if (p_specific_at_least_once && !q_specific_at_least_once)
4004 if (!p_specific_at_least_once && q_specific_at_least_once)
4011 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4013 base.MutateHoistedGenericType (storey);
4015 MethodInfo mi = best_candidate as MethodInfo;
4017 best_candidate = storey.MutateGenericMethod (mi);
4021 best_candidate = storey.MutateConstructor ((ConstructorInfo) this);
4025 /// Find the Applicable Function Members (7.4.2.1)
4027 /// me: Method Group expression with the members to select.
4028 /// it might contain constructors or methods (or anything
4029 /// that maps to a method).
4031 /// Arguments: ArrayList containing resolved Argument objects.
4033 /// loc: The location if we want an error to be reported, or a Null
4034 /// location for "probing" purposes.
4036 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4037 /// that is the best match of me on Arguments.
4040 public virtual MethodGroupExpr OverloadResolve (EmitContext ec, ref ArrayList Arguments,
4041 bool may_fail, Location loc)
4043 bool method_params = false;
4044 Type applicable_type = null;
4046 ArrayList candidates = new ArrayList (2);
4047 ArrayList candidate_overrides = null;
4050 // Used to keep a map between the candidate
4051 // and whether it is being considered in its
4052 // normal or expanded form
4054 // false is normal form, true is expanded form
4056 Hashtable candidate_to_form = null;
4058 if (Arguments != null)
4059 arg_count = Arguments.Count;
4061 if (RootContext.Version == LanguageVersion.ISO_1 && Name == "Invoke" && TypeManager.IsDelegateType (DeclaringType)) {
4063 Report.Error (1533, loc, "Invoke cannot be called directly on a delegate");
4067 int nmethods = Methods.Length;
4071 // Methods marked 'override' don't take part in 'applicable_type'
4072 // computation, nor in the actual overload resolution.
4073 // However, they still need to be emitted instead of a base virtual method.
4074 // So, we salt them away into the 'candidate_overrides' array.
4076 // In case of reflected methods, we replace each overriding method with
4077 // its corresponding base virtual method. This is to improve compatibility
4078 // with non-C# libraries which change the visibility of overrides (#75636)
4081 for (int i = 0; i < Methods.Length; ++i) {
4082 MethodBase m = Methods [i];
4083 if (TypeManager.IsOverride (m)) {
4084 if (candidate_overrides == null)
4085 candidate_overrides = new ArrayList ();
4086 candidate_overrides.Add (m);
4087 m = TypeManager.TryGetBaseDefinition (m);
4096 // Enable message recording, it's used mainly by lambda expressions
4098 Report.IMessageRecorder msg_recorder = new Report.MessageRecorder ();
4099 Report.IMessageRecorder prev_recorder = Report.SetMessageRecorder (msg_recorder);
4102 // First we construct the set of applicable methods
4104 bool is_sorted = true;
4105 int best_candidate_rate = int.MaxValue;
4106 for (int i = 0; i < nmethods; i++) {
4107 Type decl_type = Methods [i].DeclaringType;
4110 // If we have already found an applicable method
4111 // we eliminate all base types (Section 14.5.5.1)
4113 if (applicable_type != null && IsAncestralType (decl_type, applicable_type))
4117 // Check if candidate is applicable (section 14.4.2.1)
4119 bool params_expanded_form = false;
4120 int candidate_rate = IsApplicable (ec, Arguments, arg_count, ref Methods [i], ref params_expanded_form);
4122 if (candidate_rate < best_candidate_rate) {
4123 best_candidate_rate = candidate_rate;
4124 best_candidate = Methods [i];
4127 if (params_expanded_form) {
4128 if (candidate_to_form == null)
4129 candidate_to_form = new PtrHashtable ();
4130 MethodBase candidate = Methods [i];
4131 candidate_to_form [candidate] = candidate;
4134 if (candidate_rate != 0) {
4135 if (msg_recorder != null)
4136 msg_recorder.EndSession ();
4140 msg_recorder = null;
4141 candidates.Add (Methods [i]);
4143 if (applicable_type == null)
4144 applicable_type = decl_type;
4145 else if (applicable_type != decl_type) {
4147 if (IsAncestralType (applicable_type, decl_type))
4148 applicable_type = decl_type;
4152 Report.SetMessageRecorder (prev_recorder);
4153 if (msg_recorder != null && msg_recorder.PrintMessages ())
4156 int candidate_top = candidates.Count;
4158 if (applicable_type == null) {
4160 // When we found a top level method which does not match and it's
4161 // not an extension method. We start extension methods lookup from here
4163 if (InstanceExpression != null) {
4164 ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (type, Name, loc);
4165 if (ex_method_lookup != null) {
4166 ex_method_lookup.ExtensionExpression = InstanceExpression;
4167 ex_method_lookup.SetTypeArguments (type_arguments);
4168 return ex_method_lookup.OverloadResolve (ec, ref Arguments, may_fail, loc);
4176 // Okay so we have failed to find exact match so we
4177 // return error info about the closest match
4179 if (best_candidate != null) {
4180 if (CustomErrorHandler != null) {
4181 if (CustomErrorHandler.NoExactMatch (ec, best_candidate))
4185 ParameterData pd = TypeManager.GetParameterData (best_candidate);
4186 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4187 if (arg_count == pd.Count || pd.HasParams) {
4188 if (TypeManager.IsGenericMethodDefinition (best_candidate)) {
4189 if (type_arguments == null) {
4190 Report.Error (411, loc,
4191 "The type arguments for method `{0}' cannot be inferred from " +
4192 "the usage. Try specifying the type arguments explicitly",
4193 TypeManager.CSharpSignature (best_candidate));
4197 Type [] g_args = TypeManager.GetGenericArguments (best_candidate);
4198 if (type_arguments.Count != g_args.Length) {
4199 Report.SymbolRelatedToPreviousError (best_candidate);
4200 Report.Error (305, loc, "Using the generic method `{0}' requires `{1}' type argument(s)",
4201 TypeManager.CSharpSignature (best_candidate),
4202 g_args.Length.ToString ());
4206 if (type_arguments != null && !TypeManager.IsGenericMethod (best_candidate)) {
4207 Namespace.Error_TypeArgumentsCannotBeUsed (best_candidate, loc);
4212 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate, cand_params, may_fail, loc))
4217 if (almost_matched_members.Count != 0) {
4218 Error_MemberLookupFailed (ec.ContainerType, type, type, ".ctor",
4219 null, MemberTypes.Constructor, AllBindingFlags);
4224 // We failed to find any method with correct argument count
4226 if (Name == ConstructorInfo.ConstructorName) {
4227 Report.SymbolRelatedToPreviousError (type);
4228 Report.Error (1729, loc,
4229 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4230 TypeManager.CSharpName (type), arg_count);
4232 Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4233 Name, arg_count.ToString ());
4241 // At this point, applicable_type is _one_ of the most derived types
4242 // in the set of types containing the methods in this MethodGroup.
4243 // Filter the candidates so that they only contain methods from the
4244 // most derived types.
4247 int finalized = 0; // Number of finalized candidates
4250 // Invariant: applicable_type is a most derived type
4252 // We'll try to complete Section 14.5.5.1 for 'applicable_type' by
4253 // eliminating all it's base types. At the same time, we'll also move
4254 // every unrelated type to the end of the array, and pick the next
4255 // 'applicable_type'.
4257 Type next_applicable_type = null;
4258 int j = finalized; // where to put the next finalized candidate
4259 int k = finalized; // where to put the next undiscarded candidate
4260 for (int i = finalized; i < candidate_top; ++i) {
4261 MethodBase candidate = (MethodBase) candidates [i];
4262 Type decl_type = candidate.DeclaringType;
4264 if (decl_type == applicable_type) {
4265 candidates [k++] = candidates [j];
4266 candidates [j++] = candidates [i];
4270 if (IsAncestralType (decl_type, applicable_type))
4273 if (next_applicable_type != null &&
4274 IsAncestralType (decl_type, next_applicable_type))
4277 candidates [k++] = candidates [i];
4279 if (next_applicable_type == null ||
4280 IsAncestralType (next_applicable_type, decl_type))
4281 next_applicable_type = decl_type;
4284 applicable_type = next_applicable_type;
4287 } while (applicable_type != null);
4291 // Now we actually find the best method
4294 best_candidate = (MethodBase) candidates [0];
4295 if (delegate_type == null)
4296 method_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4298 for (int ix = 1; ix < candidate_top; ix++) {
4299 MethodBase candidate = (MethodBase) candidates [ix];
4301 if (candidate == best_candidate)
4304 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4306 if (BetterFunction (ec, Arguments, arg_count,
4307 candidate, cand_params,
4308 best_candidate, method_params)) {
4309 best_candidate = candidate;
4310 method_params = cand_params;
4314 // Now check that there are no ambiguities i.e the selected method
4315 // should be better than all the others
4317 MethodBase ambiguous = null;
4318 for (int ix = 1; ix < candidate_top; ix++) {
4319 MethodBase candidate = (MethodBase) candidates [ix];
4321 if (candidate == best_candidate)
4324 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4325 if (!BetterFunction (ec, Arguments, arg_count,
4326 best_candidate, method_params,
4327 candidate, cand_params))
4330 Report.SymbolRelatedToPreviousError (candidate);
4331 ambiguous = candidate;
4335 if (ambiguous != null) {
4336 Report.SymbolRelatedToPreviousError (best_candidate);
4337 Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4338 TypeManager.CSharpSignature (ambiguous), TypeManager.CSharpSignature (best_candidate));
4343 // If the method is a virtual function, pick an override closer to the LHS type.
4345 if (!IsBase && best_candidate.IsVirtual) {
4346 if (TypeManager.IsOverride (best_candidate))
4347 throw new InternalErrorException (
4348 "Should not happen. An 'override' method took part in overload resolution: " + best_candidate);
4350 if (candidate_overrides != null) {
4351 Type[] gen_args = null;
4352 bool gen_override = false;
4353 if (TypeManager.IsGenericMethod (best_candidate))
4354 gen_args = TypeManager.GetGenericArguments (best_candidate);
4356 foreach (MethodBase candidate in candidate_overrides) {
4357 if (TypeManager.IsGenericMethod (candidate)) {
4358 if (gen_args == null)
4361 if (gen_args.Length != TypeManager.GetGenericArguments (candidate).Length)
4364 if (gen_args != null)
4368 if (IsOverride (candidate, best_candidate)) {
4369 gen_override = true;
4370 best_candidate = candidate;
4374 if (gen_override && gen_args != null) {
4376 best_candidate = ((MethodInfo) best_candidate).MakeGenericMethod (gen_args);
4383 // And now check if the arguments are all
4384 // compatible, perform conversions if
4385 // necessary etc. and return if everything is
4388 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate,
4389 method_params, may_fail, loc))
4392 if (best_candidate == null)
4395 MethodBase the_method = TypeManager.DropGenericMethodArguments (best_candidate);
4397 if (the_method.IsGenericMethodDefinition &&
4398 !ConstraintChecker.CheckConstraints (ec, the_method, best_candidate, loc))
4402 IMethodData data = TypeManager.GetMethod (the_method);
4404 data.SetMemberIsUsed ();
4409 public override void SetTypeArguments (TypeArguments ta)
4411 type_arguments = ta;
4414 public bool VerifyArgumentsCompat (EmitContext ec, ref ArrayList arguments,
4415 int arg_count, MethodBase method,
4416 bool chose_params_expanded,
4417 bool may_fail, Location loc)
4419 ParameterData pd = TypeManager.GetParameterData (method);
4421 int errors = Report.Errors;
4422 Parameter.Modifier p_mod = 0;
4424 int a_idx = 0, a_pos = 0;
4426 ArrayList params_initializers = null;
4428 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4429 a = (Argument) arguments [a_idx];
4430 if (p_mod != Parameter.Modifier.PARAMS) {
4431 p_mod = pd.ParameterModifier (a_idx);
4432 pt = pd.ParameterType (a_idx);
4434 if (p_mod == Parameter.Modifier.ARGLIST) {
4435 if (a.Type != TypeManager.runtime_argument_handle_type)
4440 if (pt.IsPointer && !ec.InUnsafe) {
4447 if (p_mod == Parameter.Modifier.PARAMS) {
4448 if (chose_params_expanded) {
4449 params_initializers = new ArrayList (arg_count - a_idx);
4450 pt = TypeManager.GetElementType (pt);
4452 } else if (p_mod != 0) {
4453 pt = TypeManager.GetElementType (pt);
4458 // Types have to be identical when ref or out modifer is used
4460 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4461 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4464 if (!TypeManager.IsEqual (a.Expr.Type, pt))
4471 if (TypeManager.IsEqual (a.Type, pt)) {
4474 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4480 // Convert params arguments to an array initializer
4482 if (params_initializers != null) {
4483 // we choose to use 'a.Expr' rather than 'conv' so that
4484 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
4485 params_initializers.Add (a.Expr);
4486 arguments.RemoveAt (a_idx--);
4491 // Update the argument with the implicit conversion
4496 // Fill not provided arguments required by params modifier
4498 if (params_initializers == null && pd.HasParams && arg_count < pd.Count && a_idx + 1 == pd.Count) {
4499 if (arguments == null)
4500 arguments = new ArrayList (1);
4502 pt = pd.Types [GetApplicableParametersCount (method, pd) - 1];
4503 pt = TypeManager.GetElementType (pt);
4504 params_initializers = new ArrayList (0);
4507 if (a_idx == arg_count) {
4509 // Append an array argument with all params arguments
4511 if (params_initializers != null) {
4512 arguments.Add (new Argument (
4513 new ArrayCreation (new TypeExpression (pt, loc), "[]",
4514 params_initializers, loc).Resolve (ec)));
4519 if (!may_fail && Report.Errors == errors) {
4520 if (CustomErrorHandler != null)
4521 CustomErrorHandler.NoExactMatch (ec, best_candidate);
4523 Error_InvalidArguments (ec, loc, a_pos, method, a, pd, pt);
4529 public class ConstantExpr : MemberExpr
4533 public ConstantExpr (FieldInfo constant, Location loc)
4535 this.constant = constant;
4539 public override string Name {
4540 get { throw new NotImplementedException (); }
4543 public override bool IsInstance {
4544 get { return !IsStatic; }
4547 public override bool IsStatic {
4548 get { return constant.IsStatic; }
4551 public override Type DeclaringType {
4552 get { return constant.DeclaringType; }
4555 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc, SimpleName original)
4557 constant = TypeManager.GetGenericFieldDefinition (constant);
4559 IConstant ic = TypeManager.GetConstant (constant);
4561 if (constant.IsLiteral) {
4562 ic = new ExternalConstant (constant);
4564 ic = ExternalConstant.CreateDecimal (constant);
4565 // HACK: decimal field was not resolved as constant
4567 return new FieldExpr (constant, loc).ResolveMemberAccess (ec, left, loc, original);
4569 TypeManager.RegisterConstant (constant, ic);
4572 return base.ResolveMemberAccess (ec, left, loc, original);
4575 public override Expression CreateExpressionTree (EmitContext ec)
4577 throw new NotSupportedException ("ET");
4580 public override Expression DoResolve (EmitContext ec)
4582 IConstant ic = TypeManager.GetConstant (constant);
4583 if (ic.ResolveValue ()) {
4584 if (!ec.IsInObsoleteScope)
4585 ic.CheckObsoleteness (loc);
4588 return ic.CreateConstantReference (loc);
4591 public override void Emit (EmitContext ec)
4593 throw new NotSupportedException ();
4596 public override string GetSignatureForError ()
4598 return TypeManager.GetFullNameSignature (constant);
4603 /// Fully resolved expression that evaluates to a Field
4605 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariable {
4606 public readonly FieldInfo FieldInfo;
4607 readonly Type constructed_generic_type;
4608 VariableInfo variable_info;
4610 LocalTemporary temp;
4612 bool in_initializer;
4614 public FieldExpr (FieldInfo fi, Location l, bool in_initializer):
4617 this.in_initializer = in_initializer;
4620 public FieldExpr (FieldInfo fi, Location l)
4623 eclass = ExprClass.Variable;
4624 type = TypeManager.TypeToCoreType (fi.FieldType);
4628 public FieldExpr (FieldInfo fi, Type genericType, Location l)
4631 this.constructed_generic_type = genericType;
4634 public override string Name {
4636 return FieldInfo.Name;
4640 public override bool IsInstance {
4642 return !FieldInfo.IsStatic;
4646 public override bool IsStatic {
4648 return FieldInfo.IsStatic;
4652 public override Type DeclaringType {
4654 return FieldInfo.DeclaringType;
4658 public override string GetSignatureForError ()
4660 return TypeManager.GetFullNameSignature (FieldInfo);
4663 public VariableInfo VariableInfo {
4665 return variable_info;
4669 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
4670 SimpleName original)
4672 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
4673 Type t = fi.FieldType;
4675 if (t.IsPointer && !ec.InUnsafe) {
4679 return base.ResolveMemberAccess (ec, left, loc, original);
4682 public override Expression CreateExpressionTree (EmitContext ec)
4684 Expression instance;
4685 if (InstanceExpression == null) {
4686 instance = new NullLiteral (loc);
4688 instance = InstanceExpression.CreateExpressionTree (ec);
4691 ArrayList args = new ArrayList (2);
4692 args.Add (new Argument (instance));
4693 args.Add (new Argument (CreateTypeOfExpression ()));
4694 return CreateExpressionFactoryCall ("Field", args);
4697 public Expression CreateTypeOfExpression ()
4699 return new TypeOfField (FieldInfo, loc);
4702 override public Expression DoResolve (EmitContext ec)
4704 return DoResolve (ec, false, false);
4707 Expression DoResolve (EmitContext ec, bool lvalue_instance, bool out_access)
4709 if (!FieldInfo.IsStatic){
4710 if (InstanceExpression == null){
4712 // This can happen when referencing an instance field using
4713 // a fully qualified type expression: TypeName.InstanceField = xxx
4715 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4719 // Resolve the field's instance expression while flow analysis is turned
4720 // off: when accessing a field "a.b", we must check whether the field
4721 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4723 if (lvalue_instance) {
4724 using (ec.With (EmitContext.Flags.DoFlowAnalysis, false)) {
4725 Expression right_side =
4726 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4727 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side, loc);
4730 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
4731 InstanceExpression = InstanceExpression.Resolve (ec, rf);
4734 if (InstanceExpression == null)
4737 using (ec.Set (EmitContext.Flags.OmitStructFlowAnalysis)) {
4738 InstanceExpression.CheckMarshalByRefAccess (ec);
4742 if (!in_initializer && !ec.IsInFieldInitializer) {
4743 ObsoleteAttribute oa;
4744 FieldBase f = TypeManager.GetField (FieldInfo);
4746 if (!ec.IsInObsoleteScope)
4747 f.CheckObsoleteness (loc);
4749 // To be sure that type is external because we do not register generated fields
4750 } else if (!(FieldInfo.DeclaringType is TypeBuilder)) {
4751 oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
4753 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
4757 IFixedBuffer fb = AttributeTester.GetFixedBuffer (FieldInfo);
4759 if (!ec.InFixedInitializer && ec.ContainerType.IsValueType) {
4760 Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4763 if (InstanceExpression.eclass != ExprClass.Variable) {
4764 Report.SymbolRelatedToPreviousError (FieldInfo);
4765 Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4766 TypeManager.GetFullNameSignature (FieldInfo));
4769 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4772 // If the instance expression is a local variable or parameter.
4773 IVariable var = InstanceExpression as IVariable;
4774 if (var == null || var.VariableInfo == null)
4777 VariableInfo vi = var.VariableInfo;
4778 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
4781 variable_info = vi.GetSubStruct (FieldInfo.Name);
4785 static readonly int [] codes = {
4786 191, // instance, write access
4787 192, // instance, out access
4788 198, // static, write access
4789 199, // static, out access
4790 1648, // member of value instance, write access
4791 1649, // member of value instance, out access
4792 1650, // member of value static, write access
4793 1651 // member of value static, out access
4796 static readonly string [] msgs = {
4797 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4798 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4799 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4800 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4801 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4802 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4803 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4804 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4807 // The return value is always null. Returning a value simplifies calling code.
4808 Expression Report_AssignToReadonly (Expression right_side)
4811 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4815 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4817 Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4822 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4824 IVariable var = InstanceExpression as IVariable;
4825 if (var != null && var.VariableInfo != null)
4826 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
4828 bool lvalue_instance = !FieldInfo.IsStatic && FieldInfo.DeclaringType.IsValueType;
4829 bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
4831 Expression e = DoResolve (ec, lvalue_instance, out_access);
4836 FieldBase fb = TypeManager.GetField (FieldInfo);
4840 if (FieldInfo.IsInitOnly) {
4841 // InitOnly fields can only be assigned in constructors or initializers
4842 if (!ec.IsInFieldInitializer && !ec.IsConstructor)
4843 return Report_AssignToReadonly (right_side);
4845 if (ec.IsConstructor) {
4846 Type ctype = ec.TypeContainer.CurrentType;
4848 ctype = ec.ContainerType;
4850 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4851 if (!TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
4852 return Report_AssignToReadonly (right_side);
4853 // static InitOnly fields cannot be assigned-to in an instance constructor
4854 if (IsStatic && !ec.IsStatic)
4855 return Report_AssignToReadonly (right_side);
4856 // instance constructors can't modify InitOnly fields of other instances of the same type
4857 if (!IsStatic && !(InstanceExpression is This))
4858 return Report_AssignToReadonly (right_side);
4862 if (right_side == EmptyExpression.OutAccess &&
4863 !IsStatic && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type)) {
4864 Report.SymbolRelatedToPreviousError (DeclaringType);
4865 Report.Warning (197, 1, loc,
4866 "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",
4867 GetSignatureForError ());
4873 bool is_marshal_by_ref ()
4875 return !IsStatic && Type.IsValueType && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type);
4878 public override void CheckMarshalByRefAccess (EmitContext ec)
4880 if (is_marshal_by_ref () && !(InstanceExpression is This)) {
4881 Report.SymbolRelatedToPreviousError (DeclaringType);
4882 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",
4883 GetSignatureForError ());
4887 public override int GetHashCode ()
4889 return FieldInfo.GetHashCode ();
4892 public bool IsFixed {
4894 IVariable variable = InstanceExpression as IVariable;
4895 // A variable of the form V.I is fixed when V is a fixed variable of a struct type.
4896 // We defer the InstanceExpression check after the variable check to avoid a
4897 // separate null check on InstanceExpression.
4898 return variable != null && InstanceExpression.Type.IsValueType && variable.IsFixed;
4902 public override bool Equals (object obj)
4904 FieldExpr fe = obj as FieldExpr;
4908 if (FieldInfo != fe.FieldInfo)
4911 if (InstanceExpression == null || fe.InstanceExpression == null)
4914 return InstanceExpression.Equals (fe.InstanceExpression);
4917 public void Emit (EmitContext ec, bool leave_copy)
4919 ILGenerator ig = ec.ig;
4920 bool is_volatile = false;
4922 FieldBase f = TypeManager.GetField (FieldInfo);
4924 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4927 f.SetMemberIsUsed ();
4930 if (FieldInfo.IsStatic){
4932 ig.Emit (OpCodes.Volatile);
4934 ig.Emit (OpCodes.Ldsfld, GetConstructedFieldInfo ());
4937 EmitInstance (ec, false);
4939 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
4941 ig.Emit (OpCodes.Ldflda, GetConstructedFieldInfo ());
4942 ig.Emit (OpCodes.Ldflda, ff.Element);
4945 ig.Emit (OpCodes.Volatile);
4947 ig.Emit (OpCodes.Ldfld, GetConstructedFieldInfo ());
4952 ec.ig.Emit (OpCodes.Dup);
4953 if (!FieldInfo.IsStatic) {
4954 temp = new LocalTemporary (this.Type);
4960 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4962 FieldAttributes fa = FieldInfo.Attributes;
4963 bool is_static = (fa & FieldAttributes.Static) != 0;
4964 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
4965 ILGenerator ig = ec.ig;
4967 if (is_readonly && !ec.IsConstructor){
4968 Report_AssignToReadonly (source);
4972 prepared = prepare_for_load;
4973 EmitInstance (ec, prepared);
4977 ec.ig.Emit (OpCodes.Dup);
4978 if (!FieldInfo.IsStatic) {
4979 temp = new LocalTemporary (this.Type);
4984 FieldBase f = TypeManager.GetField (FieldInfo);
4986 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4987 ig.Emit (OpCodes.Volatile);
4993 ig.Emit (OpCodes.Stsfld, GetConstructedFieldInfo ());
4995 ig.Emit (OpCodes.Stfld, GetConstructedFieldInfo ());
5004 public override void Emit (EmitContext ec)
5009 public override void EmitSideEffect (EmitContext ec)
5011 FieldBase f = TypeManager.GetField (FieldInfo);
5012 bool is_volatile = f != null && (f.ModFlags & Modifiers.VOLATILE) != 0;
5014 if (is_volatile || is_marshal_by_ref ())
5015 base.EmitSideEffect (ec);
5018 public void AddressOf (EmitContext ec, AddressOp mode)
5020 ILGenerator ig = ec.ig;
5022 FieldBase f = TypeManager.GetField (FieldInfo);
5024 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
5025 Report.Warning (420, 1, loc, "`{0}': A volatile field references will not be treated as volatile",
5026 f.GetSignatureForError ());
5029 if ((mode & AddressOp.Store) != 0)
5031 if ((mode & AddressOp.Load) != 0)
5032 f.SetMemberIsUsed ();
5036 // Handle initonly fields specially: make a copy and then
5037 // get the address of the copy.
5040 if (FieldInfo.IsInitOnly){
5042 if (ec.IsConstructor){
5043 if (FieldInfo.IsStatic){
5055 local = ig.DeclareLocal (type);
5056 ig.Emit (OpCodes.Stloc, local);
5057 ig.Emit (OpCodes.Ldloca, local);
5062 if (FieldInfo.IsStatic){
5063 ig.Emit (OpCodes.Ldsflda, GetConstructedFieldInfo ());
5066 EmitInstance (ec, false);
5067 ig.Emit (OpCodes.Ldflda, GetConstructedFieldInfo ());
5071 FieldInfo GetConstructedFieldInfo ()
5073 if (constructed_generic_type == null)
5076 return TypeBuilder.GetField (constructed_generic_type, FieldInfo);
5078 throw new NotSupportedException ();
5085 /// Expression that evaluates to a Property. The Assign class
5086 /// might set the `Value' expression if we are in an assignment.
5088 /// This is not an LValue because we need to re-write the expression, we
5089 /// can not take data from the stack and store it.
5091 public class PropertyExpr : MemberExpr, IAssignMethod {
5092 public readonly PropertyInfo PropertyInfo;
5093 MethodInfo getter, setter;
5098 LocalTemporary temp;
5101 public PropertyExpr (Type container_type, PropertyInfo pi, Location l)
5104 eclass = ExprClass.PropertyAccess;
5108 type = TypeManager.TypeToCoreType (pi.PropertyType);
5110 ResolveAccessors (container_type);
5113 public override string Name {
5115 return PropertyInfo.Name;
5119 public override bool IsInstance {
5125 public override bool IsStatic {
5131 public override Expression CreateExpressionTree (EmitContext ec)
5134 if (IsSingleDimensionalArrayLength ()) {
5135 args = new ArrayList (1);
5136 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5137 return CreateExpressionFactoryCall ("ArrayLength", args);
5141 Error_BaseAccessInExpressionTree (loc);
5145 args = new ArrayList (2);
5146 if (InstanceExpression == null)
5147 args.Add (new Argument (new NullLiteral (loc)));
5149 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5150 args.Add (new Argument (new TypeOfMethodInfo (getter, loc)));
5151 return CreateExpressionFactoryCall ("Property", args);
5154 public Expression CreateSetterTypeOfExpression ()
5156 return new TypeOfMethodInfo (setter, loc);
5159 public override Type DeclaringType {
5161 return PropertyInfo.DeclaringType;
5165 public override string GetSignatureForError ()
5167 return TypeManager.GetFullNameSignature (PropertyInfo);
5170 void FindAccessors (Type invocation_type)
5172 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
5173 BindingFlags.Static | BindingFlags.Instance |
5174 BindingFlags.DeclaredOnly;
5176 Type current = PropertyInfo.DeclaringType;
5177 for (; current != null; current = current.BaseType) {
5178 MemberInfo[] group = TypeManager.MemberLookup (
5179 invocation_type, invocation_type, current,
5180 MemberTypes.Property, flags, PropertyInfo.Name, null);
5185 if (group.Length != 1)
5186 // Oooops, can this ever happen ?
5189 PropertyInfo pi = (PropertyInfo) group [0];
5192 getter = pi.GetGetMethod (true);
5195 setter = pi.GetSetMethod (true);
5197 MethodInfo accessor = getter != null ? getter : setter;
5199 if (!accessor.IsVirtual)
5205 // We also perform the permission checking here, as the PropertyInfo does not
5206 // hold the information for the accessibility of its setter/getter
5208 // TODO: Refactor to use some kind of cache together with GetPropertyFromAccessor
5209 void ResolveAccessors (Type container_type)
5211 FindAccessors (container_type);
5213 if (getter != null) {
5214 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
5215 IMethodData md = TypeManager.GetMethod (the_getter);
5217 md.SetMemberIsUsed ();
5219 is_static = getter.IsStatic;
5222 if (setter != null) {
5223 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
5224 IMethodData md = TypeManager.GetMethod (the_setter);
5226 md.SetMemberIsUsed ();
5228 is_static = setter.IsStatic;
5232 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5234 if (InstanceExpression != null)
5235 InstanceExpression.MutateHoistedGenericType (storey);
5237 type = storey.MutateType (type);
5238 getter = storey.MutateGenericMethod (getter);
5241 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
5244 InstanceExpression = null;
5248 if (InstanceExpression == null) {
5249 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5253 InstanceExpression = InstanceExpression.DoResolve (ec);
5254 if (lvalue_instance && InstanceExpression != null)
5255 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
5257 if (InstanceExpression == null)
5260 InstanceExpression.CheckMarshalByRefAccess (ec);
5262 if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) &&
5263 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
5264 !TypeManager.IsNestedChildOf (ec.ContainerType, InstanceExpression.Type) &&
5265 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.ContainerType)) {
5266 Report.SymbolRelatedToPreviousError (PropertyInfo);
5267 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
5274 void Error_PropertyNotFound (MethodInfo mi, bool getter)
5276 // TODO: correctly we should compare arguments but it will lead to bigger changes
5277 if (mi is MethodBuilder) {
5278 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
5282 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
5284 ParameterData iparams = TypeManager.GetParameterData (mi);
5285 sig.Append (getter ? "get_" : "set_");
5287 sig.Append (iparams.GetSignatureForError ());
5289 Report.SymbolRelatedToPreviousError (mi);
5290 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
5291 Name, sig.ToString ());
5294 public bool IsAccessibleFrom (Type invocation_type, bool lvalue)
5297 MethodInfo accessor = lvalue ? setter : getter;
5298 if (accessor == null && lvalue)
5300 return accessor != null && IsAccessorAccessible (invocation_type, accessor, out dummy);
5303 bool IsSingleDimensionalArrayLength ()
5305 if (DeclaringType != TypeManager.array_type || getter == null || Name != "Length")
5308 string t_name = InstanceExpression.Type.Name;
5309 int t_name_len = t_name.Length;
5310 return t_name_len > 2 && t_name [t_name_len - 2] == '[';
5313 override public Expression DoResolve (EmitContext ec)
5318 if (getter != null){
5319 if (TypeManager.GetParameterData (getter).Count != 0){
5320 Error_PropertyNotFound (getter, true);
5325 if (getter == null){
5327 // The following condition happens if the PropertyExpr was
5328 // created, but is invalid (ie, the property is inaccessible),
5329 // and we did not want to embed the knowledge about this in
5330 // the caller routine. This only avoids double error reporting.
5335 if (InstanceExpression != EmptyExpression.Null) {
5336 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5337 TypeManager.GetFullNameSignature (PropertyInfo));
5342 bool must_do_cs1540_check = false;
5343 if (getter != null &&
5344 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
5345 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
5346 if (pm != null && pm.HasCustomAccessModifier) {
5347 Report.SymbolRelatedToPreviousError (pm);
5348 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5349 TypeManager.CSharpSignature (getter));
5352 Report.SymbolRelatedToPreviousError (getter);
5353 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
5358 if (!InstanceResolve (ec, false, must_do_cs1540_check))
5362 // Only base will allow this invocation to happen.
5364 if (IsBase && getter.IsAbstract) {
5365 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5369 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
5379 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
5381 if (right_side == EmptyExpression.OutAccess) {
5382 if (ec.CurrentBlock.Toplevel.GetTransparentIdentifier (PropertyInfo.Name) != null) {
5383 Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5386 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as `ref' or `out' parameter",
5387 GetSignatureForError ());
5392 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5393 Error_CannotModifyIntermediateExpressionValue (ec);
5396 if (setter == null){
5398 // The following condition happens if the PropertyExpr was
5399 // created, but is invalid (ie, the property is inaccessible),
5400 // and we did not want to embed the knowledge about this in
5401 // the caller routine. This only avoids double error reporting.
5405 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
5406 GetSignatureForError ());
5410 if (TypeManager.GetParameterData (setter).Count != 1){
5411 Error_PropertyNotFound (setter, false);
5415 bool must_do_cs1540_check;
5416 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
5417 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
5418 if (pm != null && pm.HasCustomAccessModifier) {
5419 Report.SymbolRelatedToPreviousError (pm);
5420 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5421 TypeManager.CSharpSignature (setter));
5424 Report.SymbolRelatedToPreviousError (setter);
5425 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
5430 if (!InstanceResolve (ec, PropertyInfo.DeclaringType.IsValueType, must_do_cs1540_check))
5434 // Only base will allow this invocation to happen.
5436 if (IsBase && setter.IsAbstract){
5437 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5444 public override void Emit (EmitContext ec)
5449 public void Emit (EmitContext ec, bool leave_copy)
5452 // Special case: length of single dimension array property is turned into ldlen
5454 if (IsSingleDimensionalArrayLength ()) {
5456 EmitInstance (ec, false);
5457 ec.ig.Emit (OpCodes.Ldlen);
5458 ec.ig.Emit (OpCodes.Conv_I4);
5462 Invocation.EmitCall (ec, IsBase, InstanceExpression, getter, null, loc, prepared, false);
5465 ec.ig.Emit (OpCodes.Dup);
5467 temp = new LocalTemporary (this.Type);
5474 // Implements the IAssignMethod interface for assignments
5476 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5478 Expression my_source = source;
5480 if (prepare_for_load) {
5485 ec.ig.Emit (OpCodes.Dup);
5487 temp = new LocalTemporary (this.Type);
5491 } else if (leave_copy) {
5493 temp = new LocalTemporary (this.Type);
5498 ArrayList args = new ArrayList (1);
5499 args.Add (new Argument (my_source, Argument.AType.Expression));
5501 Invocation.EmitCall (ec, IsBase, InstanceExpression, setter, args, loc, false, prepared);
5511 /// Fully resolved expression that evaluates to an Event
5513 public class EventExpr : MemberExpr {
5514 public readonly EventInfo EventInfo;
5517 MethodInfo add_accessor, remove_accessor;
5519 public EventExpr (EventInfo ei, Location loc)
5523 eclass = ExprClass.EventAccess;
5525 add_accessor = TypeManager.GetAddMethod (ei);
5526 remove_accessor = TypeManager.GetRemoveMethod (ei);
5527 if (add_accessor.IsStatic || remove_accessor.IsStatic)
5530 if (EventInfo is MyEventBuilder){
5531 MyEventBuilder eb = (MyEventBuilder) EventInfo;
5532 type = eb.EventType;
5535 type = EventInfo.EventHandlerType;
5538 public override string Name {
5540 return EventInfo.Name;
5544 public override bool IsInstance {
5550 public override bool IsStatic {
5556 public override Type DeclaringType {
5558 return EventInfo.DeclaringType;
5562 void Error_AssignmentEventOnly ()
5564 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5565 GetSignatureForError ());
5568 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
5569 SimpleName original)
5572 // If the event is local to this class, we transform ourselves into a FieldExpr
5575 if (EventInfo.DeclaringType == ec.ContainerType ||
5576 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
5577 EventField mi = TypeManager.GetEventField (EventInfo);
5580 if (!ec.IsInObsoleteScope)
5581 mi.CheckObsoleteness (loc);
5583 if ((mi.ModFlags & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0 && !ec.IsInCompoundAssignment)
5584 Error_AssignmentEventOnly ();
5586 FieldExpr ml = new FieldExpr (mi.FieldBuilder, loc);
5588 InstanceExpression = null;
5590 return ml.ResolveMemberAccess (ec, left, loc, original);
5594 if (left is This && !ec.IsInCompoundAssignment)
5595 Error_AssignmentEventOnly ();
5597 return base.ResolveMemberAccess (ec, left, loc, original);
5600 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
5603 InstanceExpression = null;
5607 if (InstanceExpression == null) {
5608 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5612 InstanceExpression = InstanceExpression.DoResolve (ec);
5613 if (InstanceExpression == null)
5616 if (IsBase && add_accessor.IsAbstract) {
5617 Error_CannotCallAbstractBase(TypeManager.CSharpSignature(add_accessor));
5622 // This is using the same mechanism as the CS1540 check in PropertyExpr.
5623 // However, in the Event case, we reported a CS0122 instead.
5625 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
5626 InstanceExpression.Type != ec.ContainerType &&
5627 TypeManager.IsSubclassOf (ec.ContainerType, InstanceExpression.Type)) {
5628 Report.SymbolRelatedToPreviousError (EventInfo);
5629 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5636 public bool IsAccessibleFrom (Type invocation_type)
5639 return IsAccessorAccessible (invocation_type, add_accessor, out dummy) &&
5640 IsAccessorAccessible (invocation_type, remove_accessor, out dummy);
5643 public override Expression CreateExpressionTree (EmitContext ec)
5645 throw new NotSupportedException ("ET");
5648 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5650 // contexts where an LValue is valid have already devolved to FieldExprs
5651 Error_CannotAssign ();
5655 public override Expression DoResolve (EmitContext ec)
5657 bool must_do_cs1540_check;
5658 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
5659 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
5660 Report.SymbolRelatedToPreviousError (EventInfo);
5661 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5665 if (!InstanceResolve (ec, must_do_cs1540_check))
5668 if (!ec.IsInCompoundAssignment) {
5669 Error_CannotAssign ();
5676 public override void Emit (EmitContext ec)
5678 Error_CannotAssign ();
5681 public void Error_CannotAssign ()
5683 Report.Error (70, loc,
5684 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
5685 GetSignatureForError (), TypeManager.CSharpName (EventInfo.DeclaringType));
5688 public override string GetSignatureForError ()
5690 return TypeManager.CSharpSignature (EventInfo);
5693 public void EmitAddOrRemove (EmitContext ec, bool is_add, Expression source)
5695 ArrayList args = new ArrayList (1);
5696 args.Add (new Argument (source, Argument.AType.Expression));
5697 Invocation.EmitCall (ec, IsBase, InstanceExpression, is_add ? add_accessor : remove_accessor, args, loc);
5701 public class TemporaryVariable : VariableReference
5705 public TemporaryVariable (Type type, Location loc)
5709 eclass = ExprClass.Variable;
5712 public override Expression CreateExpressionTree (EmitContext ec)
5714 throw new NotSupportedException ("ET");
5717 public override Expression DoResolve (EmitContext ec)
5722 TypeExpr te = new TypeExpression (type, loc);
5723 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
5724 if (!li.Resolve (ec))
5727 if (ec.MustCaptureVariable (li) && !ec.IsInProbingMode) {
5728 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
5729 storey.CaptureLocalVariable (ec, li);
5735 public override void Emit (EmitContext ec)
5740 public void EmitAssign (EmitContext ec, Expression source)
5742 EmitAssign (ec, source, false, false);
5745 public override HoistedVariable HoistedVariable {
5746 get { return li.HoistedVariableReference; }
5749 public override bool IsFixed {
5750 get { return true; }
5753 public override bool IsRef {
5754 get { return false; }
5757 protected override ILocalVariable Variable {
5761 public override VariableInfo VariableInfo {
5762 get { throw new NotImplementedException (); }
5767 /// Handles `var' contextual keyword; var becomes a keyword only
5768 /// if no type called var exists in a variable scope
5770 public class VarExpr : SimpleName
5772 // Used for error reporting only
5773 ArrayList initializer;
5775 public VarExpr (Location loc)
5780 public ArrayList VariableInitializer {
5782 this.initializer = value;
5786 public bool InferType (EmitContext ec, Expression right_side)
5789 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
5791 type = right_side.Type;
5792 if (type == TypeManager.null_type || type == TypeManager.void_type || type == TypeManager.anonymous_method_type) {
5793 Report.Error (815, loc, "An implicitly typed local variable declaration cannot be initialized with `{0}'",
5794 right_side.GetSignatureForError ());
5798 eclass = ExprClass.Variable;
5802 protected override void Error_TypeOrNamespaceNotFound (IResolveContext ec)
5804 Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");
5807 public override TypeExpr ResolveAsContextualType (IResolveContext rc, bool silent)
5809 TypeExpr te = base.ResolveAsContextualType (rc, true);
5813 if (initializer == null)
5816 if (initializer.Count > 1) {
5817 Location loc = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [1]).Location;
5818 Report.Error (819, loc, "An implicitly typed local variable declaration cannot include multiple declarators");
5823 Expression variable_initializer = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [0]).expression_or_array_initializer;
5824 if (variable_initializer == null) {
5825 Report.Error (818, loc, "An implicitly typed local variable declarator must include an initializer");