2 // ecore.cs: Core of the Expression representation for the intermediate tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@seznam.cz)
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
13 namespace Mono.CSharp {
15 using System.Collections;
16 using System.Diagnostics;
17 using System.Reflection;
18 using System.Reflection.Emit;
22 /// The ExprClass class contains the is used to pass the
23 /// classification of an expression (value, variable, namespace,
24 /// type, method group, property access, event access, indexer access,
27 public enum ExprClass : byte {
42 /// This is used to tell Resolve in which types of expressions we're
46 public enum ResolveFlags {
47 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
50 // Returns a type expression.
53 // Returns a method group.
56 // Mask of all the expression class flags.
59 // Disable control flow analysis while resolving the expression.
60 // This is used when resolving the instance expression of a field expression.
61 DisableFlowAnalysis = 8,
63 // Set if this is resolving the first part of a MemberAccess.
66 // Disable control flow analysis _of struct_ while resolving the expression.
67 // This is used when resolving the instance expression of a field expression.
68 DisableStructFlowAnalysis = 32,
73 // This is just as a hint to AddressOf of what will be done with the
76 public enum AddressOp {
83 /// This interface is implemented by variables
85 public interface IMemoryLocation {
87 /// The AddressOf method should generate code that loads
88 /// the address of the object and leaves it on the stack.
90 /// The `mode' argument is used to notify the expression
91 /// of whether this will be used to read from the address or
92 /// write to the address.
94 /// This is just a hint that can be used to provide good error
95 /// reporting, and should have no other side effects.
97 void AddressOf (EmitContext ec, AddressOp mode);
101 // An expressions resolved as a direct variable reference
103 public interface IVariableReference {
104 bool IsFixedVariable { get; }
105 bool IsHoisted { get; }
107 VariableInfo VariableInfo { get; }
109 void SetHasAddressTaken ();
113 /// Base class for expressions
115 public abstract class Expression {
116 public ExprClass eclass;
118 protected Location loc;
122 set { type = value; }
125 public virtual Location Location {
130 /// Utility wrapper routine for Error, just to beautify the code
132 public void Error (int error, string s)
134 Report.Error (error, loc, s);
137 // Not nice but we have broken hierarchy.
138 public virtual void CheckMarshalByRefAccess (EmitContext ec)
142 public virtual bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
144 Attribute.Error_AttributeArgumentNotValid (loc);
149 public virtual string GetSignatureForError ()
151 return TypeManager.CSharpName (type);
154 public static bool IsAccessorAccessible (Type invocation_type, MethodInfo mi, out bool must_do_cs1540_check)
156 MethodAttributes ma = mi.Attributes & MethodAttributes.MemberAccessMask;
158 must_do_cs1540_check = false; // by default we do not check for this
160 if (ma == MethodAttributes.Public)
164 // If only accessible to the current class or children
166 if (ma == MethodAttributes.Private)
167 return TypeManager.IsPrivateAccessible (invocation_type, mi.DeclaringType) ||
168 TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType);
170 if (TypeManager.IsThisOrFriendAssembly (mi.DeclaringType.Assembly)) {
171 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamORAssem)
174 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamANDAssem)
178 // Family and FamANDAssem require that we derive.
179 // FamORAssem requires that we derive if in different assemblies.
180 if (!TypeManager.IsNestedFamilyAccessible (invocation_type, mi.DeclaringType))
183 if (!TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType))
184 must_do_cs1540_check = true;
189 public virtual bool IsNull {
196 /// Performs semantic analysis on the Expression
200 /// The Resolve method is invoked to perform the semantic analysis
203 /// The return value is an expression (it can be the
204 /// same expression in some cases) or a new
205 /// expression that better represents this node.
207 /// For example, optimizations of Unary (LiteralInt)
208 /// would return a new LiteralInt with a negated
211 /// If there is an error during semantic analysis,
212 /// then an error should be reported (using Report)
213 /// and a null value should be returned.
215 /// There are two side effects expected from calling
216 /// Resolve(): the the field variable "eclass" should
217 /// be set to any value of the enumeration
218 /// `ExprClass' and the type variable should be set
219 /// to a valid type (this is the type of the
222 public abstract Expression DoResolve (EmitContext ec);
224 public virtual Expression DoResolveLValue (EmitContext ec, Expression right_side)
230 // This is used if the expression should be resolved as a type or namespace name.
231 // the default implementation fails.
233 public virtual FullNamedExpression ResolveAsTypeStep (IResolveContext rc, bool silent)
237 EmitContext ec = rc as EmitContext;
241 e.Error_UnexpectedKind (ResolveFlags.Type, loc);
247 // C# 3.0 introduced contextual keywords (var) which behaves like a type if type with
248 // same name exists or as a keyword when no type was found
250 public virtual TypeExpr ResolveAsContextualType (IResolveContext rc, bool silent)
252 return ResolveAsTypeTerminal (rc, silent);
256 // This is used to resolve the expression as a type, a null
257 // value will be returned if the expression is not a type
260 public virtual TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
262 TypeExpr te = ResolveAsBaseTerminal (ec, silent);
266 if (!silent) { // && !(te is TypeParameterExpr)) {
267 ObsoleteAttribute obsolete_attr = AttributeTester.GetObsoleteAttribute (te.Type);
268 if (obsolete_attr != null && !ec.IsInObsoleteScope) {
269 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location);
273 ConstructedType ct = te as ConstructedType;
275 // Skip constrains check for overrides and explicit implementations
276 // TODO: they should use different overload
277 GenericMethod gm = ec.GenericDeclContainer as GenericMethod;
278 if (gm != null && ((gm.ModFlags & Modifiers.OVERRIDE) != 0 || gm.MemberName.Left != null)) {
283 // TODO: silent flag is ignored
284 ct.CheckConstraints (ec);
290 public TypeExpr ResolveAsBaseTerminal (IResolveContext ec, bool silent)
292 int errors = Report.Errors;
294 FullNamedExpression fne = ResolveAsTypeStep (ec, silent);
299 if (fne.eclass != ExprClass.Type) {
300 if (!silent && errors == Report.Errors)
301 fne.Error_UnexpectedKind (null, "type", loc);
305 TypeExpr te = fne as TypeExpr;
307 if (!te.CheckAccessLevel (ec.GenericDeclContainer)) {
308 Report.SymbolRelatedToPreviousError (te.Type);
309 ErrorIsInaccesible (loc, TypeManager.CSharpName (te.Type));
317 public static void ErrorIsInaccesible (Location loc, string name)
319 Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", name);
322 protected static void Error_CannotAccessProtected (Location loc, MemberInfo m, Type qualifier, Type container)
324 Report.Error (1540, loc, "Cannot access protected member `{0}' via a qualifier of type `{1}'."
325 + " The qualifier must be of type `{2}' or derived from it",
326 TypeManager.GetFullNameSignature (m),
327 TypeManager.CSharpName (qualifier),
328 TypeManager.CSharpName (container));
332 public static void Error_InvalidExpressionStatement (Location loc)
334 Report.Error (201, loc, "Only assignment, call, increment, decrement, and new object " +
335 "expressions can be used as a statement");
338 public void Error_InvalidExpressionStatement ()
340 Error_InvalidExpressionStatement (loc);
343 protected void Error_CannotAssign (string to, string roContext)
345 Report.Error (1656, loc, "Cannot assign to `{0}' because it is a `{1}'",
349 public static void Error_VoidInvalidInTheContext (Location loc)
351 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
354 public virtual void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl)
356 // The error was already reported as CS1660
357 if (type == TypeManager.anonymous_method_type)
360 if (TypeManager.IsGenericParameter (Type) && TypeManager.IsGenericParameter (target) && type.Name == target.Name) {
362 string sig1 = type.DeclaringMethod == null ?
363 TypeManager.CSharpName (type.DeclaringType) :
364 TypeManager.CSharpSignature (type.DeclaringMethod);
365 string sig2 = target.DeclaringMethod == null ?
366 TypeManager.CSharpName (target.DeclaringType) :
367 TypeManager.CSharpSignature (target.DeclaringMethod);
368 Report.ExtraInformation (loc,
370 "The generic parameter `{0}' of `{1}' cannot be converted to the generic parameter `{0}' of `{2}' (in the previous ",
371 Type.Name, sig1, sig2));
373 } else if (Type.FullName == target.FullName){
374 Report.ExtraInformation (loc,
376 "The type `{0}' has two conflicting definitions, one comes from `{1}' and the other from `{2}' (in the previous ",
377 Type.FullName, Type.Assembly.FullName, target.Assembly.FullName));
381 Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
382 TypeManager.CSharpName (type), TypeManager.CSharpName (target));
386 Report.DisableReporting ();
387 bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null;
388 Report.EnableReporting ();
391 Report.Error (266, loc, "Cannot implicitly convert type `{0}' to `{1}'. " +
392 "An explicit conversion exists (are you missing a cast?)",
393 TypeManager.CSharpName (Type), TypeManager.CSharpName (target));
397 Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
398 TypeManager.CSharpName (type),
399 TypeManager.CSharpName (target));
402 public virtual void Error_VariableIsUsedBeforeItIsDeclared (string name)
404 Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", name);
407 protected virtual void Error_TypeDoesNotContainDefinition (Type type, string name)
409 Error_TypeDoesNotContainDefinition (loc, type, name);
412 public static void Error_TypeDoesNotContainDefinition (Location loc, Type type, string name)
414 Report.SymbolRelatedToPreviousError (type);
415 Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
416 TypeManager.CSharpName (type), name);
419 protected static void Error_ValueAssignment (Location loc)
421 Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
424 ResolveFlags ExprClassToResolveFlags
429 case ExprClass.Namespace:
430 return ResolveFlags.Type;
432 case ExprClass.MethodGroup:
433 return ResolveFlags.MethodGroup;
435 case ExprClass.Value:
436 case ExprClass.Variable:
437 case ExprClass.PropertyAccess:
438 case ExprClass.EventAccess:
439 case ExprClass.IndexerAccess:
440 return ResolveFlags.VariableOrValue;
443 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
449 /// Resolves an expression and performs semantic analysis on it.
453 /// Currently Resolve wraps DoResolve to perform sanity
454 /// checking and assertion checking on what we expect from Resolve.
456 public Expression Resolve (EmitContext ec, ResolveFlags flags)
458 if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type)
459 return ResolveAsTypeStep (ec, false);
461 bool do_flow_analysis = ec.DoFlowAnalysis;
462 bool omit_struct_analysis = ec.OmitStructFlowAnalysis;
463 if ((flags & ResolveFlags.DisableFlowAnalysis) != 0)
464 do_flow_analysis = false;
465 if ((flags & ResolveFlags.DisableStructFlowAnalysis) != 0)
466 omit_struct_analysis = true;
469 using (ec.WithFlowAnalysis (do_flow_analysis, omit_struct_analysis)) {
470 if (this is SimpleName) {
471 bool intermediate = (flags & ResolveFlags.Intermediate) == ResolveFlags.Intermediate;
472 e = ((SimpleName) this).DoResolve (ec, intermediate);
481 if ((flags & e.ExprClassToResolveFlags) == 0) {
482 e.Error_UnexpectedKind (flags, loc);
486 if (e.type == null && !(e is Namespace)) {
487 throw new Exception (
488 "Expression " + e.GetType () +
489 " did not set its type after Resolve\n" +
490 "called from: " + this.GetType ());
497 /// Resolves an expression and performs semantic analysis on it.
499 public Expression Resolve (EmitContext ec)
501 Expression e = Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
503 if (e != null && e.eclass == ExprClass.MethodGroup && RootContext.Version == LanguageVersion.ISO_1) {
504 ((MethodGroupExpr) e).ReportUsageError ();
510 public Constant ResolveAsConstant (EmitContext ec, MemberCore mc)
512 Expression e = Resolve (ec);
516 Constant c = e as Constant;
520 Const.Error_ExpressionMustBeConstant (loc, mc.GetSignatureForError ());
525 /// Resolves an expression for LValue assignment
529 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
530 /// checking and assertion checking on what we expect from Resolve
532 public Expression ResolveLValue (EmitContext ec, Expression right_side, Location loc)
534 int errors = Report.Errors;
535 bool out_access = right_side == EmptyExpression.OutAccess;
537 Expression e = DoResolveLValue (ec, right_side);
539 if (e != null && out_access && !(e is IMemoryLocation)) {
540 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
541 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
543 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
544 // e.GetType () + " " + e.GetSignatureForError ());
549 if (errors == Report.Errors) {
551 Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
553 Error_ValueAssignment (loc);
558 if (e.eclass == ExprClass.Invalid)
559 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
561 if ((e.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 value type `{0}' cannot be assigned using a property `{1}' object initializer",
1173 TypeManager.CSharpName (type), 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 (EmitContext ec, Type value_type, out object value)
1376 return child.GetAttributableValue (ec, 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 AParametersCollection pd = TypeManager.GetParameterData (oper);
1458 if (pd.Types [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 AParametersCollection pd = TypeManager.GetParameterData (oper);
1513 if (pd.Types [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 AParametersCollection pd = TypeManager.GetParameterData (oper);
1555 if (pd.Types [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 (EmitContext ec, 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 // Created during resolving pahse when an expression is wrapped or constantified
2164 // and original expression can be used later (e.g. for expression trees)
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 bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
2195 // Even if resolved result is a constant original expression was not
2196 // and attribute accepts constants only
2198 Attribute.Error_AttributeArgumentNotValid (loc);
2203 public override object GetValue ()
2205 return expr.GetValue ();
2208 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
2210 throw new NotImplementedException ();
2213 public override Expression DoResolve (EmitContext ec)
2218 public override Constant Increment ()
2220 throw new NotImplementedException ();
2223 public override bool IsDefaultValue {
2225 return expr.IsDefaultValue;
2229 public override bool IsNegative {
2231 return expr.IsNegative;
2235 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2237 expr.MutateHoistedGenericType (storey);
2240 public override void Emit (EmitContext ec)
2246 readonly Expression expr, orig_expr;
2248 private ReducedExpression (Expression expr, Expression orig_expr)
2251 this.orig_expr = orig_expr;
2252 this.loc = orig_expr.Location;
2255 public static Expression Create (Constant expr, Expression original_expr)
2257 return new ReducedConstantExpression (expr, original_expr);
2260 public static Expression Create (Expression expr, Expression original_expr)
2262 Constant c = expr as Constant;
2264 return Create (c, original_expr);
2266 return new ReducedExpression (expr, original_expr);
2269 public override Expression CreateExpressionTree (EmitContext ec)
2271 return orig_expr.CreateExpressionTree (ec);
2274 public override Expression DoResolve (EmitContext ec)
2276 eclass = expr.eclass;
2281 public override void Emit (EmitContext ec)
2286 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2288 expr.EmitBranchable (ec, target, on_true);
2291 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2293 expr.MutateHoistedGenericType (storey);
2298 // Unresolved type name expressions
2300 public abstract class ATypeNameExpression : FullNamedExpression
2302 public readonly string Name;
2303 protected TypeArguments targs;
2305 protected ATypeNameExpression (string name, Location l)
2311 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2318 public bool HasTypeArguments {
2320 return targs != null;
2324 public override string GetSignatureForError ()
2326 if (targs != null) {
2327 return TypeManager.RemoveGenericArity (Name) + "<" +
2328 targs.GetSignatureForError () + ">";
2336 /// SimpleName expressions are formed of a single word and only happen at the beginning
2337 /// of a dotted-name.
2339 public class SimpleName : ATypeNameExpression {
2342 public SimpleName (string name, Location l)
2347 public SimpleName (string name, TypeArguments args, Location l)
2348 : base (name, args, l)
2352 public SimpleName (string name, TypeParameter[] type_params, Location l)
2355 targs = new TypeArguments (l);
2356 foreach (TypeParameter type_param in type_params)
2357 targs.Add (new TypeParameterExpr (type_param, l));
2360 public static string RemoveGenericArity (string name)
2363 StringBuilder sb = null;
2365 int pos = name.IndexOf ('`', start);
2370 sb.Append (name.Substring (start));
2375 sb = new StringBuilder ();
2376 sb.Append (name.Substring (start, pos-start));
2379 while ((pos < name.Length) && Char.IsNumber (name [pos]))
2383 } while (start < name.Length);
2385 return sb.ToString ();
2388 public SimpleName GetMethodGroup ()
2390 return new SimpleName (RemoveGenericArity (Name), targs, loc);
2393 public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
2395 if (ec.IsInFieldInitializer)
2396 Report.Error (236, l,
2397 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2401 120, l, "`{0}': An object reference is required for the nonstatic field, method or property",
2405 public bool IdenticalNameAndTypeName (EmitContext ec, Expression resolved_to, Location loc)
2407 return resolved_to != null && resolved_to.Type != null &&
2408 resolved_to.Type.Name == Name &&
2409 (ec.DeclContainer.LookupNamespaceOrType (Name, loc, /* ignore_cs0104 = */ true) != null);
2412 public override Expression DoResolve (EmitContext ec)
2414 return SimpleNameResolve (ec, null, false);
2417 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
2419 return SimpleNameResolve (ec, right_side, false);
2423 public Expression DoResolve (EmitContext ec, bool intermediate)
2425 return SimpleNameResolve (ec, null, intermediate);
2428 static bool IsNestedChild (Type t, Type parent)
2430 while (parent != null) {
2431 if (TypeManager.IsNestedChildOf (t, TypeManager.DropGenericTypeArguments (parent)))
2434 parent = parent.BaseType;
2440 FullNamedExpression ResolveNested (IResolveContext ec, Type t)
2442 if (!TypeManager.IsGenericTypeDefinition (t) && !TypeManager.IsGenericType (t))
2445 DeclSpace ds = ec.DeclContainer;
2446 while (ds != null && !IsNestedChild (t, ds.TypeBuilder))
2452 Type[] gen_params = TypeManager.GetTypeArguments (t);
2454 int arg_count = targs != null ? targs.Count : 0;
2456 for (; (ds != null) && ds.IsGeneric; ds = ds.Parent) {
2457 if (arg_count + ds.CountTypeParameters == gen_params.Length) {
2458 TypeArguments new_args = new TypeArguments (loc);
2459 foreach (TypeParameter param in ds.TypeParameters)
2460 new_args.Add (new TypeParameterExpr (param, loc));
2463 new_args.Add (targs);
2465 return new ConstructedType (t, new_args, loc);
2472 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2474 FullNamedExpression fne = ec.GenericDeclContainer.LookupGeneric (Name, loc);
2476 return fne.ResolveAsTypeStep (ec, silent);
2478 int errors = Report.Errors;
2479 fne = ec.DeclContainer.LookupNamespaceOrType (Name, loc, /*ignore_cs0104=*/ false);
2482 if (fne.Type == null)
2485 FullNamedExpression nested = ResolveNested (ec, fne.Type);
2487 return nested.ResolveAsTypeStep (ec, false);
2489 if (targs != null) {
2490 ConstructedType ct = new ConstructedType (fne, targs, loc);
2491 return ct.ResolveAsTypeStep (ec, false);
2497 if (silent || errors != Report.Errors)
2500 Error_TypeOrNamespaceNotFound (ec);
2504 protected virtual void Error_TypeOrNamespaceNotFound (IResolveContext ec)
2506 MemberCore mc = ec.DeclContainer.GetDefinition (Name);
2508 Error_UnexpectedKind (ec.DeclContainer, "type", GetMemberType (mc), loc);
2512 string ns = ec.DeclContainer.NamespaceEntry.NS.Name;
2513 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2514 foreach (Assembly a in RootNamespace.Global.Assemblies) {
2515 Type type = a.GetType (fullname);
2517 Report.SymbolRelatedToPreviousError (type);
2518 Expression.ErrorIsInaccesible (loc, TypeManager.CSharpName (type));
2523 Type t = ec.DeclContainer.LookupAnyGeneric (Name);
2525 Namespace.Error_InvalidNumberOfTypeArguments (t, loc);
2529 if (targs != null) {
2530 FullNamedExpression retval = ec.DeclContainer.LookupNamespaceOrType (SimpleName.RemoveGenericArity (Name), loc, true);
2531 if (retval != null) {
2532 Namespace.Error_TypeArgumentsCannotBeUsed (retval.Type, loc);
2537 NamespaceEntry.Error_NamespaceNotFound (loc, Name);
2540 // TODO: I am still not convinced about this. If someone else will need it
2541 // implement this as virtual property in MemberCore hierarchy
2542 public static string GetMemberType (MemberCore mc)
2548 if (mc is FieldBase)
2550 if (mc is MethodCore)
2552 if (mc is EnumMember)
2560 Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2566 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2572 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2579 /// 7.5.2: Simple Names.
2581 /// Local Variables and Parameters are handled at
2582 /// parse time, so they never occur as SimpleNames.
2584 /// The `intermediate' flag is used by MemberAccess only
2585 /// and it is used to inform us that it is ok for us to
2586 /// avoid the static check, because MemberAccess might end
2587 /// up resolving the Name as a Type name and the access as
2588 /// a static type access.
2590 /// ie: Type Type; .... { Type.GetType (""); }
2592 /// Type is both an instance variable and a Type; Type.GetType
2593 /// is the static method not an instance method of type.
2595 Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2597 Expression e = null;
2600 // Stage 1: Performed by the parser (binding to locals or parameters).
2602 Block current_block = ec.CurrentBlock;
2603 if (current_block != null){
2604 LocalInfo vi = current_block.GetLocalInfo (Name);
2606 if (targs != null) {
2607 Report.Error (307, loc,
2608 "The variable `{0}' cannot be used with type arguments",
2613 LocalVariableReference var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2614 if (right_side != null) {
2615 return var.ResolveLValue (ec, right_side, loc);
2617 ResolveFlags rf = ResolveFlags.VariableOrValue;
2619 rf |= ResolveFlags.DisableFlowAnalysis;
2620 return var.Resolve (ec, rf);
2624 ParameterReference pref = current_block.Toplevel.GetParameterReference (Name, loc);
2626 if (targs != null) {
2627 Report.Error (307, loc,
2628 "The variable `{0}' cannot be used with type arguments",
2633 if (right_side != null)
2634 return pref.ResolveLValue (ec, right_side, loc);
2636 return pref.Resolve (ec);
2639 Expression expr = current_block.Toplevel.GetTransparentIdentifier (Name);
2641 if (right_side != null)
2642 return expr.ResolveLValue (ec, right_side, loc);
2643 return expr.Resolve (ec);
2648 // Stage 2: Lookup members
2651 Type almost_matched_type = null;
2652 ArrayList almost_matched = null;
2653 for (DeclSpace lookup_ds = ec.DeclContainer; lookup_ds != null; lookup_ds = lookup_ds.Parent) {
2654 // either RootDeclSpace or GenericMethod
2655 if (lookup_ds.TypeBuilder == null)
2658 e = MemberLookup (ec.ContainerType, lookup_ds.TypeBuilder, Name, loc);
2660 if (e is PropertyExpr) {
2661 // since TypeManager.MemberLookup doesn't know if we're doing a lvalue access or not,
2662 // it doesn't know which accessor to check permissions against
2663 if (((PropertyExpr) e).IsAccessibleFrom (ec.ContainerType, right_side != null))
2665 } else if (e is EventExpr) {
2666 if (((EventExpr) e).IsAccessibleFrom (ec.ContainerType))
2674 if (almost_matched == null && almost_matched_members.Count > 0) {
2675 almost_matched_type = lookup_ds.TypeBuilder;
2676 almost_matched = (ArrayList) almost_matched_members.Clone ();
2681 if (almost_matched == null && almost_matched_members.Count > 0) {
2682 almost_matched_type = ec.ContainerType;
2683 almost_matched = (ArrayList) almost_matched_members.Clone ();
2685 e = ResolveAsTypeStep (ec, true);
2689 if (current_block != null) {
2690 IKnownVariable ikv = current_block.Explicit.GetKnownVariable (Name);
2692 LocalInfo li = ikv as LocalInfo;
2693 // Supress CS0219 warning
2697 Error_VariableIsUsedBeforeItIsDeclared (Name);
2702 if (almost_matched != null)
2703 almost_matched_members = almost_matched;
2704 if (almost_matched_type == null)
2705 almost_matched_type = ec.ContainerType;
2706 Error_MemberLookupFailed (ec.ContainerType, null, almost_matched_type, Name,
2707 ec.DeclContainer.Name, AllMemberTypes, AllBindingFlags);
2711 if (e is TypeExpr) {
2715 ConstructedType ct = new ConstructedType (
2716 e.Type, targs, loc);
2717 return ct.ResolveAsTypeStep (ec, false);
2720 if (e is MemberExpr) {
2721 MemberExpr me = (MemberExpr) e;
2724 if (me.IsInstance) {
2725 if (ec.IsStatic || ec.IsInFieldInitializer) {
2727 // Note that an MemberExpr can be both IsInstance and IsStatic.
2728 // An unresolved MethodGroupExpr can contain both kinds of methods
2729 // and each predicate is true if the MethodGroupExpr contains
2730 // at least one of that kind of method.
2734 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2735 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2740 // Pass the buck to MemberAccess and Invocation.
2742 left = EmptyExpression.Null;
2744 left = ec.GetThis (loc);
2747 left = new TypeExpression (ec.ContainerType, loc);
2750 me = me.ResolveMemberAccess (ec, left, loc, null);
2754 if (targs != null) {
2756 me.SetTypeArguments (targs);
2759 if (!me.IsStatic && (me.InstanceExpression != null) &&
2760 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2761 me.InstanceExpression.Type != me.DeclaringType &&
2762 !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2763 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2764 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2765 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2769 return (right_side != null)
2770 ? me.DoResolveLValue (ec, right_side)
2771 : me.DoResolve (ec);
2777 protected override void CloneTo (CloneContext clonectx, Expression target)
2779 // CloneTo: Nothing, we do not keep any state on this expression
2784 /// Represents a namespace or a type. The name of the class was inspired by
2785 /// section 10.8.1 (Fully Qualified Names).
2787 public abstract class FullNamedExpression : Expression {
2789 public override Expression CreateExpressionTree (EmitContext ec)
2791 throw new NotSupportedException ("ET");
2794 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2796 throw new NotSupportedException ();
2799 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2804 public override void Emit (EmitContext ec)
2806 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2807 GetSignatureForError ());
2812 /// Expression that evaluates to a type
2814 public abstract class TypeExpr : FullNamedExpression {
2815 override public FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2817 TypeExpr t = DoResolveAsTypeStep (ec);
2821 eclass = ExprClass.Type;
2825 override public Expression DoResolve (EmitContext ec)
2827 return ResolveAsTypeTerminal (ec, false);
2830 public virtual bool CheckAccessLevel (DeclSpace ds)
2832 return ds.CheckAccessLevel (Type);
2835 public virtual bool AsAccessible (DeclSpace ds)
2837 return ds.IsAccessibleAs (Type);
2840 public virtual bool IsClass {
2841 get { return Type.IsClass; }
2844 public virtual bool IsValueType {
2845 get { return Type.IsValueType; }
2848 public virtual bool IsInterface {
2849 get { return Type.IsInterface; }
2852 public virtual bool IsSealed {
2853 get { return Type.IsSealed; }
2856 public virtual bool CanInheritFrom ()
2858 if (Type == TypeManager.enum_type ||
2859 (Type == TypeManager.value_type && RootContext.StdLib) ||
2860 Type == TypeManager.multicast_delegate_type ||
2861 Type == TypeManager.delegate_type ||
2862 Type == TypeManager.array_type)
2868 protected abstract TypeExpr DoResolveAsTypeStep (IResolveContext ec);
2870 public override bool Equals (object obj)
2872 TypeExpr tobj = obj as TypeExpr;
2876 return Type == tobj.Type;
2879 public override int GetHashCode ()
2881 return Type.GetHashCode ();
2884 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2886 type = storey.MutateType (type);
2891 /// Fully resolved Expression that already evaluated to a type
2893 public class TypeExpression : TypeExpr {
2894 public TypeExpression (Type t, Location l)
2897 eclass = ExprClass.Type;
2901 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2906 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2913 /// Used to create types from a fully qualified name. These are just used
2914 /// by the parser to setup the core types. A TypeLookupExpression is always
2915 /// classified as a type.
2917 public sealed class TypeLookupExpression : TypeExpr {
2918 readonly string name;
2920 public TypeLookupExpression (string name)
2923 eclass = ExprClass.Type;
2926 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2928 // It's null for corlib compilation only
2930 return DoResolveAsTypeStep (ec);
2935 private class UnexpectedType
2939 // This performes recursive type lookup, providing support for generic types.
2940 // For example, given the type:
2942 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]]
2944 // The types will be checked in the following order:
2947 // System.Collections |
2948 // System.Collections.Generic |
2950 // System | recursive call 1 |
2951 // System.Int32 _| | main method call
2953 // System | recursive call 2 |
2954 // System.String _| |
2956 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]] _|
2958 private Type TypeLookup (IResolveContext ec, string name)
2963 FullNamedExpression resolved = null;
2965 Type recursive_type = null;
2966 while (index < name.Length) {
2967 if (name[index] == '[') {
2972 if (name[index] == '[')
2974 else if (name[index] == ']')
2976 } while (braces > 0);
2977 recursive_type = TypeLookup (ec, name.Substring (open + 1, index - open - 1));
2978 if (recursive_type == null || (recursive_type == typeof(UnexpectedType)))
2979 return recursive_type;
2982 if (name[index] == ',')
2984 else if ((name[index] == '.' && !done) || (index == name.Length && name[0] != '[')) {
2985 string substring = name.Substring(dot, index - dot);
2987 if (resolved == null)
2988 resolved = RootNamespace.Global.Lookup (ec.DeclContainer, substring, Location.Null);
2989 else if (resolved is Namespace)
2990 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
2991 else if (type != null)
2992 type = TypeManager.GetNestedType (type, substring);
2996 if (resolved == null)
2998 else if (type == null && resolved is TypeExpr)
2999 type = resolved.Type;
3006 if (name[0] != '[') {
3007 string substring = name.Substring(dot, index - dot);
3010 return TypeManager.GetNestedType (type, substring);
3012 if (resolved != null) {
3013 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
3014 if (resolved is TypeExpr)
3015 return resolved.Type;
3017 if (resolved == null)
3020 resolved.Error_UnexpectedKind (ec.DeclContainer, "type", loc);
3021 return typeof (UnexpectedType);
3027 return recursive_type;
3030 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
3032 Type t = TypeLookup (ec, name);
3034 NamespaceEntry.Error_NamespaceNotFound (loc, name);
3037 if (t == typeof(UnexpectedType))
3043 protected override void CloneTo (CloneContext clonectx, Expression target)
3045 // CloneTo: Nothing, we do not keep any state on this expression
3048 public override string GetSignatureForError ()
3051 return TypeManager.CSharpName (name);
3053 return base.GetSignatureForError ();
3058 /// Represents an "unbound generic type", ie. typeof (Foo<>).
3061 public class UnboundTypeExpression : TypeExpr
3065 public UnboundTypeExpression (MemberName name, Location l)
3071 protected override void CloneTo (CloneContext clonectx, Expression target)
3076 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
3079 if (name.Left != null) {
3080 Expression lexpr = name.Left.GetTypeExpression ();
3081 expr = new MemberAccess (lexpr, name.Basename);
3083 expr = new SimpleName (name.Basename, loc);
3086 FullNamedExpression fne = expr.ResolveAsTypeStep (ec, false);
3091 return new TypeExpression (type, loc);
3096 /// This class denotes an expression which evaluates to a member
3097 /// of a struct or a class.
3099 public abstract class MemberExpr : Expression
3101 protected bool is_base;
3104 /// The name of this member.
3106 public abstract string Name {
3111 // When base.member is used
3113 public bool IsBase {
3114 get { return is_base; }
3115 set { is_base = value; }
3119 /// Whether this is an instance member.
3121 public abstract bool IsInstance {
3126 /// Whether this is a static member.
3128 public abstract bool IsStatic {
3133 /// The type which declares this member.
3135 public abstract Type DeclaringType {
3140 /// The instance expression associated with this member, if it's a
3141 /// non-static member.
3143 public Expression InstanceExpression;
3145 public static void error176 (Location loc, string name)
3147 Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
3148 "with an instance reference, qualify it with a type name instead", name);
3151 public static void Error_BaseAccessInExpressionTree (Location loc)
3153 Report.Error (831, loc, "An expression tree may not contain a base access");
3156 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3158 if (InstanceExpression != null)
3159 InstanceExpression.MutateHoistedGenericType (storey);
3162 // TODO: possible optimalization
3163 // Cache resolved constant result in FieldBuilder <-> expression map
3164 public virtual MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3165 SimpleName original)
3169 // original == null || original.Resolve (...) ==> left
3172 if (left is TypeExpr) {
3173 left = left.ResolveAsTypeTerminal (ec, true);
3178 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3186 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3189 return ResolveExtensionMemberAccess (left);
3192 InstanceExpression = left;
3196 protected virtual MemberExpr ResolveExtensionMemberAccess (Expression left)
3198 error176 (loc, GetSignatureForError ());
3202 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3207 if (InstanceExpression == EmptyExpression.Null) {
3208 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3212 if (InstanceExpression.Type.IsValueType) {
3213 if (InstanceExpression is IMemoryLocation) {
3214 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
3216 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
3217 InstanceExpression.Emit (ec);
3219 t.AddressOf (ec, AddressOp.Store);
3222 InstanceExpression.Emit (ec);
3224 if (prepare_for_load)
3225 ec.ig.Emit (OpCodes.Dup);
3228 public virtual void SetTypeArguments (TypeArguments ta)
3230 // TODO: need to get correct member type
3231 Report.Error (307, loc, "The property `{0}' cannot be used with type arguments",
3232 GetSignatureForError ());
3237 /// Represents group of extension methods
3239 public class ExtensionMethodGroupExpr : MethodGroupExpr
3241 readonly NamespaceEntry namespace_entry;
3242 public Expression ExtensionExpression;
3243 Argument extension_argument;
3245 public ExtensionMethodGroupExpr (ArrayList list, NamespaceEntry n, Type extensionType, Location l)
3246 : base (list, extensionType, l)
3248 this.namespace_entry = n;
3251 public override bool IsStatic {
3252 get { return true; }
3255 public bool IsTopLevel {
3256 get { return namespace_entry == null; }
3259 public override void EmitArguments (EmitContext ec, ArrayList arguments)
3261 if (arguments == null)
3262 arguments = new ArrayList (1);
3263 arguments.Insert (0, extension_argument);
3264 base.EmitArguments (ec, arguments);
3267 public override void EmitCall (EmitContext ec, ArrayList arguments)
3269 if (arguments == null)
3270 arguments = new ArrayList (1);
3271 arguments.Insert (0, extension_argument);
3272 base.EmitCall (ec, arguments);
3275 public override MethodGroupExpr OverloadResolve (EmitContext ec, ref ArrayList arguments, bool may_fail, Location loc)
3277 if (arguments == null)
3278 arguments = new ArrayList (1);
3280 arguments.Insert (0, new Argument (ExtensionExpression));
3281 MethodGroupExpr mg = ResolveOverloadExtensions (ec, arguments, namespace_entry, loc);
3283 // Store resolved argument and restore original arguments
3285 ((ExtensionMethodGroupExpr)mg).extension_argument = (Argument)arguments [0];
3286 arguments.RemoveAt (0);
3291 MethodGroupExpr ResolveOverloadExtensions (EmitContext ec, ArrayList arguments, NamespaceEntry ns, Location loc)
3293 // Use normal resolve rules
3294 MethodGroupExpr mg = base.OverloadResolve (ec, ref arguments, ns != null, loc);
3302 ExtensionMethodGroupExpr e = ns.LookupExtensionMethod (type, null, Name, loc);
3304 return base.OverloadResolve (ec, ref arguments, false, loc);
3306 e.ExtensionExpression = ExtensionExpression;
3307 e.SetTypeArguments (type_arguments);
3308 return e.ResolveOverloadExtensions (ec, arguments, e.namespace_entry, loc);
3313 /// MethodGroupExpr represents a group of method candidates which
3314 /// can be resolved to the best method overload
3316 public class MethodGroupExpr : MemberExpr
3318 public interface IErrorHandler
3320 bool NoExactMatch (EmitContext ec, MethodBase method);
3323 public IErrorHandler CustomErrorHandler;
3324 public MethodBase [] Methods;
3325 MethodBase best_candidate;
3326 // TODO: make private
3327 public TypeArguments type_arguments;
3328 bool identical_type_name;
3331 public MethodGroupExpr (MemberInfo [] mi, Type type, Location l)
3334 Methods = new MethodBase [mi.Length];
3335 mi.CopyTo (Methods, 0);
3338 public MethodGroupExpr (ArrayList list, Type type, Location l)
3342 Methods = (MethodBase[])list.ToArray (typeof (MethodBase));
3344 foreach (MemberInfo m in list){
3345 if (!(m is MethodBase)){
3346 Console.WriteLine ("Name " + m.Name);
3347 Console.WriteLine ("Found a: " + m.GetType ().FullName);
3356 protected MethodGroupExpr (Type type, Location loc)
3359 eclass = ExprClass.MethodGroup;
3363 public override Type DeclaringType {
3366 // We assume that the top-level type is in the end
3368 return Methods [Methods.Length - 1].DeclaringType;
3369 //return Methods [0].DeclaringType;
3373 public Type DelegateType {
3375 delegate_type = value;
3379 public bool IdenticalTypeName {
3381 return identical_type_name;
3385 identical_type_name = value;
3389 public override string GetSignatureForError ()
3391 if (best_candidate != null)
3392 return TypeManager.CSharpSignature (best_candidate);
3394 return TypeManager.CSharpSignature (Methods [0]);
3397 public override string Name {
3399 return Methods [0].Name;
3403 public override bool IsInstance {
3405 if (best_candidate != null)
3406 return !best_candidate.IsStatic;
3408 foreach (MethodBase mb in Methods)
3416 public override bool IsStatic {
3418 if (best_candidate != null)
3419 return best_candidate.IsStatic;
3421 foreach (MethodBase mb in Methods)
3429 public static explicit operator ConstructorInfo (MethodGroupExpr mg)
3431 return (ConstructorInfo)mg.best_candidate;
3434 public static explicit operator MethodInfo (MethodGroupExpr mg)
3436 return (MethodInfo)mg.best_candidate;
3440 // 7.4.3.3 Better conversion from expression
3441 // Returns : 1 if a->p is better,
3442 // 2 if a->q is better,
3443 // 0 if neither is better
3445 static int BetterExpressionConversion (EmitContext ec, Argument a, Type p, Type q)
3447 Type argument_type = TypeManager.TypeToCoreType (a.Type);
3448 if (argument_type == TypeManager.anonymous_method_type && RootContext.Version > LanguageVersion.ISO_2) {
3450 // Uwrap delegate from Expression<T>
3452 if (TypeManager.DropGenericTypeArguments (p) == TypeManager.expression_type) {
3453 p = TypeManager.GetTypeArguments (p) [0];
3455 if (TypeManager.DropGenericTypeArguments (q) == TypeManager.expression_type) {
3456 q = TypeManager.GetTypeArguments (q) [0];
3459 p = Delegate.GetInvokeMethod (null, p).ReturnType;
3460 q = Delegate.GetInvokeMethod (null, q).ReturnType;
3461 if (p == TypeManager.void_type && q != TypeManager.void_type)
3463 if (q == TypeManager.void_type && p != TypeManager.void_type)
3466 if (argument_type == p)
3469 if (argument_type == q)
3473 return BetterTypeConversion (ec, p, q);
3477 // 7.4.3.4 Better conversion from type
3479 public static int BetterTypeConversion (EmitContext ec, Type p, Type q)
3481 if (p == null || q == null)
3482 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3484 if (p == TypeManager.int32_type) {
3485 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3487 } else if (p == TypeManager.int64_type) {
3488 if (q == TypeManager.uint64_type)
3490 } else if (p == TypeManager.sbyte_type) {
3491 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3492 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3494 } else if (p == TypeManager.short_type) {
3495 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3496 q == TypeManager.uint64_type)
3500 if (q == TypeManager.int32_type) {
3501 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3503 } if (q == TypeManager.int64_type) {
3504 if (p == TypeManager.uint64_type)
3506 } else if (q == TypeManager.sbyte_type) {
3507 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3508 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3510 } if (q == TypeManager.short_type) {
3511 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3512 p == TypeManager.uint64_type)
3516 // TODO: this is expensive
3517 Expression p_tmp = new EmptyExpression (p);
3518 Expression q_tmp = new EmptyExpression (q);
3520 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3521 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3523 if (p_to_q && !q_to_p)
3526 if (q_to_p && !p_to_q)
3533 /// Determines "Better function" between candidate
3534 /// and the current best match
3537 /// Returns a boolean indicating :
3538 /// false if candidate ain't better
3539 /// true if candidate is better than the current best match
3541 static bool BetterFunction (EmitContext ec, ArrayList args, int argument_count,
3542 MethodBase candidate, bool candidate_params,
3543 MethodBase best, bool best_params)
3545 AParametersCollection candidate_pd = TypeManager.GetParameterData (candidate);
3546 AParametersCollection best_pd = TypeManager.GetParameterData (best);
3548 bool better_at_least_one = false;
3550 for (int j = 0, c_idx = 0, b_idx = 0; j < argument_count; ++j, ++c_idx, ++b_idx)
3552 Argument a = (Argument) args [j];
3554 Type ct = candidate_pd.Types [c_idx];
3555 Type bt = best_pd.Types [b_idx];
3557 if (candidate_params && candidate_pd.FixedParameters [c_idx].ModFlags == Parameter.Modifier.PARAMS)
3559 ct = TypeManager.GetElementType (ct);
3563 if (best_params && best_pd.FixedParameters [b_idx].ModFlags == Parameter.Modifier.PARAMS)
3565 bt = TypeManager.GetElementType (bt);
3573 int result = BetterExpressionConversion (ec, a, ct, bt);
3575 // for each argument, the conversion to 'ct' should be no worse than
3576 // the conversion to 'bt'.
3580 // for at least one argument, the conversion to 'ct' should be better than
3581 // the conversion to 'bt'.
3583 better_at_least_one = true;
3586 if (better_at_least_one)
3590 // This handles the case
3592 // Add (float f1, float f2, float f3);
3593 // Add (params decimal [] foo);
3595 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3596 // first candidate would've chosen as better.
3602 // The two methods have equal parameter types. Now apply tie-breaking rules
3604 if (TypeManager.IsGenericMethod (best) && !TypeManager.IsGenericMethod (candidate))
3606 if (!TypeManager.IsGenericMethod (best) && TypeManager.IsGenericMethod (candidate))
3610 // This handles the following cases:
3612 // Trim () is better than Trim (params char[] chars)
3613 // Concat (string s1, string s2, string s3) is better than
3614 // Concat (string s1, params string [] srest)
3615 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3617 if (!candidate_params && best_params)
3619 if (candidate_params && !best_params)
3622 int candidate_param_count = candidate_pd.Count;
3623 int best_param_count = best_pd.Count;
3625 if (candidate_param_count != best_param_count)
3626 // can only happen if (candidate_params && best_params)
3627 return candidate_param_count > best_param_count;
3630 // now, both methods have the same number of parameters, and the parameters have the same types
3631 // Pick the "more specific" signature
3634 MethodBase orig_candidate = TypeManager.DropGenericMethodArguments (candidate);
3635 MethodBase orig_best = TypeManager.DropGenericMethodArguments (best);
3637 AParametersCollection orig_candidate_pd = TypeManager.GetParameterData (orig_candidate);
3638 AParametersCollection orig_best_pd = TypeManager.GetParameterData (orig_best);
3640 bool specific_at_least_once = false;
3641 for (int j = 0; j < candidate_param_count; ++j)
3643 Type ct = orig_candidate_pd.Types [j];
3644 Type bt = orig_best_pd.Types [j];
3647 Type specific = MoreSpecific (ct, bt);
3651 specific_at_least_once = true;
3654 if (specific_at_least_once)
3657 // FIXME: handle lifted operators
3663 protected override MemberExpr ResolveExtensionMemberAccess (Expression left)
3666 return base.ResolveExtensionMemberAccess (left);
3669 // When left side is an expression and at least one candidate method is
3670 // static, it can be extension method
3672 InstanceExpression = left;
3676 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3677 SimpleName original)
3679 if (!(left is TypeExpr) &&
3680 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3681 IdenticalTypeName = true;
3683 return base.ResolveMemberAccess (ec, left, loc, original);
3686 public override Expression CreateExpressionTree (EmitContext ec)
3688 if (best_candidate == null) {
3689 Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3693 if (best_candidate.IsConstructor)
3694 return new TypeOfConstructorInfo (best_candidate, loc);
3696 IMethodData md = TypeManager.GetMethod (best_candidate);
3697 if (md != null && md.IsExcluded ())
3698 Report.Error (765, loc,
3699 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3701 return new TypeOfMethodInfo (best_candidate, loc);
3704 override public Expression DoResolve (EmitContext ec)
3706 if (InstanceExpression != null) {
3707 InstanceExpression = InstanceExpression.DoResolve (ec);
3708 if (InstanceExpression == null)
3715 public void ReportUsageError ()
3717 Report.Error (654, loc, "Method `" + DeclaringType + "." +
3718 Name + "()' is referenced without parentheses");
3721 override public void Emit (EmitContext ec)
3723 ReportUsageError ();
3726 public virtual void EmitArguments (EmitContext ec, ArrayList arguments)
3728 Invocation.EmitArguments (ec, arguments, false, null);
3731 public virtual void EmitCall (EmitContext ec, ArrayList arguments)
3733 Invocation.EmitCall (ec, IsBase, InstanceExpression, best_candidate, arguments, loc);
3736 protected virtual void Error_InvalidArguments (EmitContext ec, Location loc, int idx, MethodBase method,
3737 Argument a, AParametersCollection expected_par, Type paramType)
3739 ExtensionMethodGroupExpr emg = this as ExtensionMethodGroupExpr;
3741 if (a is CollectionElementInitializer.ElementInitializerArgument) {
3742 Report.SymbolRelatedToPreviousError (method);
3743 if ((expected_par.FixedParameters [idx].ModFlags & Parameter.Modifier.ISBYREF) != 0) {
3744 Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
3745 TypeManager.CSharpSignature (method));
3748 Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
3749 TypeManager.CSharpSignature (method));
3750 } else if (delegate_type == null) {
3751 Report.SymbolRelatedToPreviousError (method);
3753 Report.Error (1928, loc,
3754 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3755 emg.ExtensionExpression.GetSignatureForError (),
3756 emg.Name, TypeManager.CSharpSignature (method));
3758 Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
3759 TypeManager.CSharpSignature (method));
3762 Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
3763 TypeManager.CSharpName (delegate_type));
3765 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters [idx].ModFlags;
3767 string index = (idx + 1).ToString ();
3768 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
3769 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
3770 if ((mod & Parameter.Modifier.ISBYREF) == 0)
3771 Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
3772 index, Parameter.GetModifierSignature (a.Modifier));
3774 Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
3775 index, Parameter.GetModifierSignature (mod));
3777 string p1 = a.GetSignatureForError ();
3778 string p2 = TypeManager.CSharpName (paramType);
3781 Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
3782 Report.SymbolRelatedToPreviousError (a.Expr.Type);
3783 Report.SymbolRelatedToPreviousError (paramType);
3786 if (idx == 0 && emg != null) {
3787 Report.Error (1929, loc,
3788 "Extension method instance type `{0}' cannot be converted to `{1}'", p1, p2);
3790 Report.Error (1503, loc,
3791 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
3796 public override void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl)
3798 Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3799 Name, TypeManager.CSharpName (target));
3802 protected virtual int GetApplicableParametersCount (MethodBase method, AParametersCollection parameters)
3804 return parameters.Count;
3807 public static bool IsAncestralType (Type first_type, Type second_type)
3809 return first_type != second_type &&
3810 (TypeManager.IsSubclassOf (second_type, first_type) ||
3811 TypeManager.ImplementsInterface (second_type, first_type));
3815 /// Determines if the candidate method is applicable (section 14.4.2.1)
3816 /// to the given set of arguments
3817 /// A return value rates candidate method compatibility,
3818 /// 0 = the best, int.MaxValue = the worst
3820 public int IsApplicable (EmitContext ec,
3821 ArrayList arguments, int arg_count, ref MethodBase method, ref bool params_expanded_form)
3823 MethodBase candidate = method;
3825 AParametersCollection pd = TypeManager.GetParameterData (candidate);
3826 int param_count = GetApplicableParametersCount (candidate, pd);
3828 if (arg_count != param_count) {
3830 return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
3831 if (arg_count < param_count - 1)
3832 return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
3837 // 1. Handle generic method using type arguments when specified or type inference
3839 if (TypeManager.IsGenericMethod (candidate)) {
3840 if (type_arguments != null) {
3841 Type [] g_args = candidate.GetGenericArguments ();
3842 if (g_args.Length != type_arguments.Count)
3843 return int.MaxValue - 20000 + Math.Abs (type_arguments.Count - g_args.Length);
3845 // TODO: Don't create new method, create Parameters only
3846 method = ((MethodInfo) candidate).MakeGenericMethod (type_arguments.Arguments);
3848 pd = TypeManager.GetParameterData (candidate);
3850 int score = TypeManager.InferTypeArguments (ec, arguments, ref candidate);
3852 return score - 20000;
3854 if (TypeManager.IsGenericMethodDefinition (candidate))
3855 throw new InternalErrorException ("A generic method `{0}' definition took part in overload resolution",
3856 TypeManager.CSharpSignature (candidate));
3858 pd = TypeManager.GetParameterData (candidate);
3861 if (type_arguments != null)
3862 return int.MaxValue - 15000;
3867 // 2. Each argument has to be implicitly convertible to method parameter
3870 Parameter.Modifier p_mod = 0;
3872 for (int i = 0; i < arg_count; i++) {
3873 Argument a = (Argument) arguments [i];
3874 Parameter.Modifier a_mod = a.Modifier &
3875 ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3877 if (p_mod != Parameter.Modifier.PARAMS) {
3878 p_mod = pd.FixedParameters [i].ModFlags & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3880 if (p_mod == Parameter.Modifier.ARGLIST) {
3881 if (a.Type == TypeManager.runtime_argument_handle_type)
3889 params_expanded_form = true;
3893 if (!params_expanded_form)
3894 score = IsArgumentCompatible (ec, a_mod, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
3896 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0) {
3897 // It can be applicable in expanded form
3898 score = IsArgumentCompatible (ec, a_mod, a, 0, pt.GetElementType ());
3900 params_expanded_form = true;
3904 if (params_expanded_form)
3906 return (arg_count - i) * 2 + score;
3910 if (arg_count != param_count)
3911 params_expanded_form = true;
3916 int IsArgumentCompatible (EmitContext ec, Parameter.Modifier arg_mod, Argument argument, Parameter.Modifier param_mod, Type parameter)
3919 // Types have to be identical when ref or out modifer is used
3921 if (arg_mod != 0 || param_mod != 0) {
3922 if (TypeManager.HasElementType (parameter))
3923 parameter = parameter.GetElementType ();
3925 Type a_type = argument.Type;
3926 if (TypeManager.HasElementType (a_type))
3927 a_type = a_type.GetElementType ();
3929 if (a_type != parameter)
3932 if (delegate_type != null ?
3933 !Delegate.IsTypeCovariant (argument.Expr, parameter) :
3934 !Convert.ImplicitConversionExists (ec, argument.Expr, parameter))
3938 if (arg_mod != param_mod)
3944 public static bool IsOverride (MethodBase cand_method, MethodBase base_method)
3946 if (!IsAncestralType (base_method.DeclaringType, cand_method.DeclaringType))
3949 AParametersCollection cand_pd = TypeManager.GetParameterData (cand_method);
3950 AParametersCollection base_pd = TypeManager.GetParameterData (base_method);
3952 if (cand_pd.Count != base_pd.Count)
3955 for (int j = 0; j < cand_pd.Count; ++j)
3957 Parameter.Modifier cm = cand_pd.FixedParameters [j].ModFlags;
3958 Parameter.Modifier bm = base_pd.FixedParameters [j].ModFlags;
3959 Type ct = cand_pd.Types [j];
3960 Type bt = base_pd.Types [j];
3962 if (cm != bm || ct != bt)
3969 public static MethodGroupExpr MakeUnionSet (MethodGroupExpr mg1, MethodGroupExpr mg2, Location loc)
3980 ArrayList all = new ArrayList (mg1.Methods);
3981 foreach (MethodBase m in mg2.Methods){
3982 if (!TypeManager.ArrayContainsMethod (mg1.Methods, m, false))
3986 return new MethodGroupExpr (all, null, loc);
3989 static Type MoreSpecific (Type p, Type q)
3991 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
3993 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
3996 if (TypeManager.HasElementType (p))
3998 Type pe = TypeManager.GetElementType (p);
3999 Type qe = TypeManager.GetElementType (q);
4000 Type specific = MoreSpecific (pe, qe);
4006 else if (TypeManager.IsGenericType (p))
4008 Type[] pargs = TypeManager.GetTypeArguments (p);
4009 Type[] qargs = TypeManager.GetTypeArguments (q);
4011 bool p_specific_at_least_once = false;
4012 bool q_specific_at_least_once = false;
4014 for (int i = 0; i < pargs.Length; i++)
4016 Type specific = MoreSpecific (pargs [i], qargs [i]);
4017 if (specific == pargs [i])
4018 p_specific_at_least_once = true;
4019 if (specific == qargs [i])
4020 q_specific_at_least_once = true;
4023 if (p_specific_at_least_once && !q_specific_at_least_once)
4025 if (!p_specific_at_least_once && q_specific_at_least_once)
4032 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4034 base.MutateHoistedGenericType (storey);
4036 MethodInfo mi = best_candidate as MethodInfo;
4038 best_candidate = storey.MutateGenericMethod (mi);
4042 best_candidate = storey.MutateConstructor ((ConstructorInfo) this);
4046 /// Find the Applicable Function Members (7.4.2.1)
4048 /// me: Method Group expression with the members to select.
4049 /// it might contain constructors or methods (or anything
4050 /// that maps to a method).
4052 /// Arguments: ArrayList containing resolved Argument objects.
4054 /// loc: The location if we want an error to be reported, or a Null
4055 /// location for "probing" purposes.
4057 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4058 /// that is the best match of me on Arguments.
4061 public virtual MethodGroupExpr OverloadResolve (EmitContext ec, ref ArrayList Arguments,
4062 bool may_fail, Location loc)
4064 bool method_params = false;
4065 Type applicable_type = null;
4067 ArrayList candidates = new ArrayList (2);
4068 ArrayList candidate_overrides = null;
4071 // Used to keep a map between the candidate
4072 // and whether it is being considered in its
4073 // normal or expanded form
4075 // false is normal form, true is expanded form
4077 Hashtable candidate_to_form = null;
4079 if (Arguments != null)
4080 arg_count = Arguments.Count;
4082 if (RootContext.Version == LanguageVersion.ISO_1 && Name == "Invoke" && TypeManager.IsDelegateType (DeclaringType)) {
4084 Report.Error (1533, loc, "Invoke cannot be called directly on a delegate");
4088 int nmethods = Methods.Length;
4092 // Methods marked 'override' don't take part in 'applicable_type'
4093 // computation, nor in the actual overload resolution.
4094 // However, they still need to be emitted instead of a base virtual method.
4095 // So, we salt them away into the 'candidate_overrides' array.
4097 // In case of reflected methods, we replace each overriding method with
4098 // its corresponding base virtual method. This is to improve compatibility
4099 // with non-C# libraries which change the visibility of overrides (#75636)
4102 for (int i = 0; i < Methods.Length; ++i) {
4103 MethodBase m = Methods [i];
4104 if (TypeManager.IsOverride (m)) {
4105 if (candidate_overrides == null)
4106 candidate_overrides = new ArrayList ();
4107 candidate_overrides.Add (m);
4108 m = TypeManager.TryGetBaseDefinition (m);
4117 // Enable message recording, it's used mainly by lambda expressions
4119 Report.IMessageRecorder msg_recorder = new Report.MessageRecorder ();
4120 Report.IMessageRecorder prev_recorder = Report.SetMessageRecorder (msg_recorder);
4123 // First we construct the set of applicable methods
4125 bool is_sorted = true;
4126 int best_candidate_rate = int.MaxValue;
4127 for (int i = 0; i < nmethods; i++) {
4128 Type decl_type = Methods [i].DeclaringType;
4131 // If we have already found an applicable method
4132 // we eliminate all base types (Section 14.5.5.1)
4134 if (applicable_type != null && IsAncestralType (decl_type, applicable_type))
4138 // Check if candidate is applicable (section 14.4.2.1)
4140 bool params_expanded_form = false;
4141 int candidate_rate = IsApplicable (ec, Arguments, arg_count, ref Methods [i], ref params_expanded_form);
4143 if (candidate_rate < best_candidate_rate) {
4144 best_candidate_rate = candidate_rate;
4145 best_candidate = Methods [i];
4148 if (params_expanded_form) {
4149 if (candidate_to_form == null)
4150 candidate_to_form = new PtrHashtable ();
4151 MethodBase candidate = Methods [i];
4152 candidate_to_form [candidate] = candidate;
4155 if (candidate_rate != 0) {
4156 if (msg_recorder != null)
4157 msg_recorder.EndSession ();
4161 msg_recorder = null;
4162 candidates.Add (Methods [i]);
4164 if (applicable_type == null)
4165 applicable_type = decl_type;
4166 else if (applicable_type != decl_type) {
4168 if (IsAncestralType (applicable_type, decl_type))
4169 applicable_type = decl_type;
4173 Report.SetMessageRecorder (prev_recorder);
4174 if (msg_recorder != null && !msg_recorder.IsEmpty) {
4176 msg_recorder.PrintMessages ();
4181 int candidate_top = candidates.Count;
4183 if (applicable_type == null) {
4185 // When we found a top level method which does not match and it's
4186 // not an extension method. We start extension methods lookup from here
4188 if (InstanceExpression != null) {
4189 ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (type, Name, loc);
4190 if (ex_method_lookup != null) {
4191 ex_method_lookup.ExtensionExpression = InstanceExpression;
4192 ex_method_lookup.SetTypeArguments (type_arguments);
4193 return ex_method_lookup.OverloadResolve (ec, ref Arguments, may_fail, loc);
4201 // Okay so we have failed to find exact match so we
4202 // return error info about the closest match
4204 if (best_candidate != null) {
4205 if (CustomErrorHandler != null) {
4206 if (CustomErrorHandler.NoExactMatch (ec, best_candidate))
4210 AParametersCollection pd = TypeManager.GetParameterData (best_candidate);
4211 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4212 if (arg_count == pd.Count || pd.HasParams) {
4213 if (TypeManager.IsGenericMethodDefinition (best_candidate)) {
4214 if (type_arguments == null) {
4215 Report.Error (411, loc,
4216 "The type arguments for method `{0}' cannot be inferred from " +
4217 "the usage. Try specifying the type arguments explicitly",
4218 TypeManager.CSharpSignature (best_candidate));
4222 Type [] g_args = TypeManager.GetGenericArguments (best_candidate);
4223 if (type_arguments.Count != g_args.Length) {
4224 Report.SymbolRelatedToPreviousError (best_candidate);
4225 Report.Error (305, loc, "Using the generic method `{0}' requires `{1}' type argument(s)",
4226 TypeManager.CSharpSignature (best_candidate),
4227 g_args.Length.ToString ());
4231 if (type_arguments != null && !TypeManager.IsGenericMethod (best_candidate)) {
4232 Namespace.Error_TypeArgumentsCannotBeUsed (best_candidate, loc);
4237 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate, cand_params, may_fail, loc))
4242 if (almost_matched_members.Count != 0) {
4243 Error_MemberLookupFailed (ec.ContainerType, type, type, ".ctor",
4244 null, MemberTypes.Constructor, AllBindingFlags);
4249 // We failed to find any method with correct argument count
4251 if (Name == ConstructorInfo.ConstructorName) {
4252 Report.SymbolRelatedToPreviousError (type);
4253 Report.Error (1729, loc,
4254 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4255 TypeManager.CSharpName (type), arg_count);
4257 Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4258 Name, arg_count.ToString ());
4266 // At this point, applicable_type is _one_ of the most derived types
4267 // in the set of types containing the methods in this MethodGroup.
4268 // Filter the candidates so that they only contain methods from the
4269 // most derived types.
4272 int finalized = 0; // Number of finalized candidates
4275 // Invariant: applicable_type is a most derived type
4277 // We'll try to complete Section 14.5.5.1 for 'applicable_type' by
4278 // eliminating all it's base types. At the same time, we'll also move
4279 // every unrelated type to the end of the array, and pick the next
4280 // 'applicable_type'.
4282 Type next_applicable_type = null;
4283 int j = finalized; // where to put the next finalized candidate
4284 int k = finalized; // where to put the next undiscarded candidate
4285 for (int i = finalized; i < candidate_top; ++i) {
4286 MethodBase candidate = (MethodBase) candidates [i];
4287 Type decl_type = candidate.DeclaringType;
4289 if (decl_type == applicable_type) {
4290 candidates [k++] = candidates [j];
4291 candidates [j++] = candidates [i];
4295 if (IsAncestralType (decl_type, applicable_type))
4298 if (next_applicable_type != null &&
4299 IsAncestralType (decl_type, next_applicable_type))
4302 candidates [k++] = candidates [i];
4304 if (next_applicable_type == null ||
4305 IsAncestralType (next_applicable_type, decl_type))
4306 next_applicable_type = decl_type;
4309 applicable_type = next_applicable_type;
4312 } while (applicable_type != null);
4316 // Now we actually find the best method
4319 best_candidate = (MethodBase) candidates [0];
4320 if (delegate_type == null)
4321 method_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4323 for (int ix = 1; ix < candidate_top; ix++) {
4324 MethodBase candidate = (MethodBase) candidates [ix];
4326 if (candidate == best_candidate)
4329 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4331 if (BetterFunction (ec, Arguments, arg_count,
4332 candidate, cand_params,
4333 best_candidate, method_params)) {
4334 best_candidate = candidate;
4335 method_params = cand_params;
4339 // Now check that there are no ambiguities i.e the selected method
4340 // should be better than all the others
4342 MethodBase ambiguous = null;
4343 for (int ix = 1; ix < candidate_top; ix++) {
4344 MethodBase candidate = (MethodBase) candidates [ix];
4346 if (candidate == best_candidate)
4349 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4350 if (!BetterFunction (ec, Arguments, arg_count,
4351 best_candidate, method_params,
4352 candidate, cand_params))
4355 Report.SymbolRelatedToPreviousError (candidate);
4356 ambiguous = candidate;
4360 if (ambiguous != null) {
4361 Report.SymbolRelatedToPreviousError (ambiguous);
4362 Report.SymbolRelatedToPreviousError (best_candidate);
4363 Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4364 TypeManager.CSharpSignature (ambiguous), TypeManager.CSharpSignature (best_candidate));
4369 // If the method is a virtual function, pick an override closer to the LHS type.
4371 if (!IsBase && best_candidate.IsVirtual) {
4372 if (TypeManager.IsOverride (best_candidate))
4373 throw new InternalErrorException (
4374 "Should not happen. An 'override' method took part in overload resolution: " + best_candidate);
4376 if (candidate_overrides != null) {
4377 Type[] gen_args = null;
4378 bool gen_override = false;
4379 if (TypeManager.IsGenericMethod (best_candidate))
4380 gen_args = TypeManager.GetGenericArguments (best_candidate);
4382 foreach (MethodBase candidate in candidate_overrides) {
4383 if (TypeManager.IsGenericMethod (candidate)) {
4384 if (gen_args == null)
4387 if (gen_args.Length != TypeManager.GetGenericArguments (candidate).Length)
4390 if (gen_args != null)
4394 if (IsOverride (candidate, best_candidate)) {
4395 gen_override = true;
4396 best_candidate = candidate;
4400 if (gen_override && gen_args != null) {
4402 best_candidate = ((MethodInfo) best_candidate).MakeGenericMethod (gen_args);
4409 // And now check if the arguments are all
4410 // compatible, perform conversions if
4411 // necessary etc. and return if everything is
4414 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate,
4415 method_params, may_fail, loc))
4418 if (best_candidate == null)
4421 MethodBase the_method = TypeManager.DropGenericMethodArguments (best_candidate);
4423 if (the_method.IsGenericMethodDefinition &&
4424 !ConstraintChecker.CheckConstraints (ec, the_method, best_candidate, loc))
4428 IMethodData data = TypeManager.GetMethod (the_method);
4430 data.SetMemberIsUsed ();
4435 public override void SetTypeArguments (TypeArguments ta)
4437 type_arguments = ta;
4440 public bool VerifyArgumentsCompat (EmitContext ec, ref ArrayList arguments,
4441 int arg_count, MethodBase method,
4442 bool chose_params_expanded,
4443 bool may_fail, Location loc)
4445 AParametersCollection pd = TypeManager.GetParameterData (method);
4447 int errors = Report.Errors;
4448 Parameter.Modifier p_mod = 0;
4450 int a_idx = 0, a_pos = 0;
4452 ArrayList params_initializers = null;
4453 bool has_unsafe_arg = false;
4455 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4456 a = (Argument) arguments [a_idx];
4457 if (p_mod != Parameter.Modifier.PARAMS) {
4458 p_mod = pd.FixedParameters [a_idx].ModFlags;
4459 pt = pd.Types [a_idx];
4460 has_unsafe_arg |= pt.IsPointer;
4462 if (p_mod == Parameter.Modifier.ARGLIST) {
4463 if (a.Type != TypeManager.runtime_argument_handle_type)
4468 if (p_mod == Parameter.Modifier.PARAMS) {
4469 if (chose_params_expanded) {
4470 params_initializers = new ArrayList (arg_count - a_idx);
4471 pt = TypeManager.GetElementType (pt);
4477 // Types have to be identical when ref or out modifer is used
4479 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4480 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4483 if (!TypeManager.IsEqual (a.Expr.Type, pt))
4490 if (TypeManager.IsEqual (a.Type, pt)) {
4493 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4499 // Convert params arguments to an array initializer
4501 if (params_initializers != null) {
4502 // we choose to use 'a.Expr' rather than 'conv' so that
4503 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
4504 params_initializers.Add (a.Expr);
4505 arguments.RemoveAt (a_idx--);
4510 // Update the argument with the implicit conversion
4515 // Fill not provided arguments required by params modifier
4517 if (params_initializers == null && pd.HasParams && arg_count < pd.Count && a_idx + 1 == pd.Count) {
4518 if (arguments == null)
4519 arguments = new ArrayList (1);
4521 pt = pd.Types [GetApplicableParametersCount (method, pd) - 1];
4522 pt = TypeManager.GetElementType (pt);
4523 has_unsafe_arg |= pt.IsPointer;
4524 params_initializers = new ArrayList (0);
4527 if (a_idx == arg_count) {
4529 // Append an array argument with all params arguments
4531 if (params_initializers != null) {
4532 arguments.Add (new Argument (
4533 new ArrayCreation (new TypeExpression (pt, loc), "[]",
4534 params_initializers, loc).Resolve (ec)));
4537 if (has_unsafe_arg && !ec.InUnsafe) {
4546 if (!may_fail && Report.Errors == errors) {
4547 if (CustomErrorHandler != null)
4548 CustomErrorHandler.NoExactMatch (ec, best_candidate);
4550 Error_InvalidArguments (ec, loc, a_pos, method, a, pd, pt);
4556 public class ConstantExpr : MemberExpr
4560 public ConstantExpr (FieldInfo constant, Location loc)
4562 this.constant = constant;
4566 public override string Name {
4567 get { throw new NotImplementedException (); }
4570 public override bool IsInstance {
4571 get { return !IsStatic; }
4574 public override bool IsStatic {
4575 get { return constant.IsStatic; }
4578 public override Type DeclaringType {
4579 get { return constant.DeclaringType; }
4582 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc, SimpleName original)
4584 constant = TypeManager.GetGenericFieldDefinition (constant);
4586 IConstant ic = TypeManager.GetConstant (constant);
4588 if (constant.IsLiteral) {
4589 ic = new ExternalConstant (constant);
4591 ic = ExternalConstant.CreateDecimal (constant);
4592 // HACK: decimal field was not resolved as constant
4594 return new FieldExpr (constant, loc).ResolveMemberAccess (ec, left, loc, original);
4596 TypeManager.RegisterConstant (constant, ic);
4599 return base.ResolveMemberAccess (ec, left, loc, original);
4602 public override Expression CreateExpressionTree (EmitContext ec)
4604 throw new NotSupportedException ("ET");
4607 public override Expression DoResolve (EmitContext ec)
4609 IConstant ic = TypeManager.GetConstant (constant);
4610 if (ic.ResolveValue ()) {
4611 if (!ec.IsInObsoleteScope)
4612 ic.CheckObsoleteness (loc);
4615 return ic.CreateConstantReference (loc);
4618 public override void Emit (EmitContext ec)
4620 throw new NotSupportedException ();
4623 public override string GetSignatureForError ()
4625 return TypeManager.GetFullNameSignature (constant);
4630 /// Fully resolved expression that evaluates to a Field
4632 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariableReference {
4633 public FieldInfo FieldInfo;
4634 readonly Type constructed_generic_type;
4635 VariableInfo variable_info;
4637 LocalTemporary temp;
4639 bool in_initializer;
4641 public FieldExpr (FieldInfo fi, Location l, bool in_initializer):
4644 this.in_initializer = in_initializer;
4647 public FieldExpr (FieldInfo fi, Location l)
4650 eclass = ExprClass.Variable;
4651 type = TypeManager.TypeToCoreType (fi.FieldType);
4655 public FieldExpr (FieldInfo fi, Type genericType, Location l)
4658 this.constructed_generic_type = genericType;
4661 public override string Name {
4663 return FieldInfo.Name;
4667 public override bool IsInstance {
4669 return !FieldInfo.IsStatic;
4673 public override bool IsStatic {
4675 return FieldInfo.IsStatic;
4679 public override Type DeclaringType {
4681 return FieldInfo.DeclaringType;
4685 public override string GetSignatureForError ()
4687 return TypeManager.GetFullNameSignature (FieldInfo);
4690 public VariableInfo VariableInfo {
4692 return variable_info;
4696 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
4697 SimpleName original)
4699 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
4700 Type t = fi.FieldType;
4702 if (t.IsPointer && !ec.InUnsafe) {
4706 return base.ResolveMemberAccess (ec, left, loc, original);
4709 public void SetHasAddressTaken ()
4711 IVariableReference vr = InstanceExpression as IVariableReference;
4713 vr.SetHasAddressTaken ();
4716 public override Expression CreateExpressionTree (EmitContext ec)
4718 Expression instance;
4719 if (InstanceExpression == null) {
4720 instance = new NullLiteral (loc);
4722 instance = InstanceExpression.CreateExpressionTree (ec);
4725 ArrayList args = new ArrayList (2);
4726 args.Add (new Argument (instance));
4727 args.Add (new Argument (CreateTypeOfExpression ()));
4728 return CreateExpressionFactoryCall ("Field", args);
4731 public Expression CreateTypeOfExpression ()
4733 return new TypeOfField (FieldInfo, loc);
4736 override public Expression DoResolve (EmitContext ec)
4738 return DoResolve (ec, false, false);
4741 Expression DoResolve (EmitContext ec, bool lvalue_instance, bool out_access)
4743 if (!FieldInfo.IsStatic){
4744 if (InstanceExpression == null){
4746 // This can happen when referencing an instance field using
4747 // a fully qualified type expression: TypeName.InstanceField = xxx
4749 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4753 // Resolve the field's instance expression while flow analysis is turned
4754 // off: when accessing a field "a.b", we must check whether the field
4755 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4757 if (lvalue_instance) {
4758 using (ec.With (EmitContext.Flags.DoFlowAnalysis, false)) {
4759 Expression right_side =
4760 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4761 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side, loc);
4764 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
4765 InstanceExpression = InstanceExpression.Resolve (ec, rf);
4768 if (InstanceExpression == null)
4771 using (ec.Set (EmitContext.Flags.OmitStructFlowAnalysis)) {
4772 InstanceExpression.CheckMarshalByRefAccess (ec);
4776 if (!in_initializer && !ec.IsInFieldInitializer) {
4777 ObsoleteAttribute oa;
4778 FieldBase f = TypeManager.GetField (FieldInfo);
4780 if (!ec.IsInObsoleteScope)
4781 f.CheckObsoleteness (loc);
4783 // To be sure that type is external because we do not register generated fields
4784 } else if (!(FieldInfo.DeclaringType is TypeBuilder)) {
4785 oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
4787 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
4791 IFixedBuffer fb = AttributeTester.GetFixedBuffer (FieldInfo);
4792 IVariableReference var = InstanceExpression as IVariableReference;
4795 if (!ec.InFixedInitializer && ec.ContainerType.IsValueType) {
4796 Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4799 if (InstanceExpression.eclass != ExprClass.Variable) {
4800 Report.SymbolRelatedToPreviousError (FieldInfo);
4801 Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4802 TypeManager.GetFullNameSignature (FieldInfo));
4803 } else if (var != null && var.IsHoisted) {
4804 AnonymousMethodExpression.Error_AddressOfCapturedVar (var, loc);
4807 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4810 // If the instance expression is a local variable or parameter.
4811 if (var == null || var.VariableInfo == null)
4814 VariableInfo vi = var.VariableInfo;
4815 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
4818 variable_info = vi.GetSubStruct (FieldInfo.Name);
4822 static readonly int [] codes = {
4823 191, // instance, write access
4824 192, // instance, out access
4825 198, // static, write access
4826 199, // static, out access
4827 1648, // member of value instance, write access
4828 1649, // member of value instance, out access
4829 1650, // member of value static, write access
4830 1651 // member of value static, out access
4833 static readonly string [] msgs = {
4834 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4835 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4836 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4837 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4838 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4839 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4840 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4841 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4844 // The return value is always null. Returning a value simplifies calling code.
4845 Expression Report_AssignToReadonly (Expression right_side)
4848 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4852 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4854 Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4859 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4861 IVariableReference var = InstanceExpression as IVariableReference;
4862 if (var != null && var.VariableInfo != null)
4863 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
4865 bool lvalue_instance = !FieldInfo.IsStatic && FieldInfo.DeclaringType.IsValueType;
4866 bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
4868 Expression e = DoResolve (ec, lvalue_instance, out_access);
4873 FieldBase fb = TypeManager.GetField (FieldInfo);
4877 if (FieldInfo.IsInitOnly) {
4878 // InitOnly fields can only be assigned in constructors or initializers
4879 if (!ec.IsInFieldInitializer && !ec.IsConstructor)
4880 return Report_AssignToReadonly (right_side);
4882 if (ec.IsConstructor) {
4883 Type ctype = ec.TypeContainer.CurrentType;
4885 ctype = ec.ContainerType;
4887 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4888 if (!TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
4889 return Report_AssignToReadonly (right_side);
4890 // static InitOnly fields cannot be assigned-to in an instance constructor
4891 if (IsStatic && !ec.IsStatic)
4892 return Report_AssignToReadonly (right_side);
4893 // instance constructors can't modify InitOnly fields of other instances of the same type
4894 if (!IsStatic && !(InstanceExpression is This))
4895 return Report_AssignToReadonly (right_side);
4899 if (right_side == EmptyExpression.OutAccess &&
4900 !IsStatic && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type)) {
4901 Report.SymbolRelatedToPreviousError (DeclaringType);
4902 Report.Warning (197, 1, loc,
4903 "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",
4904 GetSignatureForError ());
4910 bool is_marshal_by_ref ()
4912 return !IsStatic && Type.IsValueType && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type);
4915 public override void CheckMarshalByRefAccess (EmitContext ec)
4917 if (is_marshal_by_ref () && !(InstanceExpression is This)) {
4918 Report.SymbolRelatedToPreviousError (DeclaringType);
4919 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",
4920 GetSignatureForError ());
4924 public override int GetHashCode ()
4926 return FieldInfo.GetHashCode ();
4929 public bool IsFixedVariable {
4932 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
4934 IVariableReference variable = InstanceExpression as IVariableReference;
4935 return variable != null && InstanceExpression.Type.IsValueType && variable.IsFixedVariable;
4939 public bool IsHoisted {
4941 IVariableReference hv = InstanceExpression as IVariableReference;
4942 return hv != null && hv.IsHoisted;
4946 public override bool Equals (object obj)
4948 FieldExpr fe = obj as FieldExpr;
4952 if (FieldInfo != fe.FieldInfo)
4955 if (InstanceExpression == null || fe.InstanceExpression == null)
4958 return InstanceExpression.Equals (fe.InstanceExpression);
4961 public void Emit (EmitContext ec, bool leave_copy)
4963 ILGenerator ig = ec.ig;
4964 bool is_volatile = false;
4966 FieldBase f = TypeManager.GetField (FieldInfo);
4968 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4971 f.SetMemberIsUsed ();
4974 if (FieldInfo.IsStatic){
4976 ig.Emit (OpCodes.Volatile);
4978 ig.Emit (OpCodes.Ldsfld, GetConstructedFieldInfo ());
4981 EmitInstance (ec, false);
4983 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
4985 ig.Emit (OpCodes.Ldflda, GetConstructedFieldInfo ());
4986 ig.Emit (OpCodes.Ldflda, ff.Element);
4989 ig.Emit (OpCodes.Volatile);
4991 ig.Emit (OpCodes.Ldfld, GetConstructedFieldInfo ());
4996 ec.ig.Emit (OpCodes.Dup);
4997 if (!FieldInfo.IsStatic) {
4998 temp = new LocalTemporary (this.Type);
5004 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5006 FieldAttributes fa = FieldInfo.Attributes;
5007 bool is_static = (fa & FieldAttributes.Static) != 0;
5008 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
5009 ILGenerator ig = ec.ig;
5011 if (is_readonly && !ec.IsConstructor){
5012 Report_AssignToReadonly (source);
5016 prepared = prepare_for_load;
5017 EmitInstance (ec, prepared);
5021 ec.ig.Emit (OpCodes.Dup);
5022 if (!FieldInfo.IsStatic) {
5023 temp = new LocalTemporary (this.Type);
5028 FieldBase f = TypeManager.GetField (FieldInfo);
5030 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
5031 ig.Emit (OpCodes.Volatile);
5037 ig.Emit (OpCodes.Stsfld, GetConstructedFieldInfo ());
5039 ig.Emit (OpCodes.Stfld, GetConstructedFieldInfo ());
5048 public override void Emit (EmitContext ec)
5053 public override void EmitSideEffect (EmitContext ec)
5055 FieldBase f = TypeManager.GetField (FieldInfo);
5056 bool is_volatile = f != null && (f.ModFlags & Modifiers.VOLATILE) != 0;
5058 if (is_volatile || is_marshal_by_ref ())
5059 base.EmitSideEffect (ec);
5062 public override void Error_VariableIsUsedBeforeItIsDeclared (string name)
5064 Report.Error (844, loc,
5065 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the field `{1}'",
5066 name, GetSignatureForError ());
5069 public void AddressOf (EmitContext ec, AddressOp mode)
5071 ILGenerator ig = ec.ig;
5073 FieldBase f = TypeManager.GetField (FieldInfo);
5075 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
5076 Report.Warning (420, 1, loc, "`{0}': A volatile field references will not be treated as volatile",
5077 f.GetSignatureForError ());
5080 if ((mode & AddressOp.Store) != 0)
5082 if ((mode & AddressOp.Load) != 0)
5083 f.SetMemberIsUsed ();
5087 // Handle initonly fields specially: make a copy and then
5088 // get the address of the copy.
5091 if (FieldInfo.IsInitOnly){
5093 if (ec.IsConstructor){
5094 if (FieldInfo.IsStatic){
5106 local = ig.DeclareLocal (type);
5107 ig.Emit (OpCodes.Stloc, local);
5108 ig.Emit (OpCodes.Ldloca, local);
5113 if (FieldInfo.IsStatic){
5114 ig.Emit (OpCodes.Ldsflda, GetConstructedFieldInfo ());
5117 EmitInstance (ec, false);
5118 ig.Emit (OpCodes.Ldflda, GetConstructedFieldInfo ());
5122 FieldInfo GetConstructedFieldInfo ()
5124 if (constructed_generic_type == null)
5127 return TypeBuilder.GetField (constructed_generic_type, FieldInfo);
5129 throw new NotSupportedException ();
5133 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5135 FieldInfo = storey.MutateField (FieldInfo);
5136 base.MutateHoistedGenericType (storey);
5142 /// Expression that evaluates to a Property. The Assign class
5143 /// might set the `Value' expression if we are in an assignment.
5145 /// This is not an LValue because we need to re-write the expression, we
5146 /// can not take data from the stack and store it.
5148 public class PropertyExpr : MemberExpr, IAssignMethod {
5149 public readonly PropertyInfo PropertyInfo;
5150 MethodInfo getter, setter;
5155 LocalTemporary temp;
5158 public PropertyExpr (Type container_type, PropertyInfo pi, Location l)
5161 eclass = ExprClass.PropertyAccess;
5165 type = TypeManager.TypeToCoreType (pi.PropertyType);
5167 ResolveAccessors (container_type);
5170 public override string Name {
5172 return PropertyInfo.Name;
5176 public override bool IsInstance {
5182 public override bool IsStatic {
5188 public override Expression CreateExpressionTree (EmitContext ec)
5191 if (IsSingleDimensionalArrayLength ()) {
5192 args = new ArrayList (1);
5193 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5194 return CreateExpressionFactoryCall ("ArrayLength", args);
5198 Error_BaseAccessInExpressionTree (loc);
5202 args = new ArrayList (2);
5203 if (InstanceExpression == null)
5204 args.Add (new Argument (new NullLiteral (loc)));
5206 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5207 args.Add (new Argument (new TypeOfMethodInfo (getter, loc)));
5208 return CreateExpressionFactoryCall ("Property", args);
5211 public Expression CreateSetterTypeOfExpression ()
5213 return new TypeOfMethodInfo (setter, loc);
5216 public override Type DeclaringType {
5218 return PropertyInfo.DeclaringType;
5222 public override string GetSignatureForError ()
5224 return TypeManager.GetFullNameSignature (PropertyInfo);
5227 void FindAccessors (Type invocation_type)
5229 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
5230 BindingFlags.Static | BindingFlags.Instance |
5231 BindingFlags.DeclaredOnly;
5233 Type current = PropertyInfo.DeclaringType;
5234 for (; current != null; current = current.BaseType) {
5235 MemberInfo[] group = TypeManager.MemberLookup (
5236 invocation_type, invocation_type, current,
5237 MemberTypes.Property, flags, PropertyInfo.Name, null);
5242 if (group.Length != 1)
5243 // Oooops, can this ever happen ?
5246 PropertyInfo pi = (PropertyInfo) group [0];
5249 getter = pi.GetGetMethod (true);
5252 setter = pi.GetSetMethod (true);
5254 MethodInfo accessor = getter != null ? getter : setter;
5256 if (!accessor.IsVirtual)
5262 // We also perform the permission checking here, as the PropertyInfo does not
5263 // hold the information for the accessibility of its setter/getter
5265 // TODO: Refactor to use some kind of cache together with GetPropertyFromAccessor
5266 void ResolveAccessors (Type container_type)
5268 FindAccessors (container_type);
5270 if (getter != null) {
5271 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
5272 IMethodData md = TypeManager.GetMethod (the_getter);
5274 md.SetMemberIsUsed ();
5276 is_static = getter.IsStatic;
5279 if (setter != null) {
5280 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
5281 IMethodData md = TypeManager.GetMethod (the_setter);
5283 md.SetMemberIsUsed ();
5285 is_static = setter.IsStatic;
5289 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5291 if (InstanceExpression != null)
5292 InstanceExpression.MutateHoistedGenericType (storey);
5294 type = storey.MutateType (type);
5295 getter = storey.MutateGenericMethod (getter);
5298 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
5301 InstanceExpression = null;
5305 if (InstanceExpression == null) {
5306 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5310 InstanceExpression = InstanceExpression.DoResolve (ec);
5311 if (lvalue_instance && InstanceExpression != null)
5312 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
5314 if (InstanceExpression == null)
5317 InstanceExpression.CheckMarshalByRefAccess (ec);
5319 if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) &&
5320 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
5321 !TypeManager.IsNestedChildOf (ec.ContainerType, InstanceExpression.Type) &&
5322 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.ContainerType)) {
5323 Report.SymbolRelatedToPreviousError (PropertyInfo);
5324 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
5331 void Error_PropertyNotFound (MethodInfo mi, bool getter)
5333 // TODO: correctly we should compare arguments but it will lead to bigger changes
5334 if (mi is MethodBuilder) {
5335 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
5339 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
5341 AParametersCollection iparams = TypeManager.GetParameterData (mi);
5342 sig.Append (getter ? "get_" : "set_");
5344 sig.Append (iparams.GetSignatureForError ());
5346 Report.SymbolRelatedToPreviousError (mi);
5347 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
5348 Name, sig.ToString ());
5351 public bool IsAccessibleFrom (Type invocation_type, bool lvalue)
5354 MethodInfo accessor = lvalue ? setter : getter;
5355 if (accessor == null && lvalue)
5357 return accessor != null && IsAccessorAccessible (invocation_type, accessor, out dummy);
5360 bool IsSingleDimensionalArrayLength ()
5362 if (DeclaringType != TypeManager.array_type || getter == null || Name != "Length")
5365 string t_name = InstanceExpression.Type.Name;
5366 int t_name_len = t_name.Length;
5367 return t_name_len > 2 && t_name [t_name_len - 2] == '[';
5370 override public Expression DoResolve (EmitContext ec)
5375 if (getter != null){
5376 if (TypeManager.GetParameterData (getter).Count != 0){
5377 Error_PropertyNotFound (getter, true);
5382 if (getter == null){
5384 // The following condition happens if the PropertyExpr was
5385 // created, but is invalid (ie, the property is inaccessible),
5386 // and we did not want to embed the knowledge about this in
5387 // the caller routine. This only avoids double error reporting.
5392 if (InstanceExpression != EmptyExpression.Null) {
5393 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5394 TypeManager.GetFullNameSignature (PropertyInfo));
5399 bool must_do_cs1540_check = false;
5400 if (getter != null &&
5401 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
5402 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
5403 if (pm != null && pm.HasCustomAccessModifier) {
5404 Report.SymbolRelatedToPreviousError (pm);
5405 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5406 TypeManager.CSharpSignature (getter));
5409 Report.SymbolRelatedToPreviousError (getter);
5410 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
5415 if (!InstanceResolve (ec, false, must_do_cs1540_check))
5419 // Only base will allow this invocation to happen.
5421 if (IsBase && getter.IsAbstract) {
5422 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5426 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
5436 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
5438 if (right_side == EmptyExpression.OutAccess) {
5439 if (ec.CurrentBlock.Toplevel.GetTransparentIdentifier (PropertyInfo.Name) != null) {
5440 Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5443 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as `ref' or `out' parameter",
5444 GetSignatureForError ());
5449 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5450 Error_CannotModifyIntermediateExpressionValue (ec);
5453 if (setter == null){
5455 // The following condition happens if the PropertyExpr was
5456 // created, but is invalid (ie, the property is inaccessible),
5457 // and we did not want to embed the knowledge about this in
5458 // the caller routine. This only avoids double error reporting.
5463 if (ec.CurrentBlock.Toplevel.GetTransparentIdentifier (PropertyInfo.Name) != null) {
5464 Report.Error (1947, loc, "A range variable `{0}' cannot be assigned to. Consider using `let' clause to store the value",
5467 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
5468 GetSignatureForError ());
5473 if (TypeManager.GetParameterData (setter).Count != 1){
5474 Error_PropertyNotFound (setter, false);
5478 bool must_do_cs1540_check;
5479 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
5480 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
5481 if (pm != null && pm.HasCustomAccessModifier) {
5482 Report.SymbolRelatedToPreviousError (pm);
5483 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5484 TypeManager.CSharpSignature (setter));
5487 Report.SymbolRelatedToPreviousError (setter);
5488 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
5493 if (!InstanceResolve (ec, PropertyInfo.DeclaringType.IsValueType, must_do_cs1540_check))
5497 // Only base will allow this invocation to happen.
5499 if (IsBase && setter.IsAbstract){
5500 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5504 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe) {
5511 public override void Emit (EmitContext ec)
5516 public void Emit (EmitContext ec, bool leave_copy)
5519 // Special case: length of single dimension array property is turned into ldlen
5521 if (IsSingleDimensionalArrayLength ()) {
5523 EmitInstance (ec, false);
5524 ec.ig.Emit (OpCodes.Ldlen);
5525 ec.ig.Emit (OpCodes.Conv_I4);
5529 Invocation.EmitCall (ec, IsBase, InstanceExpression, getter, null, loc, prepared, false);
5532 ec.ig.Emit (OpCodes.Dup);
5534 temp = new LocalTemporary (this.Type);
5541 // Implements the IAssignMethod interface for assignments
5543 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5545 Expression my_source = source;
5547 if (prepare_for_load) {
5552 ec.ig.Emit (OpCodes.Dup);
5554 temp = new LocalTemporary (this.Type);
5558 } else if (leave_copy) {
5560 temp = new LocalTemporary (this.Type);
5565 ArrayList args = new ArrayList (1);
5566 args.Add (new Argument (my_source, Argument.AType.Expression));
5568 Invocation.EmitCall (ec, IsBase, InstanceExpression, setter, args, loc, false, prepared);
5578 /// Fully resolved expression that evaluates to an Event
5580 public class EventExpr : MemberExpr {
5581 public readonly EventInfo EventInfo;
5584 MethodInfo add_accessor, remove_accessor;
5586 public EventExpr (EventInfo ei, Location loc)
5590 eclass = ExprClass.EventAccess;
5592 add_accessor = TypeManager.GetAddMethod (ei);
5593 remove_accessor = TypeManager.GetRemoveMethod (ei);
5594 if (add_accessor.IsStatic || remove_accessor.IsStatic)
5597 if (EventInfo is MyEventBuilder){
5598 MyEventBuilder eb = (MyEventBuilder) EventInfo;
5599 type = eb.EventType;
5602 type = EventInfo.EventHandlerType;
5605 public override string Name {
5607 return EventInfo.Name;
5611 public override bool IsInstance {
5617 public override bool IsStatic {
5623 public override Type DeclaringType {
5625 return EventInfo.DeclaringType;
5629 void Error_AssignmentEventOnly ()
5631 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5632 GetSignatureForError ());
5635 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
5636 SimpleName original)
5639 // If the event is local to this class, we transform ourselves into a FieldExpr
5642 if (EventInfo.DeclaringType == ec.ContainerType ||
5643 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
5644 EventField mi = TypeManager.GetEventField (EventInfo);
5647 if (!ec.IsInObsoleteScope)
5648 mi.CheckObsoleteness (loc);
5650 if ((mi.ModFlags & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0 && !ec.IsInCompoundAssignment)
5651 Error_AssignmentEventOnly ();
5653 FieldExpr ml = new FieldExpr (mi.FieldBuilder, loc);
5655 InstanceExpression = null;
5657 return ml.ResolveMemberAccess (ec, left, loc, original);
5661 if (left is This && !ec.IsInCompoundAssignment)
5662 Error_AssignmentEventOnly ();
5664 return base.ResolveMemberAccess (ec, left, loc, original);
5667 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
5670 InstanceExpression = null;
5674 if (InstanceExpression == null) {
5675 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5679 InstanceExpression = InstanceExpression.DoResolve (ec);
5680 if (InstanceExpression == null)
5683 if (IsBase && add_accessor.IsAbstract) {
5684 Error_CannotCallAbstractBase(TypeManager.CSharpSignature(add_accessor));
5689 // This is using the same mechanism as the CS1540 check in PropertyExpr.
5690 // However, in the Event case, we reported a CS0122 instead.
5692 // TODO: Exact copy from PropertyExpr
5694 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
5695 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
5696 !TypeManager.IsNestedChildOf (ec.ContainerType, InstanceExpression.Type) &&
5697 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.ContainerType)) {
5698 Report.SymbolRelatedToPreviousError (EventInfo);
5699 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5706 public bool IsAccessibleFrom (Type invocation_type)
5709 return IsAccessorAccessible (invocation_type, add_accessor, out dummy) &&
5710 IsAccessorAccessible (invocation_type, remove_accessor, out dummy);
5713 public override Expression CreateExpressionTree (EmitContext ec)
5715 throw new NotSupportedException ("ET");
5718 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5720 // contexts where an LValue is valid have already devolved to FieldExprs
5721 Error_CannotAssign ();
5725 public override Expression DoResolve (EmitContext ec)
5727 bool must_do_cs1540_check;
5728 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
5729 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
5730 Report.SymbolRelatedToPreviousError (EventInfo);
5731 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5735 if (!InstanceResolve (ec, must_do_cs1540_check))
5738 if (!ec.IsInCompoundAssignment) {
5739 Error_CannotAssign ();
5746 public override void Emit (EmitContext ec)
5748 Error_CannotAssign ();
5751 public void Error_CannotAssign ()
5753 Report.Error (70, loc,
5754 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
5755 GetSignatureForError (), TypeManager.CSharpName (EventInfo.DeclaringType));
5758 public override string GetSignatureForError ()
5760 return TypeManager.CSharpSignature (EventInfo);
5763 public void EmitAddOrRemove (EmitContext ec, bool is_add, Expression source)
5765 ArrayList args = new ArrayList (1);
5766 args.Add (new Argument (source, Argument.AType.Expression));
5767 Invocation.EmitCall (ec, IsBase, InstanceExpression, is_add ? add_accessor : remove_accessor, args, loc);
5771 public class TemporaryVariable : VariableReference
5775 public TemporaryVariable (Type type, Location loc)
5779 eclass = ExprClass.Variable;
5782 public override Expression CreateExpressionTree (EmitContext ec)
5784 throw new NotSupportedException ("ET");
5787 public override Expression DoResolve (EmitContext ec)
5792 TypeExpr te = new TypeExpression (type, loc);
5793 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
5794 if (!li.Resolve (ec))
5798 // Don't capture temporary variables except when using
5799 // iterator redirection
5801 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.IsIterator && ec.IsVariableCapturingRequired) {
5802 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
5803 storey.CaptureLocalVariable (ec, li);
5809 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5811 return DoResolve (ec);
5814 public override void Emit (EmitContext ec)
5819 public void EmitAssign (EmitContext ec, Expression source)
5821 EmitAssign (ec, source, false, false);
5824 public override HoistedVariable HoistedVariable {
5825 get { return li.HoistedVariableReference; }
5828 public override bool IsFixedVariable {
5829 get { return true; }
5832 public override bool IsRef {
5833 get { return false; }
5836 public override string Name {
5837 get { throw new NotImplementedException (); }
5840 public override void SetHasAddressTaken ()
5842 throw new NotImplementedException ();
5845 protected override ILocalVariable Variable {
5849 public override VariableInfo VariableInfo {
5850 get { throw new NotImplementedException (); }
5855 /// Handles `var' contextual keyword; var becomes a keyword only
5856 /// if no type called var exists in a variable scope
5858 public class VarExpr : SimpleName
5860 // Used for error reporting only
5861 ArrayList initializer;
5863 public VarExpr (Location loc)
5868 public ArrayList VariableInitializer {
5870 this.initializer = value;
5874 public bool InferType (EmitContext ec, Expression right_side)
5877 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
5879 type = right_side.Type;
5880 if (type == TypeManager.null_type || type == TypeManager.void_type || type == TypeManager.anonymous_method_type) {
5881 Report.Error (815, loc, "An implicitly typed local variable declaration cannot be initialized with `{0}'",
5882 right_side.GetSignatureForError ());
5886 eclass = ExprClass.Variable;
5890 protected override void Error_TypeOrNamespaceNotFound (IResolveContext ec)
5892 Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");
5895 public override TypeExpr ResolveAsContextualType (IResolveContext rc, bool silent)
5897 TypeExpr te = base.ResolveAsContextualType (rc, true);
5901 if (initializer == null)
5904 if (initializer.Count > 1) {
5905 Location loc = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [1]).Location;
5906 Report.Error (819, loc, "An implicitly typed local variable declaration cannot include multiple declarators");
5911 Expression variable_initializer = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [0]).expression_or_array_initializer;
5912 if (variable_initializer == null) {
5913 Report.Error (818, loc, "An implicitly typed local variable declarator must include an initializer");