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.
14 using System.Collections.Generic;
15 using System.Diagnostics;
16 using System.Reflection;
17 using System.Reflection.Emit;
19 using SLE = System.Linq.Expressions;
22 namespace Mono.CSharp {
25 /// The ExprClass class contains the is used to pass the
26 /// classification of an expression (value, variable, namespace,
27 /// type, method group, property access, event access, indexer access,
30 public enum ExprClass : byte {
46 /// This is used to tell Resolve in which types of expressions we're
50 public enum ResolveFlags {
51 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
54 // Returns a type expression.
57 // Returns a method group.
60 TypeParameter = 1 << 3,
62 // Mask of all the expression class flags.
63 MaskExprClass = VariableOrValue | Type | MethodGroup | TypeParameter,
65 // Set if this is resolving the first part of a MemberAccess.
66 Intermediate = 1 << 11,
70 // This is just as a hint to AddressOf of what will be done with the
73 public enum AddressOp {
80 /// This interface is implemented by variables
82 public interface IMemoryLocation {
84 /// The AddressOf method should generate code that loads
85 /// the address of the object and leaves it on the stack.
87 /// The `mode' argument is used to notify the expression
88 /// of whether this will be used to read from the address or
89 /// write to the address.
91 /// This is just a hint that can be used to provide good error
92 /// reporting, and should have no other side effects.
94 void AddressOf (EmitContext ec, AddressOp mode);
98 // An expressions resolved as a direct variable reference
100 public interface IVariableReference : IFixedExpression
102 bool IsHoisted { get; }
104 VariableInfo VariableInfo { get; }
106 void SetHasAddressTaken ();
110 // Implemented by an expression which could be or is always
113 public interface IFixedExpression
115 bool IsFixed { get; }
119 /// Base class for expressions
121 public abstract class Expression {
122 public ExprClass eclass;
124 protected Location loc;
128 set { type = value; }
131 public virtual Location Location {
135 // Not nice but we have broken hierarchy.
136 public virtual void CheckMarshalByRefAccess (ResolveContext ec)
140 public virtual bool GetAttributableValue (ResolveContext ec, Type value_type, out object value)
142 Attribute.Error_AttributeArgumentNotValid (ec, loc);
147 public virtual string GetSignatureForError ()
149 return TypeManager.CSharpName (type);
152 public static bool IsAccessorAccessible (Type invocation_type, MethodSpec mi, out bool must_do_cs1540_check)
154 var ma = mi.Modifiers & Modifiers.AccessibilityMask;
156 must_do_cs1540_check = false; // by default we do not check for this
158 if (ma == Modifiers.PUBLIC)
162 // If only accessible to the current class or children
164 if (ma == Modifiers.PRIVATE)
165 return TypeManager.IsPrivateAccessible (invocation_type, mi.DeclaringType) ||
166 TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType);
168 if ((ma & Modifiers.INTERNAL) != 0) {
169 var b = TypeManager.IsThisOrFriendAssembly (invocation_type.Assembly, mi.DeclaringType.Assembly);
170 if (b || ma == Modifiers.INTERNAL)
174 // Family and FamANDAssem require that we derive.
175 // FamORAssem requires that we derive if in different assemblies.
176 if (!TypeManager.IsNestedFamilyAccessible (invocation_type, mi.DeclaringType))
179 if (!TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType))
180 must_do_cs1540_check = true;
185 public virtual bool IsNull {
192 /// Performs semantic analysis on the Expression
196 /// The Resolve method is invoked to perform the semantic analysis
199 /// The return value is an expression (it can be the
200 /// same expression in some cases) or a new
201 /// expression that better represents this node.
203 /// For example, optimizations of Unary (LiteralInt)
204 /// would return a new LiteralInt with a negated
207 /// If there is an error during semantic analysis,
208 /// then an error should be reported (using Report)
209 /// and a null value should be returned.
211 /// There are two side effects expected from calling
212 /// Resolve(): the the field variable "eclass" should
213 /// be set to any value of the enumeration
214 /// `ExprClass' and the type variable should be set
215 /// to a valid type (this is the type of the
218 protected abstract Expression DoResolve (ResolveContext rc);
220 public virtual Expression DoResolveLValue (ResolveContext rc, Expression right_side)
226 // This is used if the expression should be resolved as a type or namespace name.
227 // the default implementation fails.
229 public virtual FullNamedExpression ResolveAsTypeStep (IMemberContext rc, bool silent)
232 ResolveContext ec = new ResolveContext (rc);
233 Expression e = Resolve (ec);
235 e.Error_UnexpectedKind (ec, ResolveFlags.Type, loc);
242 // C# 3.0 introduced contextual keywords (var) which behaves like a type if type with
243 // same name exists or as a keyword when no type was found
245 public virtual TypeExpr ResolveAsContextualType (IMemberContext rc, bool silent)
247 return ResolveAsTypeTerminal (rc, silent);
251 // This is used to resolve the expression as a type, a null
252 // value will be returned if the expression is not a type
255 public virtual TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
257 TypeExpr te = ResolveAsBaseTerminal (ec, silent);
261 if (!silent) { // && !(te is TypeParameterExpr)) {
262 ObsoleteAttribute obsolete_attr = AttributeTester.GetObsoleteAttribute (te.Type);
263 if (obsolete_attr != null && !ec.IsObsolete) {
264 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, ec.Compiler.Report);
268 GenericTypeExpr ct = te as GenericTypeExpr;
271 // TODO: Constrained type parameters check for parameters of generic method overrides is broken
272 // There are 2 solutions.
273 // 1, Skip this check completely when we are in override/explicit impl scope
274 // 2, Copy type parameters constraints from base implementation and pass (they have to be emitted anyway)
276 MemberCore gm = ec as GenericMethod;
279 if (gm != null && ((gm.ModFlags & Modifiers.OVERRIDE) != 0 || gm.MemberName.Left != null)) {
284 // TODO: silent flag is ignored
285 ct.CheckConstraints (ec);
291 public TypeExpr ResolveAsBaseTerminal (IMemberContext ec, bool silent)
293 int errors = ec.Compiler.Report.Errors;
295 FullNamedExpression fne = ResolveAsTypeStep (ec, silent);
300 TypeExpr te = fne as TypeExpr;
302 if (!silent && errors == ec.Compiler.Report.Errors)
303 fne.Error_UnexpectedKind (ec.Compiler.Report, null, "type", loc);
307 if (!te.CheckAccessLevel (ec)) {
308 ec.Compiler.Report.SymbolRelatedToPreviousError (te.Type);
309 ErrorIsInaccesible (loc, TypeManager.CSharpName (te.Type), ec.Compiler.Report);
317 public static void ErrorIsInaccesible (Location loc, string name, Report Report)
319 Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", name);
322 protected static void Error_CannotAccessProtected (ResolveContext ec, Location loc, MemberInfo m, Type qualifier, Type container)
324 ec.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 void Error_ExpressionMustBeConstant (ResolveContext rc, Location loc, string e_name)
334 rc.Report.Error (133, loc, "The expression being assigned to `{0}' must be constant", e_name);
337 public void Error_ConstantCanBeInitializedWithNullOnly (ResolveContext rc, Type type, Location loc, string name)
339 rc.Report.Error (134, loc, "A constant `{0}' of reference type `{1}' can only be initialized with null",
340 name, TypeManager.CSharpName (type));
343 public static void Error_InvalidExpressionStatement (Report Report, Location loc)
345 Report.Error (201, loc, "Only assignment, call, increment, decrement, and new object " +
346 "expressions can be used as a statement");
349 public void Error_InvalidExpressionStatement (BlockContext ec)
351 Error_InvalidExpressionStatement (ec.Report, loc);
354 public static void Error_VoidInvalidInTheContext (Location loc, Report Report)
356 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
359 public virtual void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, Type target, bool expl)
361 Error_ValueCannotBeConvertedCore (ec, loc, target, expl);
364 protected void Error_ValueCannotBeConvertedCore (ResolveContext ec, Location loc, Type target, bool expl)
366 // The error was already reported as CS1660
367 if (type == InternalType.AnonymousMethod)
370 if (TypeManager.IsGenericParameter (Type) && TypeManager.IsGenericParameter (target) && type.Name == target.Name) {
371 string sig1 = type.DeclaringMethod == null ?
372 TypeManager.CSharpName (type.DeclaringType) :
373 TypeManager.CSharpSignature (type.DeclaringMethod);
374 string sig2 = target.DeclaringMethod == null ?
375 TypeManager.CSharpName (target.DeclaringType) :
376 TypeManager.CSharpSignature (target.DeclaringMethod);
377 ec.Report.ExtraInformation (loc,
379 "The generic parameter `{0}' of `{1}' cannot be converted to the generic parameter `{0}' of `{2}' (in the previous ",
380 Type.Name, sig1, sig2));
381 } else if (Type.FullName == target.FullName){
382 ec.Report.ExtraInformation (loc,
384 "The type `{0}' has two conflicting definitions, one comes from `{1}' and the other from `{2}' (in the previous ",
385 Type.FullName, Type.Assembly.FullName, target.Assembly.FullName));
389 ec.Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
390 TypeManager.CSharpName (type), TypeManager.CSharpName (target));
394 ec.Report.DisableReporting ();
395 bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null;
396 ec.Report.EnableReporting ();
399 ec.Report.Error (266, loc, "Cannot implicitly convert type `{0}' to `{1}'. " +
400 "An explicit conversion exists (are you missing a cast?)",
401 TypeManager.CSharpName (Type), TypeManager.CSharpName (target));
405 ec.Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
406 TypeManager.CSharpName (type),
407 TypeManager.CSharpName (target));
410 public virtual void Error_VariableIsUsedBeforeItIsDeclared (Report Report, string name)
412 Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", name);
415 public void Error_TypeArgumentsCannotBeUsed (Report report, Location loc)
417 // Better message for possible generic expressions
418 if (eclass == ExprClass.MethodGroup || eclass == ExprClass.Type) {
419 if (this is TypeExpr)
420 report.SymbolRelatedToPreviousError (type);
422 string name = eclass == ExprClass.Type ? ExprClassName : "method";
423 report.Error (308, loc, "The non-generic {0} `{1}' cannot be used with the type arguments",
424 name, GetSignatureForError ());
426 report.Error (307, loc, "The {0} `{1}' cannot be used with type arguments",
427 ExprClassName, GetSignatureForError ());
431 protected virtual void Error_TypeDoesNotContainDefinition (ResolveContext ec, Type type, string name)
433 Error_TypeDoesNotContainDefinition (ec, loc, type, name);
436 public static void Error_TypeDoesNotContainDefinition (ResolveContext ec, Location loc, Type type, string name)
438 ec.Report.SymbolRelatedToPreviousError (type);
439 ec.Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
440 TypeManager.CSharpName (type), name);
443 protected static void Error_ValueAssignment (ResolveContext ec, Location loc)
445 ec.Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
448 ResolveFlags ExprClassToResolveFlags {
452 case ExprClass.Namespace:
453 return ResolveFlags.Type;
455 case ExprClass.MethodGroup:
456 return ResolveFlags.MethodGroup;
458 case ExprClass.TypeParameter:
459 return ResolveFlags.TypeParameter;
461 case ExprClass.Value:
462 case ExprClass.Variable:
463 case ExprClass.PropertyAccess:
464 case ExprClass.EventAccess:
465 case ExprClass.IndexerAccess:
466 return ResolveFlags.VariableOrValue;
469 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
475 /// Resolves an expression and performs semantic analysis on it.
479 /// Currently Resolve wraps DoResolve to perform sanity
480 /// checking and assertion checking on what we expect from Resolve.
482 public Expression Resolve (ResolveContext ec, ResolveFlags flags)
484 if (eclass != ExprClass.Unresolved)
488 if (this is SimpleName) {
489 e = ((SimpleName) this).DoResolve (ec, (flags & ResolveFlags.Intermediate) != 0);
497 if ((flags & e.ExprClassToResolveFlags) == 0) {
498 e.Error_UnexpectedKind (ec, flags, loc);
503 throw new InternalErrorException ("Expression `{0}' didn't set its type in DoResolve", e.GetType ());
509 /// Resolves an expression and performs semantic analysis on it.
511 public Expression Resolve (ResolveContext rc)
513 return Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
517 /// Resolves an expression for LValue assignment
521 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
522 /// checking and assertion checking on what we expect from Resolve
524 public Expression ResolveLValue (ResolveContext ec, Expression right_side)
526 int errors = ec.Report.Errors;
527 bool out_access = right_side == EmptyExpression.OutAccess.Instance;
529 Expression e = DoResolveLValue (ec, right_side);
531 if (e != null && out_access && !(e is IMemoryLocation)) {
532 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
533 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
535 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
536 // e.GetType () + " " + e.GetSignatureForError ());
541 if (errors == ec.Report.Errors) {
543 ec.Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
545 Error_ValueAssignment (ec, loc);
550 if (e.eclass == ExprClass.Unresolved)
551 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
553 if ((e.type == null) && !(e is GenericTypeExpr))
554 throw new Exception ("Expression " + e + " did not set its type after Resolve");
560 /// Emits the code for the expression
564 /// The Emit method is invoked to generate the code
565 /// for the expression.
567 public abstract void Emit (EmitContext ec);
569 // Emit code to branch to @target if this expression is equivalent to @on_true.
570 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
571 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
572 // including the use of conditional branches. Note also that a branch MUST be emitted
573 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
576 ec.ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
579 // Emit this expression for its side effects, not for its value.
580 // The default implementation is to emit the value, and then throw it away.
581 // Subclasses can provide more efficient implementations, but those MUST be equivalent
582 public virtual void EmitSideEffect (EmitContext ec)
585 ec.ig.Emit (OpCodes.Pop);
589 /// Protected constructor. Only derivate types should
590 /// be able to be created
593 protected Expression ()
598 /// Returns a fully formed expression after a MemberLookup
601 public static Expression ExprClassFromMemberInfo (Type container_type, MemberInfo mi, Location loc)
604 return new EventExpr (Import.CreateEvent ((EventInfo) mi), loc);
605 else if (mi is FieldInfo) {
606 FieldInfo fi = (FieldInfo) mi;
607 var spec = Import.CreateField (fi);
608 if (spec is ConstSpec)
609 return new ConstantExpr ((ConstSpec) spec, loc);
610 return new FieldExpr (spec, loc);
611 } else if (mi is PropertyInfo)
612 return new PropertyExpr (container_type, Import.CreateProperty ((PropertyInfo) mi), loc);
613 else if (mi is Type) {
614 return new TypeExpression ((System.Type) mi, loc);
620 // TODO: [Obsolete ("Can be removed")]
621 protected static IList<MemberInfo> almost_matched_members = new List<MemberInfo> (4);
624 // FIXME: Probably implement a cache for (t,name,current_access_set)?
626 // This code could use some optimizations, but we need to do some
627 // measurements. For example, we could use a delegate to `flag' when
628 // something can not any longer be a method-group (because it is something
632 // If the return value is an Array, then it is an array of
635 // If the return value is an MemberInfo, it is anything, but a Method
639 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
640 // the arguments here and have MemberLookup return only the methods that
641 // match the argument count/type, unlike we are doing now (we delay this
644 // This is so we can catch correctly attempts to invoke instance methods
645 // from a static body (scan for error 120 in ResolveSimpleName).
648 // FIXME: Potential optimization, have a static ArrayList
651 public static Expression MemberLookup (CompilerContext ctx, Type container_type, Type queried_type, string name,
652 MemberTypes mt, BindingFlags bf, Location loc)
654 return MemberLookup (ctx, container_type, null, queried_type, name, mt, bf, loc);
658 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
659 // `qualifier_type' or null to lookup members in the current class.
662 public static Expression MemberLookup (CompilerContext ctx, Type container_type,
663 Type qualifier_type, Type queried_type,
664 string name, MemberTypes mt,
665 BindingFlags bf, Location loc)
667 almost_matched_members.Clear ();
669 MemberInfo [] mi = TypeManager.MemberLookup (container_type, qualifier_type,
670 queried_type, mt, bf, name, almost_matched_members);
676 bool is_interface = qualifier_type != null && qualifier_type.IsInterface;
677 var methods = new List<MethodSpec> (2);
678 List<MemberInfo> non_methods = null;
680 foreach (var m in mi) {
681 if (m is MethodBase) {
682 methods.Add (Import.CreateMethod ((MethodBase) m));
686 if (non_methods == null)
687 non_methods = new List<MemberInfo> (2);
689 bool is_candidate = true;
690 for (int i = 0; i < non_methods.Count; ++i) {
691 MemberInfo n_m = non_methods [i];
692 if (n_m.DeclaringType.IsInterface && TypeManager.ImplementsInterface (m.DeclaringType, n_m.DeclaringType)) {
693 non_methods.Remove (n_m);
695 } else if (m.DeclaringType.IsInterface && TypeManager.ImplementsInterface (n_m.DeclaringType, m.DeclaringType)) {
696 is_candidate = false;
706 if (methods.Count == 0 && non_methods != null && non_methods.Count > 1) {
707 ctx.Report.SymbolRelatedToPreviousError (non_methods [1]);
708 ctx.Report.SymbolRelatedToPreviousError (non_methods [0]);
709 ctx.Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
710 TypeManager.GetFullNameSignature (non_methods [1]),
711 TypeManager.GetFullNameSignature (non_methods [0]));
715 if (methods.Count == 0)
716 return ExprClassFromMemberInfo (container_type, (MemberInfo)non_methods [0], loc);
718 if (non_methods != null && non_methods.Count > 0) {
719 var method = methods [0];
720 MemberInfo non_method = (MemberInfo) non_methods [0];
721 if (method.DeclaringType == non_method.DeclaringType) {
722 // Cannot happen with C# code, but is valid in IL
723 ctx.Report.SymbolRelatedToPreviousError (method.MetaInfo);
724 ctx.Report.SymbolRelatedToPreviousError (non_method);
725 ctx.Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
726 TypeManager.GetFullNameSignature (non_method),
727 TypeManager.CSharpSignature (method.MetaInfo));
732 ctx.Report.SymbolRelatedToPreviousError (method.MetaInfo);
733 ctx.Report.SymbolRelatedToPreviousError (non_method);
734 ctx.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and non-method `{1}'. Using method `{0}'",
735 TypeManager.CSharpSignature (method.MetaInfo), TypeManager.GetFullNameSignature (non_method));
739 return new MethodGroupExpr (methods, queried_type, loc);
742 if (mi [0] is MethodBase)
743 return new MethodGroupExpr (mi.Select (l => Import.CreateMethod ((MethodBase) l)).ToArray (), queried_type, loc);
745 return ExprClassFromMemberInfo (container_type, mi [0], loc);
748 public const MemberTypes AllMemberTypes =
749 MemberTypes.Constructor |
753 MemberTypes.NestedType |
754 MemberTypes.Property;
756 public const BindingFlags AllBindingFlags =
757 BindingFlags.Public |
758 BindingFlags.Static |
759 BindingFlags.Instance;
761 public static Expression MemberLookup (CompilerContext ctx, Type container_type, Type queried_type,
762 string name, Location loc)
764 return MemberLookup (ctx, container_type, null, queried_type, name,
765 AllMemberTypes, AllBindingFlags, loc);
768 public static Expression MemberLookup (CompilerContext ctx, Type container_type, Type qualifier_type,
769 Type queried_type, string name, Location loc)
771 return MemberLookup (ctx, container_type, qualifier_type, queried_type,
772 name, AllMemberTypes, AllBindingFlags, loc);
775 public static MethodGroupExpr MethodLookup (CompilerContext ctx, Type container_type, Type queried_type,
776 string name, Location loc)
778 return (MethodGroupExpr)MemberLookup (ctx, container_type, null, queried_type, name,
779 MemberTypes.Method, AllBindingFlags, loc);
783 /// This is a wrapper for MemberLookup that is not used to "probe", but
784 /// to find a final definition. If the final definition is not found, we
785 /// look for private members and display a useful debugging message if we
788 protected Expression MemberLookupFinal (ResolveContext ec, Type qualifier_type,
789 Type queried_type, string name,
790 MemberTypes mt, BindingFlags bf,
795 int errors = ec.Report.Errors;
796 e = MemberLookup (ec.Compiler, ec.CurrentType, qualifier_type, queried_type, name, mt, bf, loc);
798 if (e != null || errors != ec.Report.Errors)
801 // No errors were reported by MemberLookup, but there was an error.
802 return Error_MemberLookupFailed (ec, ec.CurrentType, qualifier_type, queried_type,
806 protected virtual Expression Error_MemberLookupFailed (ResolveContext ec, Type container_type, Type qualifier_type,
807 Type queried_type, string name, string class_name,
808 MemberTypes mt, BindingFlags bf)
810 MemberInfo[] lookup = null;
811 if (queried_type == null) {
812 class_name = "global::";
814 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
815 mt, (bf & ~BindingFlags.Public) | BindingFlags.NonPublic,
818 if (lookup != null) {
819 Expression e = Error_MemberLookupFailed (ec, queried_type, lookup);
822 // FIXME: This is still very wrong, it should be done inside
823 // OverloadResolve to do correct arguments matching.
824 // Requires MemberLookup accessiblity check removal
826 if (e == null || (mt & (MemberTypes.Method | MemberTypes.Constructor)) == 0) {
827 MemberInfo mi = lookup[0];
828 ec.Report.SymbolRelatedToPreviousError (mi);
829 if (qualifier_type != null && container_type != null && qualifier_type != container_type &&
830 TypeManager.IsNestedFamilyAccessible (container_type, mi.DeclaringType)) {
831 // Although a derived class can access protected members of
832 // its base class it cannot do so through an instance of the
833 // base class (CS1540). If the qualifier_type is a base of the
834 // ec.CurrentType and the lookup succeeds with the latter one,
835 // then we are in this situation.
836 Error_CannotAccessProtected (ec, loc, mi, qualifier_type, container_type);
838 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (mi), ec.Report);
845 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
846 AllMemberTypes, AllBindingFlags | BindingFlags.NonPublic,
850 if (lookup == null) {
851 if (class_name != null) {
852 ec.Report.Error (103, loc, "The name `{0}' does not exist in the current context",
855 Error_TypeDoesNotContainDefinition (ec, queried_type, name);
860 if (TypeManager.MemberLookup (queried_type, null, queried_type,
861 AllMemberTypes, AllBindingFlags |
862 BindingFlags.NonPublic, name, null) == null) {
863 if ((lookup.Length == 1) && (lookup [0] is Type)) {
864 Type t = (Type) lookup [0];
866 ec.Report.Error (305, loc,
867 "Using the generic type `{0}' " +
868 "requires {1} type arguments",
869 TypeManager.CSharpName (t),
870 TypeManager.GetNumberOfTypeArguments (t).ToString ());
875 return Error_MemberLookupFailed (ec, queried_type, lookup);
878 protected virtual Expression Error_MemberLookupFailed (ResolveContext ec, Type type, MemberInfo[] members)
880 List<MethodSpec> methods = new List<MethodSpec> ();
881 for (int i = 0; i < members.Length; ++i) {
882 if (!(members [i] is MethodBase))
885 methods.Add (Import.CreateMethod (members[i] as MethodBase));
888 // By default propagate the closest candidates upwards
889 return new MethodGroupExpr (methods.ToArray (), type, loc, true);
892 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
894 throw new NotImplementedException ();
897 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
899 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
903 /// Returns an expression that can be used to invoke operator true
904 /// on the expression if it exists.
906 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
908 return GetOperatorTrueOrFalse (ec, e, true, loc);
912 /// Returns an expression that can be used to invoke operator false
913 /// on the expression if it exists.
915 static public Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
917 return GetOperatorTrueOrFalse (ec, e, false, loc);
920 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
922 MethodGroupExpr operator_group;
923 string mname = Operator.GetMetadataName (is_true ? Operator.OpType.True : Operator.OpType.False);
924 operator_group = MethodLookup (ec.Compiler, ec.CurrentType, e.Type, mname, loc) as MethodGroupExpr;
925 if (operator_group == null)
928 Arguments arguments = new Arguments (1);
929 arguments.Add (new Argument (e));
930 operator_group = operator_group.OverloadResolve (
931 ec, ref arguments, false, loc);
933 if (operator_group == null)
936 return new UserOperatorCall (operator_group, arguments, null, loc);
939 public virtual string ExprClassName
943 case ExprClass.Unresolved:
945 case ExprClass.Value:
947 case ExprClass.Variable:
949 case ExprClass.Namespace:
953 case ExprClass.MethodGroup:
954 return "method group";
955 case ExprClass.PropertyAccess:
956 return "property access";
957 case ExprClass.EventAccess:
958 return "event access";
959 case ExprClass.IndexerAccess:
960 return "indexer access";
961 case ExprClass.Nothing:
963 case ExprClass.TypeParameter:
964 return "type parameter";
966 throw new Exception ("Should not happen");
971 /// Reports that we were expecting `expr' to be of class `expected'
973 public void Error_UnexpectedKind (Report r, MemberCore mc, string expected, Location loc)
975 Error_UnexpectedKind (r, mc, expected, ExprClassName, loc);
978 public void Error_UnexpectedKind (Report r, MemberCore mc, string expected, string was, Location loc)
982 name = mc.GetSignatureForError ();
984 name = GetSignatureForError ();
986 r.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
987 name, was, expected);
990 public void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
992 string [] valid = new string [4];
995 if ((flags & ResolveFlags.VariableOrValue) != 0) {
996 valid [count++] = "variable";
997 valid [count++] = "value";
1000 if ((flags & ResolveFlags.Type) != 0)
1001 valid [count++] = "type";
1003 if ((flags & ResolveFlags.MethodGroup) != 0)
1004 valid [count++] = "method group";
1007 valid [count++] = "unknown";
1009 StringBuilder sb = new StringBuilder (valid [0]);
1010 for (int i = 1; i < count - 1; i++) {
1012 sb.Append (valid [i]);
1015 sb.Append ("' or `");
1016 sb.Append (valid [count - 1]);
1019 ec.Report.Error (119, loc,
1020 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1023 public static void UnsafeError (ResolveContext ec, Location loc)
1025 UnsafeError (ec.Report, loc);
1028 public static void UnsafeError (Report Report, Location loc)
1030 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1034 // Load the object from the pointer.
1036 public static void LoadFromPtr (ILGenerator ig, Type t)
1038 if (t == TypeManager.int32_type)
1039 ig.Emit (OpCodes.Ldind_I4);
1040 else if (t == TypeManager.uint32_type)
1041 ig.Emit (OpCodes.Ldind_U4);
1042 else if (t == TypeManager.short_type)
1043 ig.Emit (OpCodes.Ldind_I2);
1044 else if (t == TypeManager.ushort_type)
1045 ig.Emit (OpCodes.Ldind_U2);
1046 else if (t == TypeManager.char_type)
1047 ig.Emit (OpCodes.Ldind_U2);
1048 else if (t == TypeManager.byte_type)
1049 ig.Emit (OpCodes.Ldind_U1);
1050 else if (t == TypeManager.sbyte_type)
1051 ig.Emit (OpCodes.Ldind_I1);
1052 else if (t == TypeManager.uint64_type)
1053 ig.Emit (OpCodes.Ldind_I8);
1054 else if (t == TypeManager.int64_type)
1055 ig.Emit (OpCodes.Ldind_I8);
1056 else if (t == TypeManager.float_type)
1057 ig.Emit (OpCodes.Ldind_R4);
1058 else if (t == TypeManager.double_type)
1059 ig.Emit (OpCodes.Ldind_R8);
1060 else if (t == TypeManager.bool_type)
1061 ig.Emit (OpCodes.Ldind_I1);
1062 else if (t == TypeManager.intptr_type)
1063 ig.Emit (OpCodes.Ldind_I);
1064 else if (TypeManager.IsEnumType (t)) {
1065 if (t == TypeManager.enum_type)
1066 ig.Emit (OpCodes.Ldind_Ref);
1068 LoadFromPtr (ig, TypeManager.GetEnumUnderlyingType (t));
1069 } else if (TypeManager.IsStruct (t) || TypeManager.IsGenericParameter (t))
1070 ig.Emit (OpCodes.Ldobj, t);
1071 else if (t.IsPointer)
1072 ig.Emit (OpCodes.Ldind_I);
1074 ig.Emit (OpCodes.Ldind_Ref);
1078 // The stack contains the pointer and the value of type `type'
1080 public static void StoreFromPtr (ILGenerator ig, Type type)
1082 if (TypeManager.IsEnumType (type))
1083 type = TypeManager.GetEnumUnderlyingType (type);
1084 if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
1085 ig.Emit (OpCodes.Stind_I4);
1086 else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
1087 ig.Emit (OpCodes.Stind_I8);
1088 else if (type == TypeManager.char_type || type == TypeManager.short_type ||
1089 type == TypeManager.ushort_type)
1090 ig.Emit (OpCodes.Stind_I2);
1091 else if (type == TypeManager.float_type)
1092 ig.Emit (OpCodes.Stind_R4);
1093 else if (type == TypeManager.double_type)
1094 ig.Emit (OpCodes.Stind_R8);
1095 else if (type == TypeManager.byte_type || type == TypeManager.sbyte_type ||
1096 type == TypeManager.bool_type)
1097 ig.Emit (OpCodes.Stind_I1);
1098 else if (type == TypeManager.intptr_type)
1099 ig.Emit (OpCodes.Stind_I);
1100 else if (TypeManager.IsStruct (type) || TypeManager.IsGenericParameter (type))
1101 ig.Emit (OpCodes.Stobj, type);
1103 ig.Emit (OpCodes.Stind_Ref);
1107 // Returns the size of type `t' if known, otherwise, 0
1109 public static int GetTypeSize (Type t)
1111 t = TypeManager.TypeToCoreType (t);
1112 if (t == TypeManager.int32_type ||
1113 t == TypeManager.uint32_type ||
1114 t == TypeManager.float_type)
1116 else if (t == TypeManager.int64_type ||
1117 t == TypeManager.uint64_type ||
1118 t == TypeManager.double_type)
1120 else if (t == TypeManager.byte_type ||
1121 t == TypeManager.sbyte_type ||
1122 t == TypeManager.bool_type)
1124 else if (t == TypeManager.short_type ||
1125 t == TypeManager.char_type ||
1126 t == TypeManager.ushort_type)
1128 else if (t == TypeManager.decimal_type)
1134 protected void Error_CannotCallAbstractBase (ResolveContext ec, string name)
1136 ec.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
1139 protected void Error_CannotModifyIntermediateExpressionValue (ResolveContext ec)
1141 ec.Report.SymbolRelatedToPreviousError (type);
1142 if (ec.CurrentInitializerVariable != null) {
1143 ec.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
1144 TypeManager.CSharpName (type), GetSignatureForError ());
1146 ec.Report.Error (1612, loc, "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
1147 GetSignatureForError ());
1152 // Converts `source' to an int, uint, long or ulong.
1154 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source)
1156 if (TypeManager.IsDynamicType (source.type)) {
1157 Arguments args = new Arguments (1);
1158 args.Add (new Argument (source));
1159 return new DynamicConversion (TypeManager.int32_type, CSharpBinderFlags.ConvertArrayIndex, args, loc).Resolve (ec);
1162 Expression converted;
1164 using (ec.Set (ResolveContext.Options.CheckedScope)) {
1165 converted = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, source.loc);
1166 if (converted == null)
1167 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, source.loc);
1168 if (converted == null)
1169 converted = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, source.loc);
1170 if (converted == null)
1171 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, source.loc);
1173 if (converted == null) {
1174 source.Error_ValueCannotBeConverted (ec, source.loc, TypeManager.int32_type, false);
1180 // Only positive constants are allowed at compile time
1182 Constant c = converted as Constant;
1183 if (c != null && c.IsNegative)
1184 Error_NegativeArrayIndex (ec, source.loc);
1186 // No conversion needed to array index
1187 if (converted.Type == TypeManager.int32_type)
1190 return new ArrayIndexCast (converted).Resolve (ec);
1194 // Derived classes implement this method by cloning the fields that
1195 // could become altered during the Resolve stage
1197 // Only expressions that are created for the parser need to implement
1200 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1202 throw new NotImplementedException (
1204 "CloneTo not implemented for expression {0}", this.GetType ()));
1208 // Clones an expression created by the parser.
1210 // We only support expressions created by the parser so far, not
1211 // expressions that have been resolved (many more classes would need
1212 // to implement CloneTo).
1214 // This infrastructure is here merely for Lambda expressions which
1215 // compile the same code using different type values for the same
1216 // arguments to find the correct overload
1218 public Expression Clone (CloneContext clonectx)
1220 Expression cloned = (Expression) MemberwiseClone ();
1221 CloneTo (clonectx, cloned);
1227 // Implementation of expression to expression tree conversion
1229 public abstract Expression CreateExpressionTree (ResolveContext ec);
1231 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
1233 return CreateExpressionFactoryCall (ec, name, null, args, loc);
1236 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
1238 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
1241 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
1243 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
1246 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
1248 TypeExpr texpr = TypeManager.expression_type_expr;
1249 if (texpr == null) {
1250 Type t = TypeManager.CoreLookupType (ec.Compiler, "System.Linq.Expressions", "Expression", MemberKind.Class, true);
1254 TypeManager.expression_type_expr = texpr = new TypeExpression (t, Location.Null);
1261 // Implemented by all expressions which support conversion from
1262 // compiler expression to invokable runtime expression. Used by
1263 // dynamic C# binder.
1265 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
1267 throw new NotImplementedException ("MakeExpression for " + GetType ());
1270 public virtual void MutateHoistedGenericType (AnonymousMethodStorey storey)
1272 // TODO: It should probably be type = storey.MutateType (type);
1277 /// This is just a base class for expressions that can
1278 /// appear on statements (invocations, object creation,
1279 /// assignments, post/pre increment and decrement). The idea
1280 /// being that they would support an extra Emition interface that
1281 /// does not leave a result on the stack.
1283 public abstract class ExpressionStatement : Expression {
1285 public virtual ExpressionStatement ResolveStatement (BlockContext ec)
1287 Expression e = Resolve (ec);
1291 ExpressionStatement es = e as ExpressionStatement;
1293 Error_InvalidExpressionStatement (ec);
1299 /// Requests the expression to be emitted in a `statement'
1300 /// context. This means that no new value is left on the
1301 /// stack after invoking this method (constrasted with
1302 /// Emit that will always leave a value on the stack).
1304 public abstract void EmitStatement (EmitContext ec);
1306 public override void EmitSideEffect (EmitContext ec)
1313 /// This kind of cast is used to encapsulate the child
1314 /// whose type is child.Type into an expression that is
1315 /// reported to return "return_type". This is used to encapsulate
1316 /// expressions which have compatible types, but need to be dealt
1317 /// at higher levels with.
1319 /// For example, a "byte" expression could be encapsulated in one
1320 /// of these as an "unsigned int". The type for the expression
1321 /// would be "unsigned int".
1324 public abstract class TypeCast : Expression
1326 protected readonly Expression child;
1328 protected TypeCast (Expression child, Type return_type)
1330 eclass = child.eclass;
1331 loc = child.Location;
1336 public override Expression CreateExpressionTree (ResolveContext ec)
1338 Arguments args = new Arguments (2);
1339 args.Add (new Argument (child.CreateExpressionTree (ec)));
1340 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1342 if (type.IsPointer || child.Type.IsPointer)
1343 Error_PointerInsideExpressionTree (ec);
1345 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1348 protected override Expression DoResolve (ResolveContext ec)
1350 // This should never be invoked, we are born in fully
1351 // initialized state.
1356 public override void Emit (EmitContext ec)
1361 public override bool GetAttributableValue (ResolveContext ec, Type value_type, out object value)
1363 return child.GetAttributableValue (ec, value_type, out value);
1366 public override SLE.Expression MakeExpression (BuilderContext ctx)
1368 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1369 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type) :
1370 SLE.Expression.Convert (child.MakeExpression (ctx), type);
1373 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1375 type = storey.MutateType (type);
1376 child.MutateHoistedGenericType (storey);
1379 protected override void CloneTo (CloneContext clonectx, Expression t)
1384 public override bool IsNull {
1385 get { return child.IsNull; }
1389 public class EmptyCast : TypeCast {
1390 EmptyCast (Expression child, Type target_type)
1391 : base (child, target_type)
1395 public static Expression Create (Expression child, Type type)
1397 Constant c = child as Constant;
1399 return new EmptyConstantCast (c, type);
1401 EmptyCast e = child as EmptyCast;
1403 return new EmptyCast (e.child, type);
1405 return new EmptyCast (child, type);
1408 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1410 child.EmitBranchable (ec, label, on_true);
1413 public override void EmitSideEffect (EmitContext ec)
1415 child.EmitSideEffect (ec);
1420 // Used for predefined class library user casts (no obsolete check, etc.)
1422 public class OperatorCast : TypeCast {
1423 MethodInfo conversion_operator;
1425 public OperatorCast (Expression child, Type target_type)
1426 : this (child, target_type, false)
1430 public OperatorCast (Expression child, Type target_type, bool find_explicit)
1431 : base (child, target_type)
1433 conversion_operator = GetConversionOperator (find_explicit);
1434 if (conversion_operator == null)
1435 throw new InternalErrorException ("Outer conversion routine is out of sync");
1438 // Returns the implicit operator that converts from
1439 // 'child.Type' to our target type (type)
1440 MethodInfo GetConversionOperator (bool find_explicit)
1442 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1446 mi = TypeManager.MemberLookup (child.Type, child.Type, child.Type, MemberTypes.Method,
1447 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1450 mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1451 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1454 foreach (MethodInfo oper in mi) {
1455 AParametersCollection pd = TypeManager.GetParameterData (oper);
1457 if (pd.Types [0] == child.Type && TypeManager.TypeToCoreType (oper.ReturnType) == type)
1464 public override void Emit (EmitContext ec)
1467 ec.ig.Emit (OpCodes.Call, conversion_operator);
1472 /// This is a numeric cast to a Decimal
1474 public class CastToDecimal : OperatorCast {
1475 public CastToDecimal (Expression child)
1476 : this (child, false)
1480 public CastToDecimal (Expression child, bool find_explicit)
1481 : base (child, TypeManager.decimal_type, find_explicit)
1487 /// This is an explicit numeric cast from a Decimal
1489 public class CastFromDecimal : TypeCast
1491 static Dictionary<Type, MethodInfo> operators;
1493 public CastFromDecimal (Expression child, Type return_type)
1494 : base (child, return_type)
1496 if (child.Type != TypeManager.decimal_type)
1497 throw new InternalErrorException (
1498 "The expected type is Decimal, instead it is " + child.Type.FullName);
1501 // Returns the explicit operator that converts from an
1502 // express of type System.Decimal to 'type'.
1503 public Expression Resolve ()
1505 if (operators == null) {
1506 MemberInfo[] all_oper = TypeManager.MemberLookup (TypeManager.decimal_type,
1507 TypeManager.decimal_type, TypeManager.decimal_type, MemberTypes.Method,
1508 BindingFlags.Static | BindingFlags.Public, "op_Explicit", null);
1510 operators = new Dictionary<Type, MethodInfo> (ReferenceEquality<Type>.Default);
1511 foreach (MethodInfo oper in all_oper) {
1512 AParametersCollection pd = TypeManager.GetParameterData (oper);
1513 if (pd.Types [0] == TypeManager.decimal_type)
1514 operators.Add (TypeManager.TypeToCoreType (oper.ReturnType), oper);
1518 return operators.ContainsKey (type) ? this : null;
1521 public override void Emit (EmitContext ec)
1523 ILGenerator ig = ec.ig;
1526 ig.Emit (OpCodes.Call, operators [type]);
1532 // Constant specialization of EmptyCast.
1533 // We need to special case this since an empty cast of
1534 // a constant is still a constant.
1536 public class EmptyConstantCast : Constant
1538 public Constant child;
1540 public EmptyConstantCast (Constant child, Type type)
1541 : base (child.Location)
1544 throw new ArgumentNullException ("child");
1547 this.eclass = child.eclass;
1551 public override string AsString ()
1553 return child.AsString ();
1556 public override object GetValue ()
1558 return child.GetValue ();
1561 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
1563 if (child.Type == target_type)
1566 // FIXME: check that 'type' can be converted to 'target_type' first
1567 return child.ConvertExplicitly (in_checked_context, target_type);
1570 public override Expression CreateExpressionTree (ResolveContext ec)
1572 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1573 child.CreateExpressionTree (ec),
1574 new TypeOf (new TypeExpression (type, loc), loc));
1577 Error_PointerInsideExpressionTree (ec);
1579 return CreateExpressionFactoryCall (ec, "Convert", args);
1582 public override bool IsDefaultValue {
1583 get { return child.IsDefaultValue; }
1586 public override bool IsNegative {
1587 get { return child.IsNegative; }
1590 public override bool IsNull {
1591 get { return child.IsNull; }
1594 public override bool IsOneInteger {
1595 get { return child.IsOneInteger; }
1598 public override bool IsZeroInteger {
1599 get { return child.IsZeroInteger; }
1602 protected override Expression DoResolve (ResolveContext rc)
1607 public override void Emit (EmitContext ec)
1612 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1614 child.EmitBranchable (ec, label, on_true);
1616 // Only to make verifier happy
1617 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1618 ec.ig.Emit (OpCodes.Unbox_Any, type);
1621 public override void EmitSideEffect (EmitContext ec)
1623 child.EmitSideEffect (ec);
1626 public override Constant ConvertImplicitly (ResolveContext rc, Type target_type)
1628 // FIXME: Do we need to check user conversions?
1629 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1631 return child.ConvertImplicitly (rc, target_type);
1634 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1636 child.MutateHoistedGenericType (storey);
1641 /// This class is used to wrap literals which belong inside Enums
1643 public class EnumConstant : Constant
1645 public Constant Child;
1647 public EnumConstant (Constant child, Type enum_type)
1648 : base (child.Location)
1651 this.type = enum_type;
1654 protected EnumConstant (Location loc)
1659 protected override Expression DoResolve (ResolveContext rc)
1661 Child = Child.Resolve (rc);
1662 this.eclass = ExprClass.Value;
1666 public override void Emit (EmitContext ec)
1671 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1673 Child.EmitBranchable (ec, label, on_true);
1676 public override void EmitSideEffect (EmitContext ec)
1678 Child.EmitSideEffect (ec);
1681 public override bool GetAttributableValue (ResolveContext ec, Type value_type, out object value)
1683 value = GetTypedValue ();
1687 public override string GetSignatureForError()
1689 return TypeManager.CSharpName (Type);
1692 public override object GetValue ()
1694 return Child.GetValue ();
1697 public override object GetTypedValue ()
1699 // FIXME: runtime is not ready to work with just emited enums
1700 if (!RootContext.StdLib) {
1701 return Child.GetValue ();
1705 // Small workaround for big problem
1706 // System.Enum.ToObject cannot be called on dynamic types
1707 // EnumBuilder has to be used, but we cannot use EnumBuilder
1708 // because it does not properly support generics
1710 // This works only sometimes
1712 if (TypeManager.IsBeingCompiled (type))
1713 return Child.GetValue ();
1716 return System.Enum.ToObject (type, Child.GetValue ());
1719 public override string AsString ()
1721 return Child.AsString ();
1724 public EnumConstant Increment()
1726 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1729 public override bool IsDefaultValue {
1731 return Child.IsDefaultValue;
1735 public override bool IsZeroInteger {
1736 get { return Child.IsZeroInteger; }
1739 public override bool IsNegative {
1741 return Child.IsNegative;
1745 public override Constant ConvertExplicitly(bool in_checked_context, Type target_type)
1747 if (Child.Type == target_type)
1750 return Child.ConvertExplicitly (in_checked_context, target_type);
1753 public override Constant ConvertImplicitly (ResolveContext rc, Type type)
1755 Type this_type = TypeManager.DropGenericTypeArguments (Type);
1756 type = TypeManager.DropGenericTypeArguments (type);
1758 if (this_type == type) {
1759 // This is workaround of mono bug. It can be removed when the latest corlib spreads enough
1760 if (TypeManager.IsEnumType (type.UnderlyingSystemType))
1763 Type child_type = TypeManager.DropGenericTypeArguments (Child.Type);
1764 if (type.UnderlyingSystemType != child_type)
1765 Child = Child.ConvertImplicitly (rc, type.UnderlyingSystemType);
1769 if (!Convert.ImplicitStandardConversionExists (this, type)){
1773 return Child.ConvertImplicitly (rc, type);
1778 /// This kind of cast is used to encapsulate Value Types in objects.
1780 /// The effect of it is to box the value type emitted by the previous
1783 public class BoxedCast : TypeCast {
1785 public BoxedCast (Expression expr, Type target_type)
1786 : base (expr, target_type)
1788 eclass = ExprClass.Value;
1791 protected override Expression DoResolve (ResolveContext ec)
1793 // This should never be invoked, we are born in fully
1794 // initialized state.
1799 public override void Emit (EmitContext ec)
1803 ec.ig.Emit (OpCodes.Box, child.Type);
1806 public override void EmitSideEffect (EmitContext ec)
1808 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1809 // so, we need to emit the box+pop instructions in most cases
1810 if (TypeManager.IsStruct (child.Type) &&
1811 (type == TypeManager.object_type || type == TypeManager.value_type))
1812 child.EmitSideEffect (ec);
1814 base.EmitSideEffect (ec);
1818 public class UnboxCast : TypeCast {
1819 public UnboxCast (Expression expr, Type return_type)
1820 : base (expr, return_type)
1824 protected override Expression DoResolve (ResolveContext ec)
1826 // This should never be invoked, we are born in fully
1827 // initialized state.
1832 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
1834 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
1835 ec.Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
1836 return base.DoResolveLValue (ec, right_side);
1839 public override void Emit (EmitContext ec)
1843 ILGenerator ig = ec.ig;
1844 ig.Emit (OpCodes.Unbox_Any, type);
1847 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1849 type = storey.MutateType (type);
1850 base.MutateHoistedGenericType (storey);
1855 /// This is used to perform explicit numeric conversions.
1857 /// Explicit numeric conversions might trigger exceptions in a checked
1858 /// context, so they should generate the conv.ovf opcodes instead of
1861 public class ConvCast : TypeCast {
1862 public enum Mode : byte {
1863 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1865 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1866 U2_I1, U2_U1, U2_I2, U2_CH,
1867 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1868 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1869 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1870 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1871 CH_I1, CH_U1, CH_I2,
1872 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1873 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1879 public ConvCast (Expression child, Type return_type, Mode m)
1880 : base (child, return_type)
1885 protected override Expression DoResolve (ResolveContext ec)
1887 // This should never be invoked, we are born in fully
1888 // initialized state.
1893 public override string ToString ()
1895 return String.Format ("ConvCast ({0}, {1})", mode, child);
1898 public override void Emit (EmitContext ec)
1900 ILGenerator ig = ec.ig;
1904 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1906 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1907 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1908 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1909 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1910 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1912 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1913 case Mode.U1_CH: /* nothing */ break;
1915 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1916 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1917 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1918 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1919 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1920 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1922 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1923 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1924 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1925 case Mode.U2_CH: /* nothing */ break;
1927 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1928 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1929 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1930 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1931 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1932 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1933 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1935 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1936 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1937 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1938 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1939 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1940 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1942 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1943 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1944 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1945 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1946 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1947 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1948 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1949 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1950 case Mode.I8_I: ig.Emit (OpCodes.Conv_Ovf_U); break;
1952 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1953 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1954 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1955 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1956 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1957 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1958 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1959 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1960 case Mode.U8_I: ig.Emit (OpCodes.Conv_Ovf_U_Un); break;
1962 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1963 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1964 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1966 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1967 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1968 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1969 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1970 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1971 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1972 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1973 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1974 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1976 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1977 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1978 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1979 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1980 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1981 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1982 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1983 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1984 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1985 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1987 case Mode.I_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1991 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
1992 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
1993 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
1994 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
1995 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
1997 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
1998 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
2000 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
2001 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
2002 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
2003 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
2004 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
2005 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
2007 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
2008 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
2009 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
2010 case Mode.U2_CH: /* nothing */ break;
2012 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
2013 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
2014 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
2015 case Mode.I4_U4: /* nothing */ break;
2016 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
2017 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
2018 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
2020 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
2021 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
2022 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
2023 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
2024 case Mode.U4_I4: /* nothing */ break;
2025 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
2027 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
2028 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
2029 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
2030 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
2031 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
2032 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
2033 case Mode.I8_U8: /* nothing */ break;
2034 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
2035 case Mode.I8_I: ig.Emit (OpCodes.Conv_U); break;
2037 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
2038 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
2039 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
2040 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
2041 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
2042 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
2043 case Mode.U8_I8: /* nothing */ break;
2044 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
2045 case Mode.U8_I: ig.Emit (OpCodes.Conv_U); break;
2047 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
2048 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
2049 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
2051 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
2052 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
2053 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
2054 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
2055 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
2056 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
2057 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
2058 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
2059 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
2061 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
2062 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
2063 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
2064 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
2065 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
2066 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
2067 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
2068 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
2069 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
2070 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
2072 case Mode.I_I8: ig.Emit (OpCodes.Conv_U8); break;
2078 public class OpcodeCast : TypeCast {
2081 public OpcodeCast (Expression child, Type return_type, OpCode op)
2082 : base (child, return_type)
2087 protected override Expression DoResolve (ResolveContext ec)
2089 // This should never be invoked, we are born in fully
2090 // initialized state.
2095 public override void Emit (EmitContext ec)
2101 public Type UnderlyingType {
2102 get { return child.Type; }
2107 /// This kind of cast is used to encapsulate a child and cast it
2108 /// to the class requested
2110 public sealed class ClassCast : TypeCast {
2111 readonly bool forced;
2113 public ClassCast (Expression child, Type return_type)
2114 : base (child, return_type)
2118 public ClassCast (Expression child, Type return_type, bool forced)
2119 : base (child, return_type)
2121 this.forced = forced;
2124 public override void Emit (EmitContext ec)
2128 bool gen = TypeManager.IsGenericParameter (child.Type);
2130 ec.ig.Emit (OpCodes.Box, child.Type);
2132 if (type.IsGenericParameter) {
2133 ec.ig.Emit (OpCodes.Unbox_Any, type);
2140 ec.ig.Emit (OpCodes.Castclass, type);
2145 // Created during resolving pahse when an expression is wrapped or constantified
2146 // and original expression can be used later (e.g. for expression trees)
2148 public class ReducedExpression : Expression
2150 sealed class ReducedConstantExpression : EmptyConstantCast
2152 readonly Expression orig_expr;
2154 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2155 : base (expr, expr.Type)
2157 this.orig_expr = orig_expr;
2160 public override Constant ConvertImplicitly (ResolveContext rc, Type target_type)
2162 Constant c = base.ConvertImplicitly (rc, target_type);
2164 c = new ReducedConstantExpression (c, orig_expr);
2169 public override Expression CreateExpressionTree (ResolveContext ec)
2171 return orig_expr.CreateExpressionTree (ec);
2174 public override bool GetAttributableValue (ResolveContext ec, Type value_type, out object value)
2177 // Even if resolved result is a constant original expression was not
2178 // and attribute accepts constants only
2180 Attribute.Error_AttributeArgumentNotValid (ec, orig_expr.Location);
2185 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
2187 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
2189 c = new ReducedConstantExpression (c, orig_expr);
2194 sealed class ReducedExpressionStatement : ExpressionStatement
2196 readonly Expression orig_expr;
2197 readonly ExpressionStatement stm;
2199 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
2201 this.orig_expr = orig;
2203 this.loc = orig.Location;
2206 public override Expression CreateExpressionTree (ResolveContext ec)
2208 return orig_expr.CreateExpressionTree (ec);
2211 protected override Expression DoResolve (ResolveContext ec)
2213 eclass = stm.eclass;
2218 public override void Emit (EmitContext ec)
2223 public override void EmitStatement (EmitContext ec)
2225 stm.EmitStatement (ec);
2228 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2230 stm.MutateHoistedGenericType (storey);
2234 readonly Expression expr, orig_expr;
2236 private ReducedExpression (Expression expr, Expression orig_expr)
2239 this.eclass = expr.eclass;
2240 this.type = expr.Type;
2241 this.orig_expr = orig_expr;
2242 this.loc = orig_expr.Location;
2246 // Creates fully resolved expression switcher
2248 public static Constant Create (Constant expr, Expression original_expr)
2250 if (expr.eclass == ExprClass.Unresolved)
2251 throw new ArgumentException ("Unresolved expression");
2253 return new ReducedConstantExpression (expr, original_expr);
2256 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
2258 return new ReducedExpressionStatement (s, orig);
2262 // Creates unresolved reduce expression. The original expression has to be
2265 public static Expression Create (Expression expr, Expression original_expr)
2267 Constant c = expr as Constant;
2269 return Create (c, original_expr);
2271 ExpressionStatement s = expr as ExpressionStatement;
2273 return Create (s, original_expr);
2275 if (expr.eclass == ExprClass.Unresolved)
2276 throw new ArgumentException ("Unresolved expression");
2278 return new ReducedExpression (expr, original_expr);
2281 public override Expression CreateExpressionTree (ResolveContext ec)
2283 return orig_expr.CreateExpressionTree (ec);
2286 protected override Expression DoResolve (ResolveContext ec)
2291 public override void Emit (EmitContext ec)
2296 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2298 expr.EmitBranchable (ec, target, on_true);
2301 public override SLE.Expression MakeExpression (BuilderContext ctx)
2303 return orig_expr.MakeExpression (ctx);
2306 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2308 expr.MutateHoistedGenericType (storey);
2313 // Standard composite pattern
2315 public abstract class CompositeExpression : Expression
2319 protected CompositeExpression (Expression expr)
2322 this.loc = expr.Location;
2325 public override Expression CreateExpressionTree (ResolveContext ec)
2327 return expr.CreateExpressionTree (ec);
2330 public Expression Child {
2331 get { return expr; }
2334 protected override Expression DoResolve (ResolveContext ec)
2336 expr = expr.Resolve (ec);
2339 eclass = expr.eclass;
2345 public override void Emit (EmitContext ec)
2350 public override bool IsNull {
2351 get { return expr.IsNull; }
2356 // Base of expressions used only to narrow resolve flow
2358 public abstract class ShimExpression : Expression
2360 protected Expression expr;
2362 protected ShimExpression (Expression expr)
2367 protected override void CloneTo (CloneContext clonectx, Expression t)
2372 ShimExpression target = (ShimExpression) t;
2373 target.expr = expr.Clone (clonectx);
2376 public override Expression CreateExpressionTree (ResolveContext ec)
2378 throw new NotSupportedException ("ET");
2381 public override void Emit (EmitContext ec)
2383 throw new InternalErrorException ("Missing Resolve call");
2386 public Expression Expr {
2387 get { return expr; }
2390 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2392 throw new InternalErrorException ("Missing Resolve call");
2397 // Unresolved type name expressions
2399 public abstract class ATypeNameExpression : FullNamedExpression
2402 protected TypeArguments targs;
2404 protected ATypeNameExpression (string name, Location l)
2410 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2417 public bool HasTypeArguments {
2419 return targs != null;
2423 public override bool Equals (object obj)
2425 ATypeNameExpression atne = obj as ATypeNameExpression;
2426 return atne != null && atne.Name == Name &&
2427 (targs == null || targs.Equals (atne.targs));
2430 public override int GetHashCode ()
2432 return Name.GetHashCode ();
2435 public override string GetSignatureForError ()
2437 if (targs != null) {
2438 return TypeManager.RemoveGenericArity (Name) + "<" +
2439 targs.GetSignatureForError () + ">";
2445 public string Name {
2454 public TypeArguments TypeArguments {
2462 /// SimpleName expressions are formed of a single word and only happen at the beginning
2463 /// of a dotted-name.
2465 public class SimpleName : ATypeNameExpression
2467 public SimpleName (string name, Location l)
2472 public SimpleName (string name, TypeArguments args, Location l)
2473 : base (name, args, l)
2477 public SimpleName (string name, TypeParameter[] type_params, Location l)
2480 targs = new TypeArguments ();
2481 foreach (TypeParameter type_param in type_params)
2482 targs.Add (new TypeParameterExpr (type_param, l));
2485 public static string RemoveGenericArity (string name)
2488 StringBuilder sb = null;
2490 int pos = name.IndexOf ('`', start);
2495 sb.Append (name.Substring (start));
2500 sb = new StringBuilder ();
2501 sb.Append (name.Substring (start, pos-start));
2504 while ((pos < name.Length) && Char.IsNumber (name [pos]))
2508 } while (start < name.Length);
2510 return sb.ToString ();
2513 public SimpleName GetMethodGroup ()
2515 return new SimpleName (RemoveGenericArity (Name), targs, loc);
2518 public static void Error_ObjectRefRequired (ResolveContext ec, Location l, string name)
2520 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope))
2521 ec.Report.Error (236, l,
2522 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2525 ec.Report.Error (120, l,
2526 "An object reference is required to access non-static member `{0}'",
2530 public bool IdenticalNameAndTypeName (IMemberContext mc, Expression resolved_to, Location loc)
2532 return resolved_to != null && resolved_to.Type != null &&
2533 resolved_to.Type.Name == Name &&
2534 (mc.LookupNamespaceOrType (Name, loc, /* ignore_cs0104 = */ true) != null);
2537 protected override Expression DoResolve (ResolveContext ec)
2539 return SimpleNameResolve (ec, null, false);
2542 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2544 return SimpleNameResolve (ec, right_side, false);
2547 public Expression DoResolve (ResolveContext ec, bool intermediate)
2549 return SimpleNameResolve (ec, null, intermediate);
2552 static bool IsNestedChild (Type t, Type parent)
2554 while (parent != null) {
2555 if (TypeManager.IsNestedChildOf (t, TypeManager.DropGenericTypeArguments (parent)))
2558 parent = parent.BaseType;
2564 FullNamedExpression ResolveNested (Type t)
2566 if (!TypeManager.IsGenericTypeDefinition (t) && !TypeManager.IsGenericType (t))
2570 while (ds != null && !IsNestedChild (t, ds))
2571 ds = ds.DeclaringType;
2576 Type[] gen_params = TypeManager.GetTypeArguments (t);
2578 int arg_count = targs != null ? targs.Count : 0;
2580 for (; (ds != null) && TypeManager.IsGenericType (ds); ds = ds.DeclaringType) {
2581 Type[] gargs = TypeManager.GetTypeArguments (ds);
2582 if (arg_count + gargs.Length == gen_params.Length) {
2583 TypeArguments new_args = new TypeArguments ();
2584 foreach (Type param in gargs)
2585 new_args.Add (new TypeExpression (param, loc));
2588 new_args.Add (targs);
2590 return new GenericTypeExpr (t, new_args, loc);
2597 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2599 int errors = ec.Compiler.Report.Errors;
2600 FullNamedExpression fne = ec.LookupNamespaceOrType (Name, loc, /*ignore_cs0104=*/ false);
2603 if (fne.Type == null)
2606 FullNamedExpression nested = ResolveNested (fne.Type);
2608 return nested.ResolveAsTypeStep (ec, false);
2610 if (targs != null) {
2611 if (TypeManager.IsGenericType (fne.Type)) {
2612 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2613 return ct.ResolveAsTypeStep (ec, false);
2616 fne.Error_TypeArgumentsCannotBeUsed (ec.Compiler.Report, loc);
2622 if (!HasTypeArguments && Name == "dynamic" &&
2623 RootContext.Version > LanguageVersion.V_3 &&
2624 RootContext.MetadataCompatibilityVersion > MetadataVersion.v2) {
2626 if (!PredefinedAttributes.Get.Dynamic.IsDefined) {
2627 ec.Compiler.Report.Error (1980, Location,
2628 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2629 PredefinedAttributes.Get.Dynamic.GetSignatureForError ());
2632 return new DynamicTypeExpr (loc);
2635 if (silent || errors != ec.Compiler.Report.Errors)
2638 Error_TypeOrNamespaceNotFound (ec);
2642 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ec)
2644 if (ec.CurrentType != null) {
2645 if (ec.CurrentTypeDefinition != null) {
2646 MemberCore mc = ec.CurrentTypeDefinition.GetDefinition (Name);
2648 Error_UnexpectedKind (ec.Compiler.Report, mc, "type", GetMemberType (mc), loc);
2653 string ns = ec.CurrentType.Namespace;
2654 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2655 foreach (Assembly a in GlobalRootNamespace.Instance.Assemblies) {
2656 Type type = a.GetType (fullname);
2658 ec.Compiler.Report.SymbolRelatedToPreviousError (type);
2659 Expression.ErrorIsInaccesible (loc, TypeManager.CSharpName (type), ec.Compiler.Report);
2664 if (ec.CurrentTypeDefinition != null) {
2665 Type t = ec.CurrentTypeDefinition.LookupAnyGeneric (Name);
2667 Namespace.Error_InvalidNumberOfTypeArguments (ec.Compiler.Report, t, loc);
2673 if (targs != null) {
2674 FullNamedExpression retval = ec.LookupNamespaceOrType (SimpleName.RemoveGenericArity (Name), loc, true);
2675 if (retval != null) {
2676 retval.Error_TypeArgumentsCannotBeUsed (ec.Compiler.Report, loc);
2681 NamespaceEntry.Error_NamespaceNotFound (loc, Name, ec.Compiler.Report);
2684 // TODO: I am still not convinced about this. If someone else will need it
2685 // implement this as virtual property in MemberCore hierarchy
2686 public static string GetMemberType (MemberCore mc)
2692 if (mc is FieldBase)
2694 if (mc is MethodCore)
2696 if (mc is EnumMember)
2704 Expression SimpleNameResolve (ResolveContext ec, Expression right_side, bool intermediate)
2706 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2711 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2718 /// 7.5.2: Simple Names.
2720 /// Local Variables and Parameters are handled at
2721 /// parse time, so they never occur as SimpleNames.
2723 /// The `intermediate' flag is used by MemberAccess only
2724 /// and it is used to inform us that it is ok for us to
2725 /// avoid the static check, because MemberAccess might end
2726 /// up resolving the Name as a Type name and the access as
2727 /// a static type access.
2729 /// ie: Type Type; .... { Type.GetType (""); }
2731 /// Type is both an instance variable and a Type; Type.GetType
2732 /// is the static method not an instance method of type.
2734 Expression DoSimpleNameResolve (ResolveContext ec, Expression right_side, bool intermediate)
2736 Expression e = null;
2739 // Stage 1: Performed by the parser (binding to locals or parameters).
2741 Block current_block = ec.CurrentBlock;
2742 if (current_block != null){
2743 LocalInfo vi = current_block.GetLocalInfo (Name);
2745 e = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2747 if (right_side != null) {
2748 e = e.ResolveLValue (ec, right_side);
2751 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
2752 e = e.Resolve (ec, ResolveFlags.VariableOrValue);
2755 e = e.Resolve (ec, ResolveFlags.VariableOrValue);
2759 if (targs != null && e != null)
2760 e.Error_TypeArgumentsCannotBeUsed (ec.Report, loc);
2765 e = current_block.Toplevel.GetParameterReference (Name, loc);
2767 if (right_side != null)
2768 e = e.ResolveLValue (ec, right_side);
2772 if (targs != null && e != null)
2773 e.Error_TypeArgumentsCannotBeUsed (ec.Report, loc);
2780 // Stage 2: Lookup members
2783 Type almost_matched_type = null;
2784 IList<MemberInfo> almost_matched = null;
2785 for (Type lookup_ds = ec.CurrentType; lookup_ds != null; lookup_ds = lookup_ds.DeclaringType) {
2786 e = MemberLookup (ec.Compiler, ec.CurrentType, lookup_ds, Name, loc);
2788 PropertyExpr pe = e as PropertyExpr;
2790 AParametersCollection param = TypeManager.GetParameterData (pe.PropertyInfo);
2792 // since TypeManager.MemberLookup doesn't know if we're doing a lvalue access or not,
2793 // it doesn't know which accessor to check permissions against
2794 if (param.IsEmpty && pe.IsAccessibleFrom (ec.CurrentType, right_side != null))
2796 } else if (e is EventExpr) {
2797 if (((EventExpr) e).IsAccessibleFrom (ec.CurrentType))
2799 } else if (targs != null && e is TypeExpression) {
2800 e = new GenericTypeExpr (e.Type, targs, loc).ResolveAsTypeStep (ec, false);
2808 if (almost_matched == null && almost_matched_members.Count > 0) {
2809 almost_matched_type = lookup_ds;
2810 almost_matched = new List<MemberInfo>(almost_matched_members);
2815 if (almost_matched == null && almost_matched_members.Count > 0) {
2816 almost_matched_type = ec.CurrentType;
2817 almost_matched = new List<MemberInfo> (almost_matched_members);
2819 e = ResolveAsTypeStep (ec, true);
2823 if (current_block != null) {
2824 IKnownVariable ikv = current_block.Explicit.GetKnownVariable (Name);
2826 LocalInfo li = ikv as LocalInfo;
2827 // Supress CS0219 warning
2831 Error_VariableIsUsedBeforeItIsDeclared (ec.Report, Name);
2836 if (RootContext.EvalMode){
2837 FieldInfo fi = Evaluator.LookupField (Name);
2839 return new FieldExpr (Import.CreateField (fi), loc).Resolve (ec);
2842 if (almost_matched != null)
2843 almost_matched_members = almost_matched;
2844 if (almost_matched_type == null)
2845 almost_matched_type = ec.CurrentType;
2847 string type_name = ec.MemberContext.CurrentType == null ? null : ec.MemberContext.CurrentType.Name;
2848 return Error_MemberLookupFailed (ec, ec.CurrentType, null, almost_matched_type, Name,
2849 type_name, AllMemberTypes, AllBindingFlags);
2852 if (e is MemberExpr) {
2853 MemberExpr me = (MemberExpr) e;
2856 if (me.IsInstance) {
2857 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope)) {
2859 // Note that an MemberExpr can be both IsInstance and IsStatic.
2860 // An unresolved MethodGroupExpr can contain both kinds of methods
2861 // and each predicate is true if the MethodGroupExpr contains
2862 // at least one of that kind of method.
2866 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2867 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2872 // Pass the buck to MemberAccess and Invocation.
2874 left = EmptyExpression.Null;
2876 left = ec.GetThis (loc);
2879 left = new TypeExpression (ec.CurrentType, loc);
2882 me = me.ResolveMemberAccess (ec, left, loc, null);
2886 if (targs != null) {
2887 if (!targs.Resolve (ec))
2890 me.SetTypeArguments (ec, targs);
2893 if (!me.IsStatic && (me.InstanceExpression != null && me.InstanceExpression != EmptyExpression.Null) &&
2894 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2895 me.InstanceExpression.Type != me.DeclaringType &&
2896 !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2897 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2898 ec.Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2899 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2903 return (right_side != null)
2904 ? me.DoResolveLValue (ec, right_side)
2913 /// Represents a namespace or a type. The name of the class was inspired by
2914 /// section 10.8.1 (Fully Qualified Names).
2916 public abstract class FullNamedExpression : Expression
2918 protected override void CloneTo (CloneContext clonectx, Expression target)
2920 // Do nothing, most unresolved type expressions cannot be
2921 // resolved to different type
2924 public override Expression CreateExpressionTree (ResolveContext ec)
2926 throw new NotSupportedException ("ET");
2929 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2931 throw new NotSupportedException ();
2934 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2939 public override void Emit (EmitContext ec)
2941 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2942 GetSignatureForError ());
2947 /// Expression that evaluates to a type
2949 public abstract class TypeExpr : FullNamedExpression {
2950 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2952 TypeExpr t = DoResolveAsTypeStep (ec);
2956 eclass = ExprClass.Type;
2960 protected override Expression DoResolve (ResolveContext ec)
2962 return ResolveAsTypeTerminal (ec, false);
2965 public virtual bool CheckAccessLevel (IMemberContext mc)
2967 return mc.CurrentTypeDefinition.CheckAccessLevel (Type);
2970 public virtual bool IsClass {
2971 get { return Type.IsClass; }
2974 public virtual bool IsValueType {
2975 get { return TypeManager.IsStruct (Type); }
2978 public virtual bool IsInterface {
2979 get { return Type.IsInterface; }
2982 public virtual bool IsSealed {
2983 get { return Type.IsSealed; }
2986 public virtual bool CanInheritFrom ()
2988 if (Type == TypeManager.enum_type ||
2989 (Type == TypeManager.value_type && RootContext.StdLib) ||
2990 Type == TypeManager.multicast_delegate_type ||
2991 Type == TypeManager.delegate_type ||
2992 Type == TypeManager.array_type)
2998 protected abstract TypeExpr DoResolveAsTypeStep (IMemberContext ec);
3000 public override bool Equals (object obj)
3002 TypeExpr tobj = obj as TypeExpr;
3006 return Type == tobj.Type;
3009 public override int GetHashCode ()
3011 return Type.GetHashCode ();
3014 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3016 type = storey.MutateType (type);
3021 /// Fully resolved Expression that already evaluated to a type
3023 public class TypeExpression : TypeExpr {
3024 public TypeExpression (Type t, Location l)
3027 eclass = ExprClass.Type;
3031 protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec)
3036 public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
3043 // Used to create types from a fully qualified name. These are just used
3044 // by the parser to setup the core types.
3046 public sealed class TypeLookupExpression : TypeExpr {
3047 readonly string ns_name;
3048 readonly string name;
3050 public TypeLookupExpression (string ns, string name)
3054 eclass = ExprClass.Type;
3057 public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
3060 // It's null only during mscorlib bootstrap when DefineType
3061 // nees to resolve base type of same type
3063 // For instance struct Char : IComparable<char>
3065 // TODO: it could be removed when Resolve starts to use
3066 // DeclSpace instead of Type
3069 Namespace ns = GlobalRootNamespace.Instance.GetNamespace (ns_name, false);
3070 FullNamedExpression fne = ns.Lookup (ec.Compiler, name, loc);
3078 protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec)
3083 public override string GetSignatureForError ()
3086 return TypeManager.CSharpName (ns_name + "." + name, null);
3088 return base.GetSignatureForError ();
3093 /// This class denotes an expression which evaluates to a member
3094 /// of a struct or a class.
3096 public abstract class MemberExpr : Expression
3098 protected bool is_base;
3101 /// The name of this member.
3103 public abstract string Name {
3108 // When base.member is used
3110 public bool IsBase {
3111 get { return is_base; }
3112 set { is_base = value; }
3116 /// Whether this is an instance member.
3118 public abstract bool IsInstance {
3123 /// Whether this is a static member.
3125 public abstract bool IsStatic {
3130 /// The type which declares this member.
3132 public abstract Type DeclaringType {
3137 /// The instance expression associated with this member, if it's a
3138 /// non-static member.
3140 public Expression InstanceExpression;
3142 public static void error176 (ResolveContext ec, Location loc, string name)
3144 ec.Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
3145 "with an instance reference, qualify it with a type name instead", name);
3148 public static void Error_BaseAccessInExpressionTree (ResolveContext ec, Location loc)
3150 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
3153 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3155 if (InstanceExpression != null)
3156 InstanceExpression.MutateHoistedGenericType (storey);
3159 // TODO: possible optimalization
3160 // Cache resolved constant result in FieldBuilder <-> expression map
3161 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, Location loc,
3162 SimpleName original)
3166 // original == null || original.Resolve (...) ==> left
3169 if (left is TypeExpr) {
3170 left = left.ResolveAsBaseTerminal (ec, false);
3174 // TODO: Same problem as in class.cs, TypeTerminal does not
3175 // always do all necessary checks
3176 ObsoleteAttribute oa = AttributeTester.GetObsoleteAttribute (left.Type);
3177 if (oa != null && !ec.IsObsolete) {
3178 AttributeTester.Report_ObsoleteMessage (oa, left.GetSignatureForError (), loc, ec.Report);
3181 GenericTypeExpr ct = left as GenericTypeExpr;
3182 if (ct != null && !ct.CheckConstraints (ec))
3187 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3195 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3198 return ResolveExtensionMemberAccess (ec, left);
3201 InstanceExpression = left;
3205 protected virtual MemberExpr ResolveExtensionMemberAccess (ResolveContext ec, Expression left)
3207 error176 (ec, loc, GetSignatureForError ());
3211 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3216 if (InstanceExpression == EmptyExpression.Null) {
3217 // FIXME: This should not be here at all
3218 SimpleName.Error_ObjectRefRequired (new ResolveContext (ec.MemberContext), loc, GetSignatureForError ());
3222 if (TypeManager.IsValueType (InstanceExpression.Type)) {
3223 if (InstanceExpression is IMemoryLocation) {
3224 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
3226 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
3227 InstanceExpression.Emit (ec);
3229 t.AddressOf (ec, AddressOp.Store);
3232 InstanceExpression.Emit (ec);
3234 if (prepare_for_load)
3235 ec.ig.Emit (OpCodes.Dup);
3238 public virtual void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3240 // TODO: need to get correct member type
3241 ec.Report.Error (307, loc, "The property `{0}' cannot be used with type arguments",
3242 GetSignatureForError ());
3247 /// Represents group of extension methods
3249 public class ExtensionMethodGroupExpr : MethodGroupExpr
3251 readonly NamespaceEntry namespace_entry;
3252 public Expression ExtensionExpression;
3253 Argument extension_argument;
3255 public ExtensionMethodGroupExpr (List<MethodSpec> list, NamespaceEntry n, Type extensionType, Location l)
3256 : base (list, extensionType, l)
3258 this.namespace_entry = n;
3261 public override bool IsStatic {
3262 get { return true; }
3265 public bool IsTopLevel {
3266 get { return namespace_entry == null; }
3269 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3271 extension_argument.Expr.MutateHoistedGenericType (storey);
3272 base.MutateHoistedGenericType (storey);
3275 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, bool may_fail, Location loc)
3277 if (arguments == null)
3278 arguments = new Arguments (1);
3280 arguments.Insert (0, new Argument (ExtensionExpression));
3281 MethodGroupExpr mg = ResolveOverloadExtensions (ec, ref arguments, namespace_entry, loc);
3283 // Store resolved argument and restore original arguments
3285 ((ExtensionMethodGroupExpr)mg).extension_argument = arguments [0];
3287 arguments.RemoveAt (0); // Clean-up modified arguments for error reporting
3292 MethodGroupExpr ResolveOverloadExtensions (ResolveContext ec, ref Arguments arguments, NamespaceEntry ns, Location loc)
3294 // Use normal resolve rules
3295 MethodGroupExpr mg = base.OverloadResolve (ec, ref arguments, ns != null, loc);
3303 ExtensionMethodGroupExpr e = ns.LookupExtensionMethod (type, Name, loc);
3305 return base.OverloadResolve (ec, ref arguments, false, loc);
3307 e.ExtensionExpression = ExtensionExpression;
3308 e.SetTypeArguments (ec, type_arguments);
3309 return e.ResolveOverloadExtensions (ec, ref arguments, e.namespace_entry, loc);
3314 /// MethodGroupExpr represents a group of method candidates which
3315 /// can be resolved to the best method overload
3317 public class MethodGroupExpr : MemberExpr
3319 public interface IErrorHandler
3321 bool AmbiguousCall (ResolveContext ec, MethodSpec ambiguous);
3322 bool NoExactMatch (ResolveContext ec, MethodSpec method);
3325 public IErrorHandler CustomErrorHandler;
3326 public MethodSpec [] Methods;
3327 MethodSpec best_candidate;
3328 // TODO: make private
3329 public TypeArguments type_arguments;
3330 bool identical_type_name;
3331 bool has_inaccessible_candidates_only;
3335 public MethodGroupExpr (MethodSpec [] mi, Type type, Location l)
3338 Methods = new MethodSpec[mi.Length];
3339 mi.CopyTo (Methods, 0);
3342 public MethodGroupExpr (MethodSpec[] mi, Type type, Location l, bool inacessibleCandidatesOnly)
3343 : this (mi, type, l)
3345 has_inaccessible_candidates_only = inacessibleCandidatesOnly;
3348 public MethodGroupExpr (List<MethodSpec> list, Type type, Location l)
3352 Methods = list.ToArray ();
3354 //foreach (MemberInfo m in list){
3355 // if (!(m is MethodBase)){
3356 // Console.WriteLine ("Name " + m.Name);
3357 // Console.WriteLine ("Found a: " + m.GetType ().FullName);
3366 protected MethodGroupExpr (Type type, Location loc)
3369 eclass = ExprClass.MethodGroup;
3370 this.type = InternalType.MethodGroup;
3371 queried_type = type;
3374 public override Type DeclaringType {
3376 return queried_type;
3380 public MethodSpec BestCandidate {
3382 return best_candidate;
3386 public Type DelegateType {
3388 delegate_type = value;
3392 public bool IdenticalTypeName {
3394 return identical_type_name;
3398 public override string GetSignatureForError ()
3400 if (best_candidate != null)
3401 return TypeManager.CSharpSignature (best_candidate.MetaInfo);
3403 return TypeManager.CSharpSignature (Methods [0].MetaInfo);
3406 public override string Name {
3408 return Methods [0].Name;
3412 public override bool IsInstance {
3414 if (best_candidate != null)
3415 return !best_candidate.IsStatic;
3417 foreach (var mb in Methods)
3425 public override bool IsStatic {
3427 if (best_candidate != null)
3428 return best_candidate.IsStatic;
3430 foreach (var mb in Methods)
3438 public static explicit operator MethodSpec (MethodGroupExpr mg)
3440 return mg.best_candidate;
3444 // 7.4.3.3 Better conversion from expression
3445 // Returns : 1 if a->p is better,
3446 // 2 if a->q is better,
3447 // 0 if neither is better
3449 static int BetterExpressionConversion (ResolveContext ec, Argument a, Type p, Type q)
3451 Type argument_type = TypeManager.TypeToCoreType (a.Type);
3452 if (argument_type == InternalType.AnonymousMethod && RootContext.Version > LanguageVersion.ISO_2) {
3454 // Uwrap delegate from Expression<T>
3456 if (TypeManager.DropGenericTypeArguments (p) == TypeManager.expression_type) {
3457 p = TypeManager.GetTypeArguments (p) [0];
3459 if (TypeManager.DropGenericTypeArguments (q) == TypeManager.expression_type) {
3460 q = TypeManager.GetTypeArguments (q) [0];
3463 p = Delegate.GetInvokeMethod (ec.Compiler, null, p).ReturnType;
3464 q = Delegate.GetInvokeMethod (ec.Compiler, null, q).ReturnType;
3465 if (p == TypeManager.void_type && q != TypeManager.void_type)
3467 if (q == TypeManager.void_type && p != TypeManager.void_type)
3470 if (argument_type == p)
3473 if (argument_type == q)
3477 return BetterTypeConversion (ec, p, q);
3481 // 7.4.3.4 Better conversion from type
3483 public static int BetterTypeConversion (ResolveContext ec, Type p, Type q)
3485 if (p == null || q == null)
3486 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3488 if (p == TypeManager.int32_type) {
3489 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3491 } else if (p == TypeManager.int64_type) {
3492 if (q == TypeManager.uint64_type)
3494 } else if (p == TypeManager.sbyte_type) {
3495 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3496 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3498 } else if (p == TypeManager.short_type) {
3499 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3500 q == TypeManager.uint64_type)
3502 } else if (p == InternalType.Dynamic) {
3503 if (q == TypeManager.object_type)
3507 if (q == TypeManager.int32_type) {
3508 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3510 } if (q == TypeManager.int64_type) {
3511 if (p == TypeManager.uint64_type)
3513 } else if (q == TypeManager.sbyte_type) {
3514 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3515 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3517 } if (q == TypeManager.short_type) {
3518 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3519 p == TypeManager.uint64_type)
3521 } else if (q == InternalType.Dynamic) {
3522 if (p == TypeManager.object_type)
3526 // TODO: this is expensive
3527 Expression p_tmp = new EmptyExpression (p);
3528 Expression q_tmp = new EmptyExpression (q);
3530 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3531 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3533 if (p_to_q && !q_to_p)
3536 if (q_to_p && !p_to_q)
3543 /// Determines "Better function" between candidate
3544 /// and the current best match
3547 /// Returns a boolean indicating :
3548 /// false if candidate ain't better
3549 /// true if candidate is better than the current best match
3551 static bool BetterFunction (ResolveContext ec, Arguments args, int argument_count,
3552 MethodSpec candidate, bool candidate_params,
3553 MethodSpec best, bool best_params)
3555 AParametersCollection candidate_pd = candidate.Parameters;
3556 AParametersCollection best_pd = best.Parameters;
3558 bool better_at_least_one = false;
3560 for (int j = 0, c_idx = 0, b_idx = 0; j < argument_count; ++j, ++c_idx, ++b_idx)
3562 Argument a = args [j];
3564 // Provided default argument value is never better
3565 if (a.IsDefaultArgument && candidate_params == best_params)
3568 Type ct = candidate_pd.Types [c_idx];
3569 Type bt = best_pd.Types [b_idx];
3571 if (candidate_params && candidate_pd.FixedParameters [c_idx].ModFlags == Parameter.Modifier.PARAMS)
3573 ct = TypeManager.GetElementType (ct);
3577 if (best_params && best_pd.FixedParameters [b_idx].ModFlags == Parameter.Modifier.PARAMS)
3579 bt = TypeManager.GetElementType (bt);
3583 if (TypeManager.IsEqual (ct, bt))
3587 int result = BetterExpressionConversion (ec, a, ct, bt);
3589 // for each argument, the conversion to 'ct' should be no worse than
3590 // the conversion to 'bt'.
3594 // for at least one argument, the conversion to 'ct' should be better than
3595 // the conversion to 'bt'.
3597 better_at_least_one = true;
3600 if (better_at_least_one)
3604 // This handles the case
3606 // Add (float f1, float f2, float f3);
3607 // Add (params decimal [] foo);
3609 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3610 // first candidate would've chosen as better.
3616 // The two methods have equal parameter types. Now apply tie-breaking rules
3618 if (best.IsGenericMethod) {
3619 if (!candidate.IsGenericMethod)
3621 } else if (candidate.IsGenericMethod) {
3626 // This handles the following cases:
3628 // Trim () is better than Trim (params char[] chars)
3629 // Concat (string s1, string s2, string s3) is better than
3630 // Concat (string s1, params string [] srest)
3631 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3633 if (!candidate_params && best_params)
3635 if (candidate_params && !best_params)
3638 int candidate_param_count = candidate_pd.Count;
3639 int best_param_count = best_pd.Count;
3641 if (candidate_param_count != best_param_count)
3642 // can only happen if (candidate_params && best_params)
3643 return candidate_param_count > best_param_count && best_pd.HasParams;
3646 // now, both methods have the same number of parameters, and the parameters have the same types
3647 // Pick the "more specific" signature
3650 MethodBase orig_candidate = TypeManager.DropGenericMethodArguments (candidate);
3651 MethodBase orig_best = TypeManager.DropGenericMethodArguments (best);
3653 AParametersCollection orig_candidate_pd = TypeManager.GetParameterData (orig_candidate);
3654 AParametersCollection orig_best_pd = TypeManager.GetParameterData (orig_best);
3656 bool specific_at_least_once = false;
3657 for (int j = 0; j < candidate_param_count; ++j)
3659 Type ct = orig_candidate_pd.Types [j];
3660 Type bt = orig_best_pd.Types [j];
3663 Type specific = MoreSpecific (ct, bt);
3667 specific_at_least_once = true;
3670 if (specific_at_least_once)
3673 // FIXME: handle lifted operators
3679 protected override MemberExpr ResolveExtensionMemberAccess (ResolveContext ec, Expression left)
3682 return base.ResolveExtensionMemberAccess (ec, left);
3685 // When left side is an expression and at least one candidate method is
3686 // static, it can be extension method
3688 InstanceExpression = left;
3692 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, Location loc,
3693 SimpleName original)
3695 if (!(left is TypeExpr) &&
3696 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3697 identical_type_name = true;
3699 return base.ResolveMemberAccess (ec, left, loc, original);
3702 public override Expression CreateExpressionTree (ResolveContext ec)
3704 if (best_candidate == null) {
3705 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3709 IMethodData md = TypeManager.GetMethod (best_candidate.MetaInfo);
3710 if (md != null && md.IsExcluded ())
3711 ec.Report.Error (765, loc,
3712 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3714 return new TypeOfMethod (best_candidate, loc);
3717 protected override Expression DoResolve (ResolveContext ec)
3719 this.eclass = ExprClass.MethodGroup;
3721 if (InstanceExpression != null) {
3722 InstanceExpression = InstanceExpression.Resolve (ec);
3723 if (InstanceExpression == null)
3730 public void ReportUsageError (ResolveContext ec)
3732 ec.Report.Error (654, loc, "Method `" + DeclaringType + "." +
3733 Name + "()' is referenced without parentheses");
3736 override public void Emit (EmitContext ec)
3738 throw new NotSupportedException ();
3739 // ReportUsageError ();
3742 public void EmitCall (EmitContext ec, Arguments arguments)
3744 Invocation.EmitCall (ec, IsBase, InstanceExpression, best_candidate, arguments, loc);
3747 void Error_AmbiguousCall (ResolveContext ec, MethodSpec ambiguous)
3749 if (CustomErrorHandler != null && CustomErrorHandler.AmbiguousCall (ec, ambiguous))
3752 ec.Report.SymbolRelatedToPreviousError (best_candidate.MetaInfo);
3753 ec.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
3754 TypeManager.CSharpSignature (ambiguous), TypeManager.CSharpSignature (best_candidate.MetaInfo));
3757 protected virtual void Error_InvalidArguments (ResolveContext ec, Location loc, int idx, MethodSpec method,
3758 Argument a, AParametersCollection expected_par, Type paramType)
3760 ExtensionMethodGroupExpr emg = this as ExtensionMethodGroupExpr;
3762 if (a is CollectionElementInitializer.ElementInitializerArgument) {
3763 ec.Report.SymbolRelatedToPreviousError (method.MetaInfo);
3764 if ((expected_par.FixedParameters [idx].ModFlags & Parameter.Modifier.ISBYREF) != 0) {
3765 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
3766 TypeManager.CSharpSignature (method));
3769 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
3770 TypeManager.CSharpSignature (method));
3771 } else if (TypeManager.IsDelegateType (method.DeclaringType)) {
3772 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
3773 TypeManager.CSharpName (method.DeclaringType));
3775 ec.Report.SymbolRelatedToPreviousError (method.MetaInfo);
3777 ec.Report.Error (1928, loc,
3778 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3779 emg.ExtensionExpression.GetSignatureForError (),
3780 emg.Name, TypeManager.CSharpSignature (method));
3782 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
3783 TypeManager.CSharpSignature (method));
3787 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters [idx].ModFlags;
3789 string index = (idx + 1).ToString ();
3790 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
3791 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
3792 if ((mod & Parameter.Modifier.ISBYREF) == 0)
3793 ec.Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
3794 index, Parameter.GetModifierSignature (a.Modifier));
3796 ec.Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
3797 index, Parameter.GetModifierSignature (mod));
3799 string p1 = a.GetSignatureForError ();
3800 string p2 = TypeManager.CSharpName (paramType);
3803 ec.Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
3804 ec.Report.SymbolRelatedToPreviousError (a.Expr.Type);
3805 ec.Report.SymbolRelatedToPreviousError (paramType);
3808 if (idx == 0 && emg != null) {
3809 ec.Report.Error (1929, loc,
3810 "Extension method instance type `{0}' cannot be converted to `{1}'", p1, p2);
3812 ec.Report.Error (1503, loc,
3813 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
3818 public override void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, Type target, bool expl)
3820 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3821 Name, TypeManager.CSharpName (target));
3824 void Error_ArgumentCountWrong (ResolveContext ec, int arg_count)
3826 ec.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
3827 Name, arg_count.ToString ());
3830 protected virtual int GetApplicableParametersCount (MethodSpec method, AParametersCollection parameters)
3832 return parameters.Count;
3835 public static bool IsAncestralType (Type first_type, Type second_type)
3837 return first_type != second_type &&
3838 (TypeManager.IsSubclassOf (second_type, first_type) ||
3839 TypeManager.ImplementsInterface (second_type, first_type));
3843 /// Determines if the candidate method is applicable (section 14.4.2.1)
3844 /// to the given set of arguments
3845 /// A return value rates candidate method compatibility,
3846 /// 0 = the best, int.MaxValue = the worst
3848 public int IsApplicable (ResolveContext ec,
3849 ref Arguments arguments, int arg_count, ref MethodSpec method, ref bool params_expanded_form)
3851 var candidate = method;
3853 AParametersCollection pd = candidate.Parameters;
3854 int param_count = GetApplicableParametersCount (candidate, pd);
3855 int optional_count = 0;
3857 if (arg_count != param_count) {
3858 for (int i = 0; i < pd.Count; ++i) {
3859 if (pd.FixedParameters [i].HasDefaultValue) {
3860 optional_count = pd.Count - i;
3865 int args_gap = System.Math.Abs (arg_count - param_count);
3866 if (optional_count != 0) {
3867 if (args_gap > optional_count)
3868 return int.MaxValue - 10000 + args_gap - optional_count;
3870 // Readjust expected number when params used
3873 if (arg_count < param_count)
3875 } else if (arg_count > param_count) {
3876 return int.MaxValue - 10000 + args_gap;
3878 } else if (arg_count != param_count) {
3880 return int.MaxValue - 10000 + args_gap;
3881 if (arg_count < param_count - 1)
3882 return int.MaxValue - 10000 + args_gap;
3885 // Initialize expanded form of a method with 1 params parameter
3886 params_expanded_form = param_count == 1 && pd.HasParams;
3888 // Resize to fit optional arguments
3889 if (optional_count != 0) {
3891 if (arguments == null) {
3892 resized = new Arguments (optional_count);
3894 resized = new Arguments (param_count);
3895 resized.AddRange (arguments);
3898 for (int i = arg_count; i < param_count; ++i)
3900 arguments = resized;
3904 if (arg_count > 0) {
3906 // Shuffle named arguments to the right positions if there are any
3908 if (arguments [arg_count - 1] is NamedArgument) {
3909 arg_count = arguments.Count;
3911 for (int i = 0; i < arg_count; ++i) {
3912 bool arg_moved = false;
3914 NamedArgument na = arguments[i] as NamedArgument;
3918 int index = pd.GetParameterIndexByName (na.Name);
3920 // Named parameter not found or already reordered
3924 // When using parameters which should not be available to the user
3925 if (index >= param_count)
3929 arguments.MarkReorderedArgument (na);
3933 Argument temp = arguments[index];
3934 arguments[index] = arguments[i];
3935 arguments[i] = temp;
3942 arg_count = arguments.Count;
3944 } else if (arguments != null) {
3945 arg_count = arguments.Count;
3949 // 1. Handle generic method using type arguments when specified or type inference
3951 if (candidate.IsGenericMethod) {
3952 if (type_arguments != null) {
3953 Type [] g_args = candidate.GetGenericArguments ();
3954 if (g_args.Length != type_arguments.Count)
3955 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args.Length);
3957 method = candidate.Inflate (type_arguments.Arguments);
3959 pd = candidate.Parameters;
3961 int score = TypeManager.InferTypeArguments (ec, arguments, ref candidate);
3963 return score - 20000;
3965 if (TypeManager.IsGenericMethodDefinition (candidate.MetaInfo))
3966 throw new InternalErrorException ("A generic method `{0}' definition took part in overload resolution",
3967 TypeManager.CSharpSignature (candidate.MetaInfo));
3969 pd = candidate.Parameters;
3972 if (type_arguments != null)
3973 return int.MaxValue - 15000;
3977 // 2. Each argument has to be implicitly convertible to method parameter
3980 Parameter.Modifier p_mod = 0;
3982 for (int i = 0; i < arg_count; i++) {
3983 Argument a = arguments [i];
3985 if (!pd.FixedParameters [i].HasDefaultValue)
3986 throw new InternalErrorException ();
3988 Expression e = pd.FixedParameters [i].DefaultValue as Constant;
3990 e = new DefaultValueExpression (new TypeExpression (pd.Types [i], loc), loc).Resolve (ec);
3992 arguments [i] = new Argument (e, Argument.AType.Default);
3996 if (p_mod != Parameter.Modifier.PARAMS) {
3997 p_mod = pd.FixedParameters [i].ModFlags & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
4000 params_expanded_form = true;
4003 Parameter.Modifier a_mod = a.Modifier & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
4005 if (!params_expanded_form)
4006 score = IsArgumentCompatible (ec, a_mod, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
4008 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && delegate_type == null) {
4009 // It can be applicable in expanded form
4010 score = IsArgumentCompatible (ec, a_mod, a, 0, TypeManager.GetElementType (pt));
4012 params_expanded_form = true;
4016 if (params_expanded_form)
4018 return (arg_count - i) * 2 + score;
4022 if (arg_count != param_count)
4023 params_expanded_form = true;
4028 int IsArgumentCompatible (ResolveContext ec, Parameter.Modifier arg_mod, Argument argument, Parameter.Modifier param_mod, Type parameter)
4031 // Types have to be identical when ref or out modifer is used
4033 if (arg_mod != 0 || param_mod != 0) {
4034 if (TypeManager.HasElementType (parameter))
4035 parameter = TypeManager.GetElementType (parameter);
4037 Type a_type = argument.Type;
4038 if (TypeManager.HasElementType (a_type))
4039 a_type = TypeManager.GetElementType (a_type);
4041 if (a_type != parameter) {
4042 if (TypeManager.IsDynamicType (a_type))
4048 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
4049 if (TypeManager.IsDynamicType (argument.Type))
4056 if (arg_mod != param_mod)
4062 public static bool IsOverride (MethodBase cand_method, MethodBase base_method)
4064 if (!IsAncestralType (base_method.DeclaringType, cand_method.DeclaringType))
4067 AParametersCollection cand_pd = TypeManager.GetParameterData (cand_method);
4068 AParametersCollection base_pd = TypeManager.GetParameterData (base_method);
4070 if (cand_pd.Count != base_pd.Count)
4073 for (int j = 0; j < cand_pd.Count; ++j)
4075 Parameter.Modifier cm = cand_pd.FixedParameters [j].ModFlags;
4076 Parameter.Modifier bm = base_pd.FixedParameters [j].ModFlags;
4077 Type ct = cand_pd.Types [j];
4078 Type bt = base_pd.Types [j];
4080 if (cm != bm || ct != bt)
4087 public static MethodGroupExpr MakeUnionSet (MethodGroupExpr mg1, MethodGroupExpr mg2, Location loc)
4098 var all = new List<MethodSpec> (mg1.Methods);
4099 foreach (var m in mg2.Methods){
4100 if (!TypeManager.ArrayContainsMethod (mg1.Methods.Select (l => l.MetaInfo).ToArray (), m.MetaInfo, false))
4104 return new MethodGroupExpr (all, null, loc);
4107 static Type MoreSpecific (Type p, Type q)
4109 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4111 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4114 if (TypeManager.HasElementType (p))
4116 Type pe = TypeManager.GetElementType (p);
4117 Type qe = TypeManager.GetElementType (q);
4118 Type specific = MoreSpecific (pe, qe);
4124 else if (TypeManager.IsGenericType (p))
4126 Type[] pargs = TypeManager.GetTypeArguments (p);
4127 Type[] qargs = TypeManager.GetTypeArguments (q);
4129 bool p_specific_at_least_once = false;
4130 bool q_specific_at_least_once = false;
4132 for (int i = 0; i < pargs.Length; i++)
4134 Type specific = MoreSpecific (TypeManager.TypeToCoreType (pargs [i]), TypeManager.TypeToCoreType (qargs [i]));
4135 if (specific == pargs [i])
4136 p_specific_at_least_once = true;
4137 if (specific == qargs [i])
4138 q_specific_at_least_once = true;
4141 if (p_specific_at_least_once && !q_specific_at_least_once)
4143 if (!p_specific_at_least_once && q_specific_at_least_once)
4150 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4152 base.MutateHoistedGenericType (storey);
4154 if (best_candidate.IsConstructor) {
4155 storey.MutateConstructor (best_candidate);
4157 storey.MutateGenericMethod (best_candidate);
4162 /// Find the Applicable Function Members (7.4.2.1)
4164 /// me: Method Group expression with the members to select.
4165 /// it might contain constructors or methods (or anything
4166 /// that maps to a method).
4168 /// Arguments: ArrayList containing resolved Argument objects.
4170 /// loc: The location if we want an error to be reported, or a Null
4171 /// location for "probing" purposes.
4173 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4174 /// that is the best match of me on Arguments.
4177 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments Arguments,
4178 bool may_fail, Location loc)
4180 bool method_params = false;
4181 Type applicable_type = null;
4182 var candidates = new List<MethodSpec> (2);
4183 List<MethodSpec> candidate_overrides = null;
4186 // Used to keep a map between the candidate
4187 // and whether it is being considered in its
4188 // normal or expanded form
4190 // false is normal form, true is expanded form
4192 Dictionary<MethodSpec, MethodSpec> candidate_to_form = null;
4193 Dictionary<MethodSpec, Arguments> candidates_expanded = null;
4194 Arguments candidate_args = Arguments;
4196 int arg_count = Arguments != null ? Arguments.Count : 0;
4198 if (RootContext.Version == LanguageVersion.ISO_1 && Name == "Invoke" && TypeManager.IsDelegateType (DeclaringType)) {
4200 ec.Report.Error (1533, loc, "Invoke cannot be called directly on a delegate");
4204 int nmethods = Methods.Length;
4208 // Methods marked 'override' don't take part in 'applicable_type'
4209 // computation, nor in the actual overload resolution.
4210 // However, they still need to be emitted instead of a base virtual method.
4211 // So, we salt them away into the 'candidate_overrides' array.
4213 // In case of reflected methods, we replace each overriding method with
4214 // its corresponding base virtual method. This is to improve compatibility
4215 // with non-C# libraries which change the visibility of overrides (#75636)
4218 MethodBase mb = null;
4219 for (int i = 0; i < Methods.Length; ++i) {
4220 var m = Methods [i];
4222 if (TypeManager.IsOverride (m)) {
4223 if (candidate_overrides == null)
4224 candidate_overrides = new List<MethodSpec> ();
4225 candidate_overrides.Add (m);
4226 mb = TypeManager.TryGetBaseDefinition (mb);
4227 if (mb != null && Array.Exists (Methods, l => l.MetaInfo == mb))
4231 Methods [j++] = Import.CreateMethod (mb);
4237 // Enable message recording, it's used mainly by lambda expressions
4239 SessionReportPrinter msg_recorder = new SessionReportPrinter ();
4240 ReportPrinter prev_recorder = ec.Report.SetPrinter (msg_recorder);
4243 // First we construct the set of applicable methods
4245 bool is_sorted = true;
4246 int best_candidate_rate = int.MaxValue;
4247 for (int i = 0; i < nmethods; i++) {
4248 Type decl_type = Methods [i].DeclaringType;
4251 // If we have already found an applicable method
4252 // we eliminate all base types (Section 14.5.5.1)
4254 if (applicable_type != null && IsAncestralType (decl_type, applicable_type))
4258 // Check if candidate is applicable (section 14.4.2.1)
4260 bool params_expanded_form = false;
4261 int candidate_rate = IsApplicable (ec, ref candidate_args, arg_count, ref Methods [i], ref params_expanded_form);
4263 if (candidate_rate < best_candidate_rate) {
4264 best_candidate_rate = candidate_rate;
4265 best_candidate = Methods [i];
4268 if (params_expanded_form) {
4269 if (candidate_to_form == null)
4270 candidate_to_form = new Dictionary<MethodSpec, MethodSpec> (4, ReferenceEquality<MethodSpec>.Default);
4271 var candidate = Methods [i];
4272 candidate_to_form [candidate] = candidate;
4275 if (candidate_args != Arguments) {
4276 if (candidates_expanded == null)
4277 candidates_expanded = new Dictionary<MethodSpec, Arguments> (4, ReferenceEquality<MethodSpec>.Default);
4279 candidates_expanded.Add (Methods [i], candidate_args);
4280 candidate_args = Arguments;
4283 if (candidate_rate != 0 || has_inaccessible_candidates_only) {
4284 if (msg_recorder != null)
4285 msg_recorder.EndSession ();
4289 msg_recorder = null;
4290 candidates.Add (Methods [i]);
4292 if (applicable_type == null)
4293 applicable_type = decl_type;
4294 else if (applicable_type != decl_type) {
4296 if (IsAncestralType (applicable_type, decl_type))
4297 applicable_type = decl_type;
4301 ec.Report.SetPrinter (prev_recorder);
4302 if (msg_recorder != null && !msg_recorder.IsEmpty) {
4304 msg_recorder.Merge (prev_recorder);
4309 int candidate_top = candidates.Count;
4311 if (applicable_type == null) {
4313 // When we found a top level method which does not match and it's
4314 // not an extension method. We start extension methods lookup from here
4316 if (InstanceExpression != null) {
4317 ExtensionMethodGroupExpr ex_method_lookup = ec.LookupExtensionMethod (type, Name, loc);
4318 if (ex_method_lookup != null) {
4319 ex_method_lookup.ExtensionExpression = InstanceExpression;
4320 ex_method_lookup.SetTypeArguments (ec, type_arguments);
4321 return ex_method_lookup.OverloadResolve (ec, ref Arguments, may_fail, loc);
4329 // Okay so we have failed to find exact match so we
4330 // return error info about the closest match
4332 if (best_candidate != null) {
4333 if (CustomErrorHandler != null && !has_inaccessible_candidates_only && CustomErrorHandler.NoExactMatch (ec, best_candidate))
4336 if (NoExactMatch (ec, ref Arguments, candidate_to_form))
4341 // We failed to find any method with correct argument count
4343 if (Name == ConstructorInfo.ConstructorName) {
4344 ec.Report.SymbolRelatedToPreviousError (queried_type);
4345 ec.Report.Error (1729, loc,
4346 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4347 TypeManager.CSharpName (queried_type), arg_count);
4349 Error_ArgumentCountWrong (ec, arg_count);
4355 if (arg_count != 0 && Arguments.HasDynamic) {
4356 best_candidate = null;
4362 // At this point, applicable_type is _one_ of the most derived types
4363 // in the set of types containing the methods in this MethodGroup.
4364 // Filter the candidates so that they only contain methods from the
4365 // most derived types.
4368 int finalized = 0; // Number of finalized candidates
4371 // Invariant: applicable_type is a most derived type
4373 // We'll try to complete Section 14.5.5.1 for 'applicable_type' by
4374 // eliminating all it's base types. At the same time, we'll also move
4375 // every unrelated type to the end of the array, and pick the next
4376 // 'applicable_type'.
4378 Type next_applicable_type = null;
4379 int j = finalized; // where to put the next finalized candidate
4380 int k = finalized; // where to put the next undiscarded candidate
4381 for (int i = finalized; i < candidate_top; ++i) {
4382 var candidate = candidates [i];
4383 Type decl_type = candidate.DeclaringType;
4385 if (decl_type == applicable_type) {
4386 candidates [k++] = candidates [j];
4387 candidates [j++] = candidates [i];
4391 if (IsAncestralType (decl_type, applicable_type))
4394 if (next_applicable_type != null &&
4395 IsAncestralType (decl_type, next_applicable_type))
4398 candidates [k++] = candidates [i];
4400 if (next_applicable_type == null ||
4401 IsAncestralType (next_applicable_type, decl_type))
4402 next_applicable_type = decl_type;
4405 applicable_type = next_applicable_type;
4408 } while (applicable_type != null);
4412 // Now we actually find the best method
4415 best_candidate = candidates [0];
4416 method_params = candidate_to_form != null && candidate_to_form.ContainsKey (best_candidate);
4419 // TODO: Broken inverse order of candidates logic does not work with optional
4420 // parameters used for method overrides and I am not going to fix it for SRE
4422 if (candidates_expanded != null && candidates_expanded.ContainsKey (best_candidate)) {
4423 candidate_args = candidates_expanded [best_candidate];
4424 arg_count = candidate_args.Count;
4427 for (int ix = 1; ix < candidate_top; ix++) {
4428 var candidate = candidates [ix];
4430 if (candidate.MetaInfo == best_candidate.MetaInfo)
4433 bool cand_params = candidate_to_form != null && candidate_to_form.ContainsKey (candidate);
4435 if (BetterFunction (ec, candidate_args, arg_count,
4436 candidate, cand_params,
4437 best_candidate, method_params)) {
4438 best_candidate = candidate;
4439 method_params = cand_params;
4443 // Now check that there are no ambiguities i.e the selected method
4444 // should be better than all the others
4446 MethodSpec ambiguous = null;
4447 for (int ix = 1; ix < candidate_top; ix++) {
4448 var candidate = candidates [ix];
4450 if (candidate.MetaInfo == best_candidate.MetaInfo)
4453 bool cand_params = candidate_to_form != null && candidate_to_form.ContainsKey (candidate);
4454 if (!BetterFunction (ec, candidate_args, arg_count,
4455 best_candidate, method_params,
4456 candidate, cand_params))
4459 ec.Report.SymbolRelatedToPreviousError (candidate.MetaInfo);
4460 ambiguous = candidate;
4464 if (ambiguous != null) {
4465 Error_AmbiguousCall (ec, ambiguous);
4470 // If the method is a virtual function, pick an override closer to the LHS type.
4472 if (!IsBase && best_candidate.IsVirtual) {
4473 if (TypeManager.IsOverride (best_candidate))
4474 throw new InternalErrorException (
4475 "Should not happen. An 'override' method took part in overload resolution: " + best_candidate);
4477 if (candidate_overrides != null) {
4478 Type[] gen_args = null;
4479 bool gen_override = false;
4480 if (best_candidate.IsGenericMethod)
4481 gen_args = TypeManager.GetGenericArguments (best_candidate.MetaInfo);
4483 foreach (var candidate in candidate_overrides) {
4484 if (candidate.IsGenericMethod) {
4485 if (gen_args == null)
4488 if (gen_args.Length != TypeManager.GetGenericArguments (candidate.MetaInfo).Length)
4491 if (gen_args != null)
4495 if (IsOverride (candidate.MetaInfo, best_candidate.MetaInfo)) {
4496 gen_override = true;
4497 best_candidate = candidate;
4501 if (gen_override && gen_args != null) {
4502 best_candidate = best_candidate.Inflate (gen_args);
4508 // And now check if the arguments are all
4509 // compatible, perform conversions if
4510 // necessary etc. and return if everything is
4513 if (!VerifyArgumentsCompat (ec, ref candidate_args, arg_count, best_candidate,
4514 method_params, may_fail, loc))
4517 if (best_candidate == null)
4520 MethodBase the_method = TypeManager.DropGenericMethodArguments (best_candidate);
4521 if (TypeManager.IsGenericMethodDefinition (the_method) &&
4522 !ConstraintChecker.CheckConstraints (ec, the_method, best_candidate.MetaInfo, loc))
4526 // Check ObsoleteAttribute on the best method
4528 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (the_method);
4529 if (oa != null && !ec.IsObsolete)
4530 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
4532 IMethodData data = TypeManager.GetMethod (the_method);
4536 Arguments = candidate_args;
4540 bool NoExactMatch (ResolveContext ec, ref Arguments Arguments, IDictionary<MethodSpec, MethodSpec> candidate_to_form)
4542 AParametersCollection pd = best_candidate.Parameters;
4543 int arg_count = Arguments == null ? 0 : Arguments.Count;
4545 if (arg_count == pd.Count || pd.HasParams) {
4546 if (TypeManager.IsGenericMethodDefinition (best_candidate.MetaInfo)) {
4547 if (type_arguments == null) {
4548 ec.Report.Error (411, loc,
4549 "The type arguments for method `{0}' cannot be inferred from " +
4550 "the usage. Try specifying the type arguments explicitly",
4551 TypeManager.CSharpSignature (best_candidate.MetaInfo));
4555 Type[] g_args = TypeManager.GetGenericArguments (best_candidate.MetaInfo);
4556 if (type_arguments.Count != g_args.Length) {
4557 ec.Report.SymbolRelatedToPreviousError (best_candidate.MetaInfo);
4558 ec.Report.Error (305, loc, "Using the generic method `{0}' requires `{1}' type argument(s)",
4559 TypeManager.CSharpSignature (best_candidate.MetaInfo),
4560 g_args.Length.ToString ());
4564 if (type_arguments != null && !best_candidate.IsGenericMethod) {
4565 Error_TypeArgumentsCannotBeUsed (ec.Report, loc);
4570 if (has_inaccessible_candidates_only) {
4571 if (InstanceExpression != null && type != ec.CurrentType && TypeManager.IsNestedFamilyAccessible (ec.CurrentType, best_candidate.DeclaringType)) {
4572 // Although a derived class can access protected members of
4573 // its base class it cannot do so through an instance of the
4574 // base class (CS1540). If the qualifier_type is a base of the
4575 // ec.CurrentType and the lookup succeeds with the latter one,
4576 // then we are in this situation.
4577 Error_CannotAccessProtected (ec, loc, best_candidate.MetaInfo, queried_type, ec.CurrentType);
4579 ec.Report.SymbolRelatedToPreviousError (best_candidate.MetaInfo);
4580 ErrorIsInaccesible (loc, GetSignatureForError (), ec.Report);
4584 bool cand_params = candidate_to_form != null && candidate_to_form.ContainsKey (best_candidate);
4585 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate, cand_params, false, loc))
4588 if (has_inaccessible_candidates_only)
4595 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4597 type_arguments = ta;
4600 public bool VerifyArgumentsCompat (ResolveContext ec, ref Arguments arguments,
4601 int arg_count, MethodSpec method,
4602 bool chose_params_expanded,
4603 bool may_fail, Location loc)
4605 AParametersCollection pd = method.Parameters;
4606 int param_count = GetApplicableParametersCount (method, pd);
4608 int errors = ec.Report.Errors;
4609 Parameter.Modifier p_mod = 0;
4611 int a_idx = 0, a_pos = 0;
4613 ArrayInitializer params_initializers = null;
4614 bool has_unsafe_arg = method.ReturnType.IsPointer;
4616 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4617 a = arguments [a_idx];
4618 if (p_mod != Parameter.Modifier.PARAMS) {
4619 p_mod = pd.FixedParameters [a_idx].ModFlags;
4620 pt = pd.Types [a_idx];
4621 has_unsafe_arg |= pt.IsPointer;
4623 if (p_mod == Parameter.Modifier.PARAMS) {
4624 if (chose_params_expanded) {
4625 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
4626 pt = TypeManager.GetElementType (pt);
4632 // Types have to be identical when ref or out modifer is used
4634 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4635 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4638 if (!TypeManager.IsEqual (a.Expr.Type, pt))
4643 NamedArgument na = a as NamedArgument;
4645 int name_index = pd.GetParameterIndexByName (na.Name);
4646 if (name_index < 0 || name_index >= param_count) {
4647 if (DeclaringType != null && TypeManager.IsDelegateType (DeclaringType)) {
4648 ec.Report.SymbolRelatedToPreviousError (DeclaringType);
4649 ec.Report.Error (1746, na.Location,
4650 "The delegate `{0}' does not contain a parameter named `{1}'",
4651 TypeManager.CSharpName (DeclaringType), na.Name);
4653 ec.Report.SymbolRelatedToPreviousError (best_candidate.MetaInfo);
4654 ec.Report.Error (1739, na.Location,
4655 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
4656 TypeManager.CSharpSignature (method.MetaInfo), na.Name);
4658 } else if (arguments[name_index] != a) {
4659 if (DeclaringType != null && TypeManager.IsDelegateType (DeclaringType))
4660 ec.Report.SymbolRelatedToPreviousError (DeclaringType);
4662 ec.Report.SymbolRelatedToPreviousError (best_candidate.MetaInfo);
4664 ec.Report.Error (1744, na.Location,
4665 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
4671 if (TypeManager.IsDynamicType (a.Expr.Type))
4674 if (delegate_type != null && !Delegate.IsTypeCovariant (a.Expr, pt))
4677 Expression conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4682 // Convert params arguments to an array initializer
4684 if (params_initializers != null) {
4685 // we choose to use 'a.Expr' rather than 'conv' so that
4686 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
4687 params_initializers.Add (a.Expr);
4688 arguments.RemoveAt (a_idx--);
4693 // Update the argument with the implicit conversion
4697 if (a_idx != arg_count) {
4698 if (!may_fail && ec.Report.Errors == errors) {
4699 if (CustomErrorHandler != null)
4700 CustomErrorHandler.NoExactMatch (ec, best_candidate);
4702 Error_InvalidArguments (ec, loc, a_pos, method, a, pd, pt);
4708 // Fill not provided arguments required by params modifier
4710 if (params_initializers == null && pd.HasParams && arg_count + 1 == param_count) {
4711 if (arguments == null)
4712 arguments = new Arguments (1);
4714 pt = pd.Types [param_count - 1];
4715 pt = TypeManager.GetElementType (pt);
4716 has_unsafe_arg |= pt.IsPointer;
4717 params_initializers = new ArrayInitializer (0, loc);
4721 // Append an array argument with all params arguments
4723 if (params_initializers != null) {
4724 arguments.Add (new Argument (
4725 new ArrayCreation (new TypeExpression (pt, loc), "[]", params_initializers, loc).Resolve (ec)));
4729 if (arg_count < param_count) {
4731 Error_ArgumentCountWrong (ec, arg_count);
4735 if (has_unsafe_arg && !ec.IsUnsafe) {
4737 UnsafeError (ec, loc);
4745 public class ConstantExpr : MemberExpr
4749 public ConstantExpr (ConstSpec constant, Location loc)
4751 this.constant = constant;
4755 public override string Name {
4756 get { throw new NotImplementedException (); }
4759 public override bool IsInstance {
4760 get { return !IsStatic; }
4763 public override bool IsStatic {
4764 get { return true; }
4767 public override Type DeclaringType {
4768 get { return constant.DeclaringType; }
4771 public override Expression CreateExpressionTree (ResolveContext ec)
4773 throw new NotSupportedException ("ET");
4776 protected override Expression DoResolve (ResolveContext rc)
4778 constant.MemberDefinition.SetIsUsed ();
4780 if (!rc.IsObsolete) {
4781 var oa = constant.GetObsoleteAttribute ();
4783 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (constant.MetaInfo), loc, rc.Report);
4786 // Constants are resolved on-demand
4787 var c = constant.Value.Resolve (rc) as Constant;
4789 // Creates reference expression to the constant value
4790 return Constant.CreateConstant (rc, c.Type, c.GetValue (), loc);
4793 public override void Emit (EmitContext ec)
4795 throw new NotSupportedException ();
4798 public override string GetSignatureForError ()
4800 return TypeManager.GetFullNameSignature (constant.MetaInfo);
4805 /// Fully resolved expression that evaluates to a Field
4807 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference {
4808 protected FieldSpec spec;
4809 readonly Type constructed_generic_type;
4810 VariableInfo variable_info;
4812 LocalTemporary temp;
4815 protected FieldExpr (Location l)
4820 public FieldExpr (FieldSpec spec, Location loc)
4825 type = TypeManager.TypeToCoreType (spec.FieldType);
4828 public FieldExpr (FieldBase fi, Location l)
4834 public FieldExpr (Field fi, Type genericType, Location l)
4837 if (TypeManager.IsGenericTypeDefinition (genericType))
4839 this.constructed_generic_type = genericType;
4842 public override string Name {
4848 public override bool IsInstance {
4850 return !spec.IsStatic;
4854 public override bool IsStatic {
4856 return spec.IsStatic;
4860 public FieldSpec Spec {
4866 public override Type DeclaringType {
4868 return spec.MetaInfo.DeclaringType;
4872 public override string GetSignatureForError ()
4874 return TypeManager.GetFullNameSignature (spec.MetaInfo);
4877 public VariableInfo VariableInfo {
4879 return variable_info;
4883 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, Location loc,
4884 SimpleName original)
4886 FieldInfo fi = TypeManager.GetGenericFieldDefinition (spec.MetaInfo);
4887 Type t = fi.FieldType;
4889 if (t.IsPointer && !ec.IsUnsafe) {
4890 UnsafeError (ec, loc);
4893 return base.ResolveMemberAccess (ec, left, loc, original);
4896 public void SetHasAddressTaken ()
4898 IVariableReference vr = InstanceExpression as IVariableReference;
4900 vr.SetHasAddressTaken ();
4903 public override Expression CreateExpressionTree (ResolveContext ec)
4905 Expression instance;
4906 if (InstanceExpression == null) {
4907 instance = new NullLiteral (loc);
4909 instance = InstanceExpression.CreateExpressionTree (ec);
4912 Arguments args = Arguments.CreateForExpressionTree (ec, null,
4914 CreateTypeOfExpression ());
4916 return CreateExpressionFactoryCall (ec, "Field", args);
4919 public Expression CreateTypeOfExpression ()
4921 return new TypeOfField (Import.CreateField (GetConstructedFieldInfo ()), loc);
4924 protected override Expression DoResolve (ResolveContext ec)
4926 return DoResolve (ec, false, false);
4929 Expression DoResolve (ResolveContext ec, bool lvalue_instance, bool out_access)
4932 if (InstanceExpression == null){
4934 // This can happen when referencing an instance field using
4935 // a fully qualified type expression: TypeName.InstanceField = xxx
4937 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4941 // Resolve the field's instance expression while flow analysis is turned
4942 // off: when accessing a field "a.b", we must check whether the field
4943 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4945 if (lvalue_instance) {
4946 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
4947 Expression right_side =
4948 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4950 if (InstanceExpression != EmptyExpression.Null)
4951 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
4954 if (InstanceExpression != EmptyExpression.Null) {
4955 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
4956 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
4961 if (InstanceExpression == null)
4964 using (ec.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
4965 InstanceExpression.CheckMarshalByRefAccess (ec);
4969 if (!ec.IsObsolete) {
4970 FieldBase f = TypeManager.GetField (spec.MetaInfo);
4972 f.CheckObsoleteness (loc);
4974 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (spec.MetaInfo);
4976 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (spec.MetaInfo), loc, ec.Report);
4980 var fb = spec as FixedFieldSpec;
4981 IVariableReference var = InstanceExpression as IVariableReference;
4984 IFixedExpression fe = InstanceExpression as IFixedExpression;
4985 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
4986 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4989 if (InstanceExpression.eclass != ExprClass.Variable) {
4990 ec.Report.SymbolRelatedToPreviousError (spec.MetaInfo);
4991 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4992 TypeManager.GetFullNameSignature (spec.MetaInfo));
4993 } else if (var != null && var.IsHoisted) {
4994 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
4997 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
5000 eclass = ExprClass.Variable;
5002 // If the instance expression is a local variable or parameter.
5003 if (var == null || var.VariableInfo == null)
5006 VariableInfo vi = var.VariableInfo;
5007 if (!vi.IsFieldAssigned (ec, Name, loc))
5010 variable_info = vi.GetSubStruct (Name);
5014 static readonly int [] codes = {
5015 191, // instance, write access
5016 192, // instance, out access
5017 198, // static, write access
5018 199, // static, out access
5019 1648, // member of value instance, write access
5020 1649, // member of value instance, out access
5021 1650, // member of value static, write access
5022 1651 // member of value static, out access
5025 static readonly string [] msgs = {
5026 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
5027 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5028 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5029 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
5030 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
5031 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5032 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5033 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
5036 // The return value is always null. Returning a value simplifies calling code.
5037 Expression Report_AssignToReadonly (ResolveContext ec, Expression right_side)
5040 if (right_side == EmptyExpression.OutAccess.Instance || right_side == EmptyExpression.LValueMemberOutAccess)
5044 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
5046 ec.Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
5051 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5053 IVariableReference var = InstanceExpression as IVariableReference;
5054 if (var != null && var.VariableInfo != null)
5055 var.VariableInfo.SetFieldAssigned (ec, Name);
5057 bool lvalue_instance = !spec.IsStatic && TypeManager.IsValueType (spec.MetaInfo.DeclaringType);
5058 bool out_access = right_side == EmptyExpression.OutAccess.Instance || right_side == EmptyExpression.LValueMemberOutAccess;
5060 Expression e = DoResolve (ec, lvalue_instance, out_access);
5065 FieldBase fb = TypeManager.GetField (spec.MetaInfo);
5069 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess.Instance) &&
5070 (fb.ModFlags & Modifiers.VOLATILE) != 0) {
5071 ec.Report.Warning (420, 1, loc,
5072 "`{0}': A volatile field references will not be treated as volatile",
5073 fb.GetSignatureForError ());
5077 if (spec.IsReadOnly) {
5078 // InitOnly fields can only be assigned in constructors or initializers
5079 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
5080 return Report_AssignToReadonly (ec, right_side);
5082 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
5083 Type ctype = ec.CurrentType;
5085 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
5086 if (!TypeManager.IsEqual (ctype, DeclaringType))
5087 return Report_AssignToReadonly (ec, right_side);
5088 // static InitOnly fields cannot be assigned-to in an instance constructor
5089 if (IsStatic && !ec.IsStatic)
5090 return Report_AssignToReadonly (ec, right_side);
5091 // instance constructors can't modify InitOnly fields of other instances of the same type
5092 if (!IsStatic && !(InstanceExpression is This))
5093 return Report_AssignToReadonly (ec, right_side);
5097 if (right_side == EmptyExpression.OutAccess.Instance &&
5098 !IsStatic && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type)) {
5099 ec.Report.SymbolRelatedToPreviousError (DeclaringType);
5100 ec.Report.Warning (197, 1, loc,
5101 "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",
5102 GetSignatureForError ());
5105 eclass = ExprClass.Variable;
5109 bool is_marshal_by_ref ()
5111 return !IsStatic && TypeManager.IsStruct (Type) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type);
5114 public override void CheckMarshalByRefAccess (ResolveContext ec)
5116 if (is_marshal_by_ref () && !(InstanceExpression is This)) {
5117 ec.Report.SymbolRelatedToPreviousError (DeclaringType);
5118 ec.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",
5119 GetSignatureForError ());
5123 public override int GetHashCode ()
5125 return spec.GetHashCode ();
5128 public bool IsFixed {
5131 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
5133 IVariableReference variable = InstanceExpression as IVariableReference;
5134 if (variable != null)
5135 return TypeManager.IsStruct (InstanceExpression.Type) && variable.IsFixed;
5137 IFixedExpression fe = InstanceExpression as IFixedExpression;
5138 return fe != null && fe.IsFixed;
5142 public bool IsHoisted {
5144 IVariableReference hv = InstanceExpression as IVariableReference;
5145 return hv != null && hv.IsHoisted;
5149 public override bool Equals (object obj)
5151 FieldExpr fe = obj as FieldExpr;
5155 if (spec.MetaInfo != fe.spec.MetaInfo)
5158 if (InstanceExpression == null || fe.InstanceExpression == null)
5161 return InstanceExpression.Equals (fe.InstanceExpression);
5164 public void Emit (EmitContext ec, bool leave_copy)
5166 ILGenerator ig = ec.ig;
5167 bool is_volatile = false;
5169 var f = TypeManager.GetField (spec.MetaInfo);
5171 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
5179 ig.Emit (OpCodes.Volatile);
5181 ig.Emit (OpCodes.Ldsfld, GetConstructedFieldInfo ());
5184 EmitInstance (ec, false);
5186 // Optimization for build-in types
5187 if (TypeManager.IsStruct (type) && TypeManager.IsEqual (type, ec.MemberContext.CurrentType)) {
5188 LoadFromPtr (ig, type);
5190 var ff = spec as FixedFieldSpec;
5192 ig.Emit (OpCodes.Ldflda, GetConstructedFieldInfo ());
5193 ig.Emit (OpCodes.Ldflda, ff.Element);
5196 ig.Emit (OpCodes.Volatile);
5198 ig.Emit (OpCodes.Ldfld, GetConstructedFieldInfo ());
5204 ec.ig.Emit (OpCodes.Dup);
5206 temp = new LocalTemporary (this.Type);
5212 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5214 //FieldAttributes fa = FieldInfo.Attributes;
5215 //bool is_static = (fa & FieldAttributes.Static) != 0;
5216 ILGenerator ig = ec.ig;
5218 prepared = prepare_for_load;
5219 EmitInstance (ec, prepared);
5223 ec.ig.Emit (OpCodes.Dup);
5225 temp = new LocalTemporary (this.Type);
5230 FieldBase f = TypeManager.GetField (spec.MetaInfo);
5232 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
5233 ig.Emit (OpCodes.Volatile);
5239 ig.Emit (OpCodes.Stsfld, GetConstructedFieldInfo ());
5241 ig.Emit (OpCodes.Stfld, GetConstructedFieldInfo ());
5250 public override void Emit (EmitContext ec)
5255 public override void EmitSideEffect (EmitContext ec)
5257 FieldBase f = TypeManager.GetField (spec.MetaInfo);
5258 bool is_volatile = f != null && (f.ModFlags & Modifiers.VOLATILE) != 0;
5260 if (is_volatile || is_marshal_by_ref ())
5261 base.EmitSideEffect (ec);
5264 public override void Error_VariableIsUsedBeforeItIsDeclared (Report r, string name)
5267 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the field `{1}'",
5268 name, GetSignatureForError ());
5271 public void AddressOf (EmitContext ec, AddressOp mode)
5273 ILGenerator ig = ec.ig;
5275 FieldBase f = TypeManager.GetField (spec.MetaInfo);
5277 if ((mode & AddressOp.Store) != 0)
5279 if ((mode & AddressOp.Load) != 0)
5284 // Handle initonly fields specially: make a copy and then
5285 // get the address of the copy.
5288 if (spec.IsReadOnly){
5290 if (ec.HasSet (EmitContext.Options.ConstructorScope)){
5303 local = ig.DeclareLocal (type);
5304 ig.Emit (OpCodes.Stloc, local);
5305 ig.Emit (OpCodes.Ldloca, local);
5311 ig.Emit (OpCodes.Ldsflda, GetConstructedFieldInfo ());
5314 EmitInstance (ec, false);
5315 ig.Emit (OpCodes.Ldflda, GetConstructedFieldInfo ());
5319 FieldInfo GetConstructedFieldInfo ()
5321 if (constructed_generic_type == null)
5322 return spec.MetaInfo;
5324 return TypeBuilder.GetField (constructed_generic_type, spec.MetaInfo);
5327 public SLE.Expression MakeAssignExpression (BuilderContext ctx)
5329 return MakeExpression (ctx);
5332 public override SLE.Expression MakeExpression (BuilderContext ctx)
5334 return SLE.Expression.Field (InstanceExpression.MakeExpression (ctx), spec.MetaInfo);
5337 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5339 storey.MutateField (spec);
5340 base.MutateHoistedGenericType (storey);
5346 /// Expression that evaluates to a Property. The Assign class
5347 /// might set the `Value' expression if we are in an assignment.
5349 /// This is not an LValue because we need to re-write the expression, we
5350 /// can not take data from the stack and store it.
5352 public class PropertyExpr : MemberExpr, IDynamicAssign
5355 MethodSpec getter, setter;
5358 TypeArguments targs;
5360 LocalTemporary temp;
5363 public PropertyExpr (Type container_type, PropertySpec spec, Location l)
5368 type = TypeManager.TypeToCoreType (spec.PropertyType);
5370 ResolveAccessors (container_type);
5373 public override string Name {
5379 public override bool IsInstance {
5385 public override bool IsStatic {
5391 public override Expression CreateExpressionTree (ResolveContext ec)
5394 if (IsSingleDimensionalArrayLength ()) {
5395 args = new Arguments (1);
5396 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5397 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
5401 Error_BaseAccessInExpressionTree (ec, loc);
5405 args = new Arguments (2);
5406 if (InstanceExpression == null)
5407 args.Add (new Argument (new NullLiteral (loc)));
5409 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5410 args.Add (new Argument (new TypeOfMethod (getter, loc)));
5411 return CreateExpressionFactoryCall (ec, "Property", args);
5414 public Expression CreateSetterTypeOfExpression ()
5416 return new TypeOfMethod (setter, loc);
5419 public override Type DeclaringType {
5421 return spec.DeclaringType;
5425 public override string GetSignatureForError ()
5427 return TypeManager.GetFullNameSignature (spec.MetaInfo);
5430 void FindAccessors (Type invocation_type)
5432 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
5433 BindingFlags.Static | BindingFlags.Instance |
5434 BindingFlags.DeclaredOnly;
5436 Type current = spec.DeclaringType;
5437 for (; current != null; current = current.BaseType) {
5438 MemberInfo[] group = TypeManager.MemberLookup (
5439 invocation_type, invocation_type, current,
5440 MemberTypes.Property, flags, spec.Name, null);
5445 if (group.Length != 1)
5446 // Oooops, can this ever happen ?
5449 PropertyInfo pi = (PropertyInfo) group [0];
5451 if (getter == null) {
5452 var m = pi.GetGetMethod (true);
5454 getter = Import.CreateMethod (m);
5457 if (setter == null) {
5458 var m = pi.GetSetMethod (true);
5460 setter = Import.CreateMethod (m);
5463 var accessor = getter != null ? getter : setter;
5465 if (!accessor.IsVirtual)
5471 // We also perform the permission checking here, as the PropertyInfo does not
5472 // hold the information for the accessibility of its setter/getter
5474 // TODO: Refactor to use some kind of cache together with GetPropertyFromAccessor
5475 void ResolveAccessors (Type container_type)
5477 FindAccessors (container_type);
5479 if (getter != null) {
5480 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
5481 IMethodData md = TypeManager.GetMethod (the_getter);
5485 is_static = getter.IsStatic;
5488 if (setter != null) {
5489 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
5490 IMethodData md = TypeManager.GetMethod (the_setter);
5494 is_static = setter.IsStatic;
5498 public SLE.Expression MakeAssignExpression (BuilderContext ctx)
5500 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) setter.MetaInfo);
5503 public override SLE.Expression MakeExpression (BuilderContext ctx)
5505 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) getter.MetaInfo);
5508 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5510 if (InstanceExpression != null)
5511 InstanceExpression.MutateHoistedGenericType (storey);
5513 type = storey.MutateType (type);
5515 storey.MutateGenericMethod (getter);
5517 storey.MutateGenericMethod (setter);
5520 public PropertyInfo PropertyInfo {
5522 return spec.MetaInfo;
5526 bool InstanceResolve (ResolveContext ec, bool lvalue_instance, bool must_do_cs1540_check)
5529 InstanceExpression = null;
5533 if (InstanceExpression == null) {
5534 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5538 InstanceExpression = InstanceExpression.Resolve (ec);
5539 if (lvalue_instance && InstanceExpression != null)
5540 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess);
5542 if (InstanceExpression == null)
5545 InstanceExpression.CheckMarshalByRefAccess (ec);
5547 if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) &&
5548 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.CurrentType) &&
5549 !TypeManager.IsNestedChildOf (ec.CurrentType, InstanceExpression.Type) &&
5550 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.CurrentType)) {
5551 ec.Report.SymbolRelatedToPreviousError (spec.MetaInfo);
5552 Error_CannotAccessProtected (ec, loc, spec.MetaInfo, InstanceExpression.Type, ec.CurrentType);
5559 void Error_PropertyNotFound (ResolveContext ec, MethodSpec mi, bool getter)
5561 // TODO: correctly we should compare arguments but it will lead to bigger changes
5562 if (mi.MetaInfo is MethodBuilder) {
5563 Error_TypeDoesNotContainDefinition (ec, loc, spec.DeclaringType, Name);
5567 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
5569 AParametersCollection iparams = mi.Parameters;
5570 sig.Append (getter ? "get_" : "set_");
5572 sig.Append (iparams.GetSignatureForError ());
5574 ec.Report.SymbolRelatedToPreviousError (mi.MetaInfo);
5575 ec.Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
5576 Name, sig.ToString ());
5579 public bool IsAccessibleFrom (Type invocation_type, bool lvalue)
5582 var accessor = lvalue ? setter : getter;
5583 if (accessor == null && lvalue)
5585 return accessor != null && IsAccessorAccessible (invocation_type, accessor, out dummy);
5588 bool IsSingleDimensionalArrayLength ()
5590 if (DeclaringType != TypeManager.array_type || getter == null || Name != "Length")
5593 string t_name = InstanceExpression.Type.Name;
5594 int t_name_len = t_name.Length;
5595 return t_name_len > 2 && t_name [t_name_len - 2] == '[';
5598 protected override Expression DoResolve (ResolveContext ec)
5600 eclass = ExprClass.PropertyAccess;
5602 bool must_do_cs1540_check = false;
5603 ec.Report.DisableReporting ();
5604 bool res = ResolveGetter (ec, ref must_do_cs1540_check);
5605 ec.Report.EnableReporting ();
5608 if (InstanceExpression != null) {
5609 Type expr_type = InstanceExpression.Type;
5610 ExtensionMethodGroupExpr ex_method_lookup = ec.LookupExtensionMethod (expr_type, Name, loc);
5611 if (ex_method_lookup != null) {
5612 ex_method_lookup.ExtensionExpression = InstanceExpression;
5613 ex_method_lookup.SetTypeArguments (ec, targs);
5614 return ex_method_lookup.Resolve (ec);
5618 ResolveGetter (ec, ref must_do_cs1540_check);
5622 if (!InstanceResolve (ec, false, must_do_cs1540_check))
5626 // Only base will allow this invocation to happen.
5628 if (IsBase && getter.IsAbstract) {
5629 Error_CannotCallAbstractBase (ec, TypeManager.GetFullNameSignature (spec.MetaInfo));
5632 if (spec.PropertyType.IsPointer && !ec.IsUnsafe){
5633 UnsafeError (ec, loc);
5636 if (!ec.IsObsolete) {
5637 PropertyBase pb = TypeManager.GetProperty (spec.MetaInfo);
5639 pb.CheckObsoleteness (loc);
5641 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (spec.MetaInfo);
5643 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
5650 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5652 eclass = ExprClass.PropertyAccess;
5654 if (right_side == EmptyExpression.OutAccess.Instance) {
5655 if (ec.CurrentBlock.Toplevel.GetParameterReference (spec.Name, loc) is MemberAccess) {
5656 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5659 right_side.DoResolveLValue (ec, this);
5664 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5665 Error_CannotModifyIntermediateExpressionValue (ec);
5668 if (setter == null){
5670 // The following condition happens if the PropertyExpr was
5671 // created, but is invalid (ie, the property is inaccessible),
5672 // and we did not want to embed the knowledge about this in
5673 // the caller routine. This only avoids double error reporting.
5678 if (ec.CurrentBlock.Toplevel.GetParameterReference (spec.Name, loc) is MemberAccess) {
5679 ec.Report.Error (1947, loc, "A range variable `{0}' cannot be assigned to. Consider using `let' clause to store the value",
5682 ec.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
5683 GetSignatureForError ());
5688 if (targs != null) {
5689 base.SetTypeArguments (ec, targs);
5693 if (setter.Parameters.Count != 1){
5694 Error_PropertyNotFound (ec, setter, false);
5698 bool must_do_cs1540_check;
5699 if (!IsAccessorAccessible (ec.CurrentType, setter, out must_do_cs1540_check)) {
5700 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter.MetaInfo) as PropertyBase.PropertyMethod;
5701 if (pm != null && pm.HasCustomAccessModifier) {
5702 ec.Report.SymbolRelatedToPreviousError (pm);
5703 ec.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5704 TypeManager.CSharpSignature (setter));
5707 ec.Report.SymbolRelatedToPreviousError (setter.MetaInfo);
5708 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter), ec.Report);
5713 if (!InstanceResolve (ec, TypeManager.IsStruct (spec.DeclaringType), must_do_cs1540_check))
5717 // Only base will allow this invocation to happen.
5719 if (IsBase && setter.IsAbstract){
5720 Error_CannotCallAbstractBase (ec, TypeManager.GetFullNameSignature (spec.MetaInfo));
5723 if (spec.PropertyType.IsPointer && !ec.IsUnsafe) {
5724 UnsafeError (ec, loc);
5727 if (!ec.IsObsolete) {
5728 PropertyBase pb = TypeManager.GetProperty (spec.MetaInfo);
5730 pb.CheckObsoleteness (loc);
5732 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (spec.MetaInfo);
5734 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
5741 public override void Emit (EmitContext ec)
5746 public void Emit (EmitContext ec, bool leave_copy)
5749 // Special case: length of single dimension array property is turned into ldlen
5751 if (IsSingleDimensionalArrayLength ()) {
5753 EmitInstance (ec, false);
5754 ec.ig.Emit (OpCodes.Ldlen);
5755 ec.ig.Emit (OpCodes.Conv_I4);
5759 Invocation.EmitCall (ec, IsBase, InstanceExpression, getter, null, loc, prepared, false);
5762 ec.ig.Emit (OpCodes.Dup);
5764 temp = new LocalTemporary (this.Type);
5771 // Implements the IAssignMethod interface for assignments
5773 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5775 Expression my_source = source;
5777 if (prepare_for_load) {
5782 ec.ig.Emit (OpCodes.Dup);
5784 temp = new LocalTemporary (this.Type);
5788 } else if (leave_copy) {
5790 temp = new LocalTemporary (this.Type);
5795 Arguments args = new Arguments (1);
5796 args.Add (new Argument (my_source));
5798 Invocation.EmitCall (ec, IsBase, InstanceExpression, setter, args, loc, false, prepared);
5806 bool ResolveGetter (ResolveContext ec, ref bool must_do_cs1540_check)
5808 if (targs != null) {
5809 base.SetTypeArguments (ec, targs);
5813 if (getter != null) {
5814 if (!getter.Parameters.IsEmpty) {
5815 Error_PropertyNotFound (ec, getter, true);
5820 if (getter == null) {
5822 // The following condition happens if the PropertyExpr was
5823 // created, but is invalid (ie, the property is inaccessible),
5824 // and we did not want to embed the knowledge about this in
5825 // the caller routine. This only avoids double error reporting.
5830 if (InstanceExpression != EmptyExpression.Null) {
5831 ec.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5832 TypeManager.GetFullNameSignature (spec.MetaInfo));
5837 if (getter != null &&
5838 !IsAccessorAccessible (ec.CurrentType, getter, out must_do_cs1540_check)) {
5839 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter.MetaInfo) as PropertyBase.PropertyMethod;
5840 if (pm != null && pm.HasCustomAccessModifier) {
5841 ec.Report.SymbolRelatedToPreviousError (pm);
5842 ec.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5843 TypeManager.CSharpSignature (getter.MetaInfo));
5845 ec.Report.SymbolRelatedToPreviousError (getter.MetaInfo);
5846 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter.MetaInfo), ec.Report);
5855 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5862 /// Fully resolved expression that evaluates to an Event
5864 public class EventExpr : MemberExpr
5866 readonly EventSpec spec;
5868 public EventExpr (EventSpec spec, Location loc)
5874 public override string Name {
5880 public override bool IsInstance {
5882 return !spec.IsStatic;
5886 public override bool IsStatic {
5888 return spec.IsStatic;
5892 public override Type DeclaringType {
5894 return spec.DeclaringType;
5898 public void Error_AssignmentEventOnly (ResolveContext ec)
5900 ec.Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5901 GetSignatureForError ());
5904 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, Location loc,
5905 SimpleName original)
5908 // If the event is local to this class, we transform ourselves into a FieldExpr
5911 if (spec.DeclaringType == ec.CurrentType ||
5912 TypeManager.IsNestedChildOf(ec.CurrentType, spec.DeclaringType)) {
5914 // TODO: Breaks dynamic binder as currect context fields are imported and not compiled
5915 EventField mi = TypeManager.GetEventField (spec.MetaInfo).MemberDefinition as EventField;
5917 if (mi != null && mi.HasBackingField) {
5920 mi.CheckObsoleteness (loc);
5922 if ((mi.ModFlags & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0 && !ec.HasSet (ResolveContext.Options.CompoundAssignmentScope))
5923 Error_AssignmentEventOnly (ec);
5925 FieldExpr ml = new FieldExpr (mi.BackingField, loc);
5927 InstanceExpression = null;
5929 return ml.ResolveMemberAccess (ec, left, loc, original);
5933 if (left is This && !ec.HasSet (ResolveContext.Options.CompoundAssignmentScope))
5934 Error_AssignmentEventOnly (ec);
5936 return base.ResolveMemberAccess (ec, left, loc, original);
5939 bool InstanceResolve (ResolveContext ec, bool must_do_cs1540_check)
5942 InstanceExpression = null;
5946 if (InstanceExpression == null) {
5947 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5951 InstanceExpression = InstanceExpression.Resolve (ec);
5952 if (InstanceExpression == null)
5955 if (IsBase && spec.IsAbstract) {
5956 Error_CannotCallAbstractBase (ec, TypeManager.CSharpSignature(spec.MetaInfo));
5961 // This is using the same mechanism as the CS1540 check in PropertyExpr.
5962 // However, in the Event case, we reported a CS0122 instead.
5964 // TODO: Exact copy from PropertyExpr
5966 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
5967 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.CurrentType) &&
5968 !TypeManager.IsNestedChildOf (ec.CurrentType, InstanceExpression.Type) &&
5969 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.CurrentType)) {
5970 ec.Report.SymbolRelatedToPreviousError (spec.MetaInfo);
5971 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (spec.MetaInfo), ec.Report);
5978 public bool IsAccessibleFrom (Type invocation_type)
5981 return IsAccessorAccessible (invocation_type, spec.AccessorAdd, out dummy) &&
5982 IsAccessorAccessible (invocation_type, spec.AccessorRemove, out dummy);
5985 public override Expression CreateExpressionTree (ResolveContext ec)
5987 throw new NotSupportedException ("ET");
5990 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5992 // contexts where an LValue is valid have already devolved to FieldExprs
5993 Error_CannotAssign (ec);
5997 protected override Expression DoResolve (ResolveContext ec)
5999 eclass = ExprClass.EventAccess;
6001 bool must_do_cs1540_check;
6002 if (!(IsAccessorAccessible (ec.CurrentType, spec.AccessorAdd, out must_do_cs1540_check) &&
6003 IsAccessorAccessible (ec.CurrentType, spec.AccessorRemove, out must_do_cs1540_check))) {
6004 ec.Report.SymbolRelatedToPreviousError (spec.MetaInfo);
6005 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (spec.MetaInfo), ec.Report);
6009 if (!InstanceResolve (ec, must_do_cs1540_check))
6012 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6013 Error_CannotAssign (ec);
6017 if (!ec.IsObsolete) {
6018 var oa = spec.GetObsoleteAttribute ();
6020 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
6023 spec.MemberDefinition.SetIsUsed ();
6024 type = spec.EventType;
6029 public override void Emit (EmitContext ec)
6031 throw new NotSupportedException ();
6032 //Error_CannotAssign ();
6035 public void Error_CannotAssign (ResolveContext ec)
6037 ec.Report.Error (70, loc,
6038 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
6039 GetSignatureForError (), TypeManager.CSharpName (spec.DeclaringType));
6042 public override string GetSignatureForError ()
6044 return TypeManager.CSharpSignature (spec.MetaInfo);
6047 public void EmitAddOrRemove (EmitContext ec, bool is_add, Expression source)
6049 Arguments args = new Arguments (1);
6050 args.Add (new Argument (source));
6051 Invocation.EmitCall (ec, IsBase, InstanceExpression,
6052 is_add ? spec.AccessorAdd : spec.AccessorRemove,
6057 public class TemporaryVariable : VariableReference
6061 public TemporaryVariable (Type type, Location loc)
6067 public override Expression CreateExpressionTree (ResolveContext ec)
6069 throw new NotSupportedException ("ET");
6072 protected override Expression DoResolve (ResolveContext ec)
6074 eclass = ExprClass.Variable;
6076 TypeExpr te = new TypeExpression (type, loc);
6077 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
6078 if (!li.Resolve (ec))
6082 // Don't capture temporary variables except when using
6083 // iterator redirection
6085 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.IsIterator && ec.IsVariableCapturingRequired) {
6086 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
6087 storey.CaptureLocalVariable (ec, li);
6093 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6095 return Resolve (ec);
6098 public override void Emit (EmitContext ec)
6103 public void EmitAssign (EmitContext ec, Expression source)
6105 EmitAssign (ec, source, false, false);
6108 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6110 return li.HoistedVariant;
6113 public override bool IsFixed {
6114 get { return true; }
6117 public override bool IsRef {
6118 get { return false; }
6121 public override string Name {
6122 get { throw new NotImplementedException (); }
6125 public override void SetHasAddressTaken ()
6127 throw new NotImplementedException ();
6130 protected override ILocalVariable Variable {
6134 public override VariableInfo VariableInfo {
6135 get { throw new NotImplementedException (); }
6140 /// Handles `var' contextual keyword; var becomes a keyword only
6141 /// if no type called var exists in a variable scope
6143 class VarExpr : SimpleName
6145 // Used for error reporting only
6146 int initializers_count;
6148 public VarExpr (Location loc)
6151 initializers_count = 1;
6154 public int VariableInitializersCount {
6156 this.initializers_count = value;
6160 public bool InferType (ResolveContext ec, Expression right_side)
6163 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
6165 type = right_side.Type;
6166 if (type == TypeManager.null_type || type == TypeManager.void_type || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
6167 ec.Report.Error (815, loc, "An implicitly typed local variable declaration cannot be initialized with `{0}'",
6168 right_side.GetSignatureForError ());
6172 eclass = ExprClass.Variable;
6176 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
6178 if (RootContext.Version < LanguageVersion.V_3)
6179 base.Error_TypeOrNamespaceNotFound (ec);
6181 ec.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");
6184 public override TypeExpr ResolveAsContextualType (IMemberContext rc, bool silent)
6186 TypeExpr te = base.ResolveAsContextualType (rc, true);
6190 if (RootContext.Version < LanguageVersion.V_3)
6191 rc.Compiler.Report.FeatureIsNotAvailable (loc, "implicitly typed local variable");
6193 if (initializers_count == 1)
6196 if (initializers_count > 1) {
6197 rc.Compiler.Report.Error (819, loc, "An implicitly typed local variable declaration cannot include multiple declarators");
6198 initializers_count = 1;
6202 if (initializers_count == 0) {
6203 initializers_count = 1;
6204 rc.Compiler.Report.Error (818, loc, "An implicitly typed local variable declarator must include an initializer");