2 // ecore.cs: Core of the Expression representation for the intermediate tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@seznam.cz)
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
13 namespace Mono.CSharp {
15 using System.Collections;
16 using System.Diagnostics;
17 using System.Reflection;
18 using System.Reflection.Emit;
22 using SLE = System.Linq.Expressions;
26 /// The ExprClass class contains the is used to pass the
27 /// classification of an expression (value, variable, namespace,
28 /// type, method group, property access, event access, indexer access,
31 public enum ExprClass : byte {
47 /// This is used to tell Resolve in which types of expressions we're
51 public enum ResolveFlags {
52 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
55 // Returns a type expression.
58 // Returns a method group.
61 TypeParameter = 1 << 3,
63 // Mask of all the expression class flags.
64 MaskExprClass = VariableOrValue | Type | MethodGroup | TypeParameter,
66 // Disable control flow analysis while resolving the expression.
67 // This is used when resolving the instance expression of a field expression.
68 DisableFlowAnalysis = 1 << 10,
70 // Set if this is resolving the first part of a MemberAccess.
71 Intermediate = 1 << 11,
73 // Disable control flow analysis _of struct_ while resolving the expression.
74 // This is used when resolving the instance expression of a field expression.
75 DisableStructFlowAnalysis = 1 << 12,
80 // This is just as a hint to AddressOf of what will be done with the
83 public enum AddressOp {
90 /// This interface is implemented by variables
92 public interface IMemoryLocation {
94 /// The AddressOf method should generate code that loads
95 /// the address of the object and leaves it on the stack.
97 /// The `mode' argument is used to notify the expression
98 /// of whether this will be used to read from the address or
99 /// write to the address.
101 /// This is just a hint that can be used to provide good error
102 /// reporting, and should have no other side effects.
104 void AddressOf (EmitContext ec, AddressOp mode);
108 // An expressions resolved as a direct variable reference
110 public interface IVariableReference : IFixedExpression
112 bool IsHoisted { get; }
114 VariableInfo VariableInfo { get; }
116 void SetHasAddressTaken ();
120 // Implemented by an expression which could be or is always
123 public interface IFixedExpression
125 bool IsFixed { get; }
129 /// Base class for expressions
131 public abstract class Expression {
132 public ExprClass eclass;
134 protected Location loc;
138 set { type = value; }
141 public virtual Location Location {
145 // Not nice but we have broken hierarchy.
146 public virtual void CheckMarshalByRefAccess (ResolveContext ec)
150 public virtual bool GetAttributableValue (ResolveContext ec, Type value_type, out object value)
152 Attribute.Error_AttributeArgumentNotValid (ec, loc);
157 public virtual string GetSignatureForError ()
159 return TypeManager.CSharpName (type);
162 public static bool IsAccessorAccessible (Type invocation_type, MethodInfo mi, out bool must_do_cs1540_check)
164 MethodAttributes ma = mi.Attributes & MethodAttributes.MemberAccessMask;
166 must_do_cs1540_check = false; // by default we do not check for this
168 if (ma == MethodAttributes.Public)
172 // If only accessible to the current class or children
174 if (ma == MethodAttributes.Private)
175 return TypeManager.IsPrivateAccessible (invocation_type, mi.DeclaringType) ||
176 TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType);
178 if (TypeManager.IsThisOrFriendAssembly (invocation_type.Assembly, mi.DeclaringType.Assembly)) {
179 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamORAssem)
182 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamANDAssem)
186 // Family and FamANDAssem require that we derive.
187 // FamORAssem requires that we derive if in different assemblies.
188 if (!TypeManager.IsNestedFamilyAccessible (invocation_type, mi.DeclaringType))
191 if (!TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType))
192 must_do_cs1540_check = true;
197 public virtual bool IsNull {
204 /// Performs semantic analysis on the Expression
208 /// The Resolve method is invoked to perform the semantic analysis
211 /// The return value is an expression (it can be the
212 /// same expression in some cases) or a new
213 /// expression that better represents this node.
215 /// For example, optimizations of Unary (LiteralInt)
216 /// would return a new LiteralInt with a negated
219 /// If there is an error during semantic analysis,
220 /// then an error should be reported (using Report)
221 /// and a null value should be returned.
223 /// There are two side effects expected from calling
224 /// Resolve(): the the field variable "eclass" should
225 /// be set to any value of the enumeration
226 /// `ExprClass' and the type variable should be set
227 /// to a valid type (this is the type of the
230 public abstract Expression DoResolve (ResolveContext ec);
232 public virtual Expression DoResolveLValue (ResolveContext ec, Expression right_side)
238 // This is used if the expression should be resolved as a type or namespace name.
239 // the default implementation fails.
241 public virtual FullNamedExpression ResolveAsTypeStep (IMemberContext rc, bool silent)
244 ResolveContext ec = new ResolveContext (rc);
245 Expression e = Resolve (ec);
247 e.Error_UnexpectedKind (ec, ResolveFlags.Type, loc);
254 // C# 3.0 introduced contextual keywords (var) which behaves like a type if type with
255 // same name exists or as a keyword when no type was found
257 public virtual TypeExpr ResolveAsContextualType (IMemberContext rc, bool silent)
259 return ResolveAsTypeTerminal (rc, silent);
263 // This is used to resolve the expression as a type, a null
264 // value will be returned if the expression is not a type
267 public virtual TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
269 TypeExpr te = ResolveAsBaseTerminal (ec, silent);
273 if (!silent) { // && !(te is TypeParameterExpr)) {
274 ObsoleteAttribute obsolete_attr = AttributeTester.GetObsoleteAttribute (te.Type);
275 if (obsolete_attr != null && !ec.IsObsolete) {
276 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, ec.Compiler.Report);
280 GenericTypeExpr ct = te as GenericTypeExpr;
283 // TODO: Constrained type parameters check for parameters of generic method overrides is broken
284 // There are 2 solutions.
285 // 1, Skip this check completely when we are in override/explicit impl scope
286 // 2, Copy type parameters constraints from base implementation and pass (they have to be emitted anyway)
288 MemberCore gm = ec as GenericMethod;
291 if (gm != null && ((gm.ModFlags & Modifiers.OVERRIDE) != 0 || gm.MemberName.Left != null)) {
296 // TODO: silent flag is ignored
297 ct.CheckConstraints (ec);
303 public TypeExpr ResolveAsBaseTerminal (IMemberContext ec, bool silent)
305 int errors = ec.Compiler.Report.Errors;
307 FullNamedExpression fne = ResolveAsTypeStep (ec, silent);
312 TypeExpr te = fne as TypeExpr;
314 if (!silent && errors == ec.Compiler.Report.Errors)
315 fne.Error_UnexpectedKind (ec.Compiler.Report, null, "type", loc);
319 if (!te.CheckAccessLevel (ec)) {
320 ec.Compiler.Report.SymbolRelatedToPreviousError (te.Type);
321 ErrorIsInaccesible (loc, TypeManager.CSharpName (te.Type), ec.Compiler.Report);
329 public static void ErrorIsInaccesible (Location loc, string name, Report Report)
331 Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", name);
334 protected static void Error_CannotAccessProtected (ResolveContext ec, Location loc, MemberInfo m, Type qualifier, Type container)
336 ec.Report.Error (1540, loc, "Cannot access protected member `{0}' via a qualifier of type `{1}'."
337 + " The qualifier must be of type `{2}' or derived from it",
338 TypeManager.GetFullNameSignature (m),
339 TypeManager.CSharpName (qualifier),
340 TypeManager.CSharpName (container));
344 public static void Error_InvalidExpressionStatement (Report Report, Location loc)
346 Report.Error (201, loc, "Only assignment, call, increment, decrement, and new object " +
347 "expressions can be used as a statement");
350 public void Error_InvalidExpressionStatement (BlockContext ec)
352 Error_InvalidExpressionStatement (ec.Report, loc);
355 public static void Error_VoidInvalidInTheContext (Location loc, Report Report)
357 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
360 public virtual void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, Type target, bool expl)
362 Error_ValueCannotBeConvertedCore (ec, loc, target, expl);
365 protected void Error_ValueCannotBeConvertedCore (ResolveContext ec, Location loc, Type target, bool expl)
367 // The error was already reported as CS1660
368 if (type == InternalType.AnonymousMethod)
371 if (TypeManager.IsGenericParameter (Type) && TypeManager.IsGenericParameter (target) && type.Name == target.Name) {
372 string sig1 = type.DeclaringMethod == null ?
373 TypeManager.CSharpName (type.DeclaringType) :
374 TypeManager.CSharpSignature (type.DeclaringMethod);
375 string sig2 = target.DeclaringMethod == null ?
376 TypeManager.CSharpName (target.DeclaringType) :
377 TypeManager.CSharpSignature (target.DeclaringMethod);
378 ec.Report.ExtraInformation (loc,
380 "The generic parameter `{0}' of `{1}' cannot be converted to the generic parameter `{0}' of `{2}' (in the previous ",
381 Type.Name, sig1, sig2));
382 } else if (Type.FullName == target.FullName){
383 ec.Report.ExtraInformation (loc,
385 "The type `{0}' has two conflicting definitions, one comes from `{1}' and the other from `{2}' (in the previous ",
386 Type.FullName, Type.Assembly.FullName, target.Assembly.FullName));
390 ec.Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
391 TypeManager.CSharpName (type), TypeManager.CSharpName (target));
395 ec.Report.DisableReporting ();
396 bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null;
397 ec.Report.EnableReporting ();
400 ec.Report.Error (266, loc, "Cannot implicitly convert type `{0}' to `{1}'. " +
401 "An explicit conversion exists (are you missing a cast?)",
402 TypeManager.CSharpName (Type), TypeManager.CSharpName (target));
406 ec.Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
407 TypeManager.CSharpName (type),
408 TypeManager.CSharpName (target));
411 public virtual void Error_VariableIsUsedBeforeItIsDeclared (Report Report, string name)
413 Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", name);
416 public void Error_TypeArgumentsCannotBeUsed (Report report, Location loc)
418 // Better message for possible generic expressions
419 if (eclass == ExprClass.MethodGroup || eclass == ExprClass.Type) {
420 if (this is TypeExpr)
421 report.SymbolRelatedToPreviousError (type);
423 string name = eclass == ExprClass.Type ? ExprClassName : "method";
424 report.Error (308, loc, "The non-generic {0} `{1}' cannot be used with the type arguments",
425 name, GetSignatureForError ());
427 report.Error (307, loc, "The {0} `{1}' cannot be used with type arguments",
428 ExprClassName, GetSignatureForError ());
432 protected virtual void Error_TypeDoesNotContainDefinition (ResolveContext ec, Type type, string name)
434 Error_TypeDoesNotContainDefinition (ec, loc, type, name);
437 public static void Error_TypeDoesNotContainDefinition (ResolveContext ec, Location loc, Type type, string name)
439 ec.Report.SymbolRelatedToPreviousError (type);
440 ec.Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
441 TypeManager.CSharpName (type), name);
444 protected static void Error_ValueAssignment (ResolveContext ec, Location loc)
446 ec.Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
449 ResolveFlags ExprClassToResolveFlags
454 case ExprClass.Namespace:
455 return ResolveFlags.Type;
457 case ExprClass.MethodGroup:
458 return ResolveFlags.MethodGroup;
460 case ExprClass.TypeParameter:
461 return ResolveFlags.TypeParameter;
463 case ExprClass.Value:
464 case ExprClass.Variable:
465 case ExprClass.PropertyAccess:
466 case ExprClass.EventAccess:
467 case ExprClass.IndexerAccess:
468 return ResolveFlags.VariableOrValue;
471 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
477 /// Resolves an expression and performs semantic analysis on it.
481 /// Currently Resolve wraps DoResolve to perform sanity
482 /// checking and assertion checking on what we expect from Resolve.
484 public Expression Resolve (ResolveContext ec, ResolveFlags flags)
486 if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type)
487 return ResolveAsTypeStep (ec, false);
489 bool do_flow_analysis = ec.DoFlowAnalysis;
490 bool omit_struct_analysis = ec.OmitStructFlowAnalysis;
491 if ((flags & ResolveFlags.DisableFlowAnalysis) != 0)
492 do_flow_analysis = false;
493 if ((flags & ResolveFlags.DisableStructFlowAnalysis) != 0)
494 omit_struct_analysis = true;
497 using (ec.WithFlowAnalysis (do_flow_analysis, omit_struct_analysis)) {
498 if (this is SimpleName) {
499 bool intermediate = (flags & ResolveFlags.Intermediate) == ResolveFlags.Intermediate;
500 e = ((SimpleName) this).DoResolve (ec, intermediate);
509 if ((flags & e.ExprClassToResolveFlags) == 0) {
510 e.Error_UnexpectedKind (ec, flags, loc);
514 if (e.type == null && !(e is Namespace)) {
515 throw new Exception (
516 "Expression " + e.GetType () +
517 " did not set its type after Resolve\n" +
518 "called from: " + this.GetType ());
525 /// Resolves an expression and performs semantic analysis on it.
527 public Expression Resolve (ResolveContext ec)
529 Expression e = Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
531 if (e != null && e.eclass == ExprClass.MethodGroup && RootContext.Version == LanguageVersion.ISO_1) {
532 ((MethodGroupExpr) e).ReportUsageError (ec);
538 public Constant ResolveAsConstant (ResolveContext ec, MemberCore mc)
540 Expression e = Resolve (ec);
544 Constant c = e as Constant;
548 if (type != null && TypeManager.IsReferenceType (type))
549 Const.Error_ConstantCanBeInitializedWithNullOnly (type, loc, mc.GetSignatureForError (), ec.Report);
551 Const.Error_ExpressionMustBeConstant (loc, mc.GetSignatureForError (), ec.Report);
557 /// Resolves an expression for LValue assignment
561 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
562 /// checking and assertion checking on what we expect from Resolve
564 public Expression ResolveLValue (ResolveContext ec, Expression right_side)
566 int errors = ec.Report.Errors;
567 bool out_access = right_side == EmptyExpression.OutAccess.Instance;
569 Expression e = DoResolveLValue (ec, right_side);
571 if (e != null && out_access && !(e is IMemoryLocation)) {
572 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
573 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
575 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
576 // e.GetType () + " " + e.GetSignatureForError ());
581 if (errors == ec.Report.Errors) {
583 ec.Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
585 Error_ValueAssignment (ec, loc);
590 if (e.eclass == ExprClass.Invalid)
591 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
593 if ((e.type == null) && !(e is GenericTypeExpr))
594 throw new Exception ("Expression " + e + " did not set its type after Resolve");
600 /// Emits the code for the expression
604 /// The Emit method is invoked to generate the code
605 /// for the expression.
607 public abstract void Emit (EmitContext ec);
609 // Emit code to branch to @target if this expression is equivalent to @on_true.
610 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
611 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
612 // including the use of conditional branches. Note also that a branch MUST be emitted
613 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
616 ec.ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
619 // Emit this expression for its side effects, not for its value.
620 // The default implementation is to emit the value, and then throw it away.
621 // Subclasses can provide more efficient implementations, but those MUST be equivalent
622 public virtual void EmitSideEffect (EmitContext ec)
625 ec.ig.Emit (OpCodes.Pop);
629 /// Protected constructor. Only derivate types should
630 /// be able to be created
633 protected Expression ()
635 eclass = ExprClass.Invalid;
640 /// Returns a fully formed expression after a MemberLookup
643 public static Expression ExprClassFromMemberInfo (Type container_type, MemberInfo mi, Location loc)
646 return new EventExpr ((EventInfo) mi, loc);
647 else if (mi is FieldInfo) {
648 FieldInfo fi = (FieldInfo) mi;
649 if (fi.IsLiteral || (fi.IsInitOnly && fi.FieldType == TypeManager.decimal_type))
650 return new ConstantExpr (fi, loc);
651 return new FieldExpr (fi, loc);
652 } else if (mi is PropertyInfo)
653 return new PropertyExpr (container_type, (PropertyInfo) mi, loc);
654 else if (mi is Type) {
655 return new TypeExpression ((System.Type) mi, loc);
661 // TODO: [Obsolete ("Can be removed")]
662 protected static ArrayList almost_matched_members = new ArrayList (4);
665 // FIXME: Probably implement a cache for (t,name,current_access_set)?
667 // This code could use some optimizations, but we need to do some
668 // measurements. For example, we could use a delegate to `flag' when
669 // something can not any longer be a method-group (because it is something
673 // If the return value is an Array, then it is an array of
676 // If the return value is an MemberInfo, it is anything, but a Method
680 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
681 // the arguments here and have MemberLookup return only the methods that
682 // match the argument count/type, unlike we are doing now (we delay this
685 // This is so we can catch correctly attempts to invoke instance methods
686 // from a static body (scan for error 120 in ResolveSimpleName).
689 // FIXME: Potential optimization, have a static ArrayList
692 public static Expression MemberLookup (CompilerContext ctx, Type container_type, Type queried_type, string name,
693 MemberTypes mt, BindingFlags bf, Location loc)
695 return MemberLookup (ctx, container_type, null, queried_type, name, mt, bf, loc);
699 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
700 // `qualifier_type' or null to lookup members in the current class.
703 public static Expression MemberLookup (CompilerContext ctx, Type container_type,
704 Type qualifier_type, Type queried_type,
705 string name, MemberTypes mt,
706 BindingFlags bf, Location loc)
708 almost_matched_members.Clear ();
710 MemberInfo [] mi = TypeManager.MemberLookup (container_type, qualifier_type,
711 queried_type, mt, bf, name, almost_matched_members);
717 bool is_interface = qualifier_type != null && qualifier_type.IsInterface;
718 ArrayList methods = new ArrayList (2);
719 ArrayList non_methods = null;
721 foreach (MemberInfo m in mi) {
722 if (m is MethodBase) {
727 if (non_methods == null)
728 non_methods = new ArrayList (2);
730 bool is_candidate = true;
731 for (int i = 0; i < non_methods.Count; ++i) {
732 MemberInfo n_m = (MemberInfo) non_methods [i];
733 if (n_m.DeclaringType.IsInterface && TypeManager.ImplementsInterface (m.DeclaringType, n_m.DeclaringType)) {
734 non_methods.Remove (n_m);
736 } else if (m.DeclaringType.IsInterface && TypeManager.ImplementsInterface (n_m.DeclaringType, m.DeclaringType)) {
737 is_candidate = false;
747 if (methods.Count == 0 && non_methods != null && non_methods.Count > 1) {
748 ctx.Report.SymbolRelatedToPreviousError ((MemberInfo)non_methods [1]);
749 ctx.Report.SymbolRelatedToPreviousError ((MemberInfo)non_methods [0]);
750 ctx.Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
751 TypeManager.GetFullNameSignature ((MemberInfo)non_methods [1]),
752 TypeManager.GetFullNameSignature ((MemberInfo)non_methods [0]));
756 if (methods.Count == 0)
757 return ExprClassFromMemberInfo (container_type, (MemberInfo)non_methods [0], loc);
759 if (non_methods != null && non_methods.Count > 0) {
760 MethodBase method = (MethodBase) methods [0];
761 MemberInfo non_method = (MemberInfo) non_methods [0];
762 if (method.DeclaringType == non_method.DeclaringType) {
763 // Cannot happen with C# code, but is valid in IL
764 ctx.Report.SymbolRelatedToPreviousError (method);
765 ctx.Report.SymbolRelatedToPreviousError (non_method);
766 ctx.Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
767 TypeManager.GetFullNameSignature (non_method),
768 TypeManager.CSharpSignature (method));
773 ctx.Report.SymbolRelatedToPreviousError (method);
774 ctx.Report.SymbolRelatedToPreviousError (non_method);
775 ctx.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and non-method `{1}'. Using method `{0}'",
776 TypeManager.CSharpSignature (method), TypeManager.GetFullNameSignature (non_method));
780 return new MethodGroupExpr (methods, queried_type, loc);
783 if (mi [0] is MethodBase)
784 return new MethodGroupExpr (mi, queried_type, loc);
786 return ExprClassFromMemberInfo (container_type, mi [0], loc);
789 public const MemberTypes AllMemberTypes =
790 MemberTypes.Constructor |
794 MemberTypes.NestedType |
795 MemberTypes.Property;
797 public const BindingFlags AllBindingFlags =
798 BindingFlags.Public |
799 BindingFlags.Static |
800 BindingFlags.Instance;
802 public static Expression MemberLookup (CompilerContext ctx, Type container_type, Type queried_type,
803 string name, Location loc)
805 return MemberLookup (ctx, container_type, null, queried_type, name,
806 AllMemberTypes, AllBindingFlags, loc);
809 public static Expression MemberLookup (CompilerContext ctx, Type container_type, Type qualifier_type,
810 Type queried_type, string name, Location loc)
812 return MemberLookup (ctx, container_type, qualifier_type, queried_type,
813 name, AllMemberTypes, AllBindingFlags, loc);
816 public static MethodGroupExpr MethodLookup (CompilerContext ctx, Type container_type, Type queried_type,
817 string name, Location loc)
819 return (MethodGroupExpr)MemberLookup (ctx, container_type, null, queried_type, name,
820 MemberTypes.Method, AllBindingFlags, loc);
824 /// This is a wrapper for MemberLookup that is not used to "probe", but
825 /// to find a final definition. If the final definition is not found, we
826 /// look for private members and display a useful debugging message if we
829 protected Expression MemberLookupFinal (ResolveContext ec, Type qualifier_type,
830 Type queried_type, string name,
831 MemberTypes mt, BindingFlags bf,
836 int errors = ec.Report.Errors;
837 e = MemberLookup (ec.Compiler, ec.CurrentType, qualifier_type, queried_type, name, mt, bf, loc);
839 if (e != null || errors != ec.Report.Errors)
842 // No errors were reported by MemberLookup, but there was an error.
843 return Error_MemberLookupFailed (ec, ec.CurrentType, qualifier_type, queried_type,
847 protected virtual Expression Error_MemberLookupFailed (ResolveContext ec, Type container_type, Type qualifier_type,
848 Type queried_type, string name, string class_name,
849 MemberTypes mt, BindingFlags bf)
851 MemberInfo[] lookup = null;
852 if (queried_type == null) {
853 class_name = "global::";
855 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
856 mt, (bf & ~BindingFlags.Public) | BindingFlags.NonPublic,
859 if (lookup != null) {
860 Expression e = Error_MemberLookupFailed (ec, queried_type, lookup);
863 // FIXME: This is still very wrong, it should be done inside
864 // OverloadResolve to do correct arguments matching.
865 // Requires MemberLookup accessiblity check removal
867 if (e == null || (mt & (MemberTypes.Method | MemberTypes.Constructor)) == 0) {
868 MemberInfo mi = lookup[0];
869 ec.Report.SymbolRelatedToPreviousError (mi);
870 if (qualifier_type != null && container_type != null && qualifier_type != container_type &&
871 TypeManager.IsNestedFamilyAccessible (container_type, mi.DeclaringType)) {
872 // Although a derived class can access protected members of
873 // its base class it cannot do so through an instance of the
874 // base class (CS1540). If the qualifier_type is a base of the
875 // ec.CurrentType and the lookup succeeds with the latter one,
876 // then we are in this situation.
877 Error_CannotAccessProtected (ec, loc, mi, qualifier_type, container_type);
879 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (mi), ec.Report);
886 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
887 AllMemberTypes, AllBindingFlags | BindingFlags.NonPublic,
891 if (lookup == null) {
892 if (class_name != null) {
893 ec.Report.Error (103, loc, "The name `{0}' does not exist in the current context",
896 Error_TypeDoesNotContainDefinition (ec, queried_type, name);
901 if (TypeManager.MemberLookup (queried_type, null, queried_type,
902 AllMemberTypes, AllBindingFlags |
903 BindingFlags.NonPublic, name, null) == null) {
904 if ((lookup.Length == 1) && (lookup [0] is Type)) {
905 Type t = (Type) lookup [0];
907 ec.Report.Error (305, loc,
908 "Using the generic type `{0}' " +
909 "requires {1} type arguments",
910 TypeManager.CSharpName (t),
911 TypeManager.GetNumberOfTypeArguments (t).ToString ());
916 return Error_MemberLookupFailed (ec, queried_type, lookup);
919 protected virtual Expression Error_MemberLookupFailed (ResolveContext ec, Type type, MemberInfo[] members)
921 for (int i = 0; i < members.Length; ++i) {
922 if (!(members [i] is MethodBase))
926 // By default propagate the closest candidates upwards
927 return new MethodGroupExpr (members, type, loc, true);
930 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
932 throw new NotImplementedException ();
935 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
937 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
941 /// Returns an expression that can be used to invoke operator true
942 /// on the expression if it exists.
944 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
946 return GetOperatorTrueOrFalse (ec, e, true, loc);
950 /// Returns an expression that can be used to invoke operator false
951 /// on the expression if it exists.
953 static public Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
955 return GetOperatorTrueOrFalse (ec, e, false, loc);
958 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
960 MethodGroupExpr operator_group;
961 string mname = Operator.GetMetadataName (is_true ? Operator.OpType.True : Operator.OpType.False);
962 operator_group = MethodLookup (ec.Compiler, ec.CurrentType, e.Type, mname, loc) as MethodGroupExpr;
963 if (operator_group == null)
966 Arguments arguments = new Arguments (1);
967 arguments.Add (new Argument (e));
968 operator_group = operator_group.OverloadResolve (
969 ec, ref arguments, false, loc);
971 if (operator_group == null)
974 return new UserOperatorCall (operator_group, arguments, null, loc);
977 public virtual string ExprClassName
981 case ExprClass.Invalid:
983 case ExprClass.Value:
985 case ExprClass.Variable:
987 case ExprClass.Namespace:
991 case ExprClass.MethodGroup:
992 return "method group";
993 case ExprClass.PropertyAccess:
994 return "property access";
995 case ExprClass.EventAccess:
996 return "event access";
997 case ExprClass.IndexerAccess:
998 return "indexer access";
999 case ExprClass.Nothing:
1001 case ExprClass.TypeParameter:
1002 return "type parameter";
1004 throw new Exception ("Should not happen");
1009 /// Reports that we were expecting `expr' to be of class `expected'
1011 public void Error_UnexpectedKind (Report r, MemberCore mc, string expected, Location loc)
1013 Error_UnexpectedKind (r, mc, expected, ExprClassName, loc);
1016 public void Error_UnexpectedKind (Report r, MemberCore mc, string expected, string was, Location loc)
1020 name = mc.GetSignatureForError ();
1022 name = GetSignatureForError ();
1024 r.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
1025 name, was, expected);
1028 public void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
1030 string [] valid = new string [4];
1033 if ((flags & ResolveFlags.VariableOrValue) != 0) {
1034 valid [count++] = "variable";
1035 valid [count++] = "value";
1038 if ((flags & ResolveFlags.Type) != 0)
1039 valid [count++] = "type";
1041 if ((flags & ResolveFlags.MethodGroup) != 0)
1042 valid [count++] = "method group";
1045 valid [count++] = "unknown";
1047 StringBuilder sb = new StringBuilder (valid [0]);
1048 for (int i = 1; i < count - 1; i++) {
1050 sb.Append (valid [i]);
1053 sb.Append ("' or `");
1054 sb.Append (valid [count - 1]);
1057 ec.Report.Error (119, loc,
1058 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1061 public static void UnsafeError (ResolveContext ec, Location loc)
1063 UnsafeError (ec.Report, loc);
1066 public static void UnsafeError (Report Report, Location loc)
1068 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1072 // Load the object from the pointer.
1074 public static void LoadFromPtr (ILGenerator ig, Type t)
1076 if (t == TypeManager.int32_type)
1077 ig.Emit (OpCodes.Ldind_I4);
1078 else if (t == TypeManager.uint32_type)
1079 ig.Emit (OpCodes.Ldind_U4);
1080 else if (t == TypeManager.short_type)
1081 ig.Emit (OpCodes.Ldind_I2);
1082 else if (t == TypeManager.ushort_type)
1083 ig.Emit (OpCodes.Ldind_U2);
1084 else if (t == TypeManager.char_type)
1085 ig.Emit (OpCodes.Ldind_U2);
1086 else if (t == TypeManager.byte_type)
1087 ig.Emit (OpCodes.Ldind_U1);
1088 else if (t == TypeManager.sbyte_type)
1089 ig.Emit (OpCodes.Ldind_I1);
1090 else if (t == TypeManager.uint64_type)
1091 ig.Emit (OpCodes.Ldind_I8);
1092 else if (t == TypeManager.int64_type)
1093 ig.Emit (OpCodes.Ldind_I8);
1094 else if (t == TypeManager.float_type)
1095 ig.Emit (OpCodes.Ldind_R4);
1096 else if (t == TypeManager.double_type)
1097 ig.Emit (OpCodes.Ldind_R8);
1098 else if (t == TypeManager.bool_type)
1099 ig.Emit (OpCodes.Ldind_I1);
1100 else if (t == TypeManager.intptr_type)
1101 ig.Emit (OpCodes.Ldind_I);
1102 else if (TypeManager.IsEnumType (t)) {
1103 if (t == TypeManager.enum_type)
1104 ig.Emit (OpCodes.Ldind_Ref);
1106 LoadFromPtr (ig, TypeManager.GetEnumUnderlyingType (t));
1107 } else if (TypeManager.IsStruct (t) || TypeManager.IsGenericParameter (t))
1108 ig.Emit (OpCodes.Ldobj, t);
1109 else if (t.IsPointer)
1110 ig.Emit (OpCodes.Ldind_I);
1112 ig.Emit (OpCodes.Ldind_Ref);
1116 // The stack contains the pointer and the value of type `type'
1118 public static void StoreFromPtr (ILGenerator ig, Type type)
1120 if (TypeManager.IsEnumType (type))
1121 type = TypeManager.GetEnumUnderlyingType (type);
1122 if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
1123 ig.Emit (OpCodes.Stind_I4);
1124 else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
1125 ig.Emit (OpCodes.Stind_I8);
1126 else if (type == TypeManager.char_type || type == TypeManager.short_type ||
1127 type == TypeManager.ushort_type)
1128 ig.Emit (OpCodes.Stind_I2);
1129 else if (type == TypeManager.float_type)
1130 ig.Emit (OpCodes.Stind_R4);
1131 else if (type == TypeManager.double_type)
1132 ig.Emit (OpCodes.Stind_R8);
1133 else if (type == TypeManager.byte_type || type == TypeManager.sbyte_type ||
1134 type == TypeManager.bool_type)
1135 ig.Emit (OpCodes.Stind_I1);
1136 else if (type == TypeManager.intptr_type)
1137 ig.Emit (OpCodes.Stind_I);
1138 else if (TypeManager.IsStruct (type) || TypeManager.IsGenericParameter (type))
1139 ig.Emit (OpCodes.Stobj, type);
1141 ig.Emit (OpCodes.Stind_Ref);
1145 // Returns the size of type `t' if known, otherwise, 0
1147 public static int GetTypeSize (Type t)
1149 t = TypeManager.TypeToCoreType (t);
1150 if (t == TypeManager.int32_type ||
1151 t == TypeManager.uint32_type ||
1152 t == TypeManager.float_type)
1154 else if (t == TypeManager.int64_type ||
1155 t == TypeManager.uint64_type ||
1156 t == TypeManager.double_type)
1158 else if (t == TypeManager.byte_type ||
1159 t == TypeManager.sbyte_type ||
1160 t == TypeManager.bool_type)
1162 else if (t == TypeManager.short_type ||
1163 t == TypeManager.char_type ||
1164 t == TypeManager.ushort_type)
1166 else if (t == TypeManager.decimal_type)
1172 protected void Error_CannotCallAbstractBase (ResolveContext ec, string name)
1174 ec.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
1177 protected void Error_CannotModifyIntermediateExpressionValue (ResolveContext ec)
1179 ec.Report.SymbolRelatedToPreviousError (type);
1180 if (ec.CurrentInitializerVariable != null) {
1181 ec.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
1182 TypeManager.CSharpName (type), GetSignatureForError ());
1184 ec.Report.Error (1612, loc, "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
1185 GetSignatureForError ());
1190 // Converts `source' to an int, uint, long or ulong.
1192 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source)
1194 if (TypeManager.IsDynamicType (source.type)) {
1195 Arguments args = new Arguments (1);
1196 args.Add (new Argument (source));
1197 return new DynamicConversion (TypeManager.int32_type, CSharpBinderFlags.ConvertArrayIndex, args, loc).Resolve (ec);
1200 Expression converted;
1202 using (ec.Set (ResolveContext.Options.CheckedScope)) {
1203 converted = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, source.loc);
1204 if (converted == null)
1205 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, source.loc);
1206 if (converted == null)
1207 converted = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, source.loc);
1208 if (converted == null)
1209 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, source.loc);
1211 if (converted == null) {
1212 source.Error_ValueCannotBeConverted (ec, source.loc, TypeManager.int32_type, false);
1218 // Only positive constants are allowed at compile time
1220 Constant c = converted as Constant;
1221 if (c != null && c.IsNegative)
1222 Error_NegativeArrayIndex (ec, source.loc);
1224 // No conversion needed to array index
1225 if (converted.Type == TypeManager.int32_type)
1228 return new ArrayIndexCast (converted).Resolve (ec);
1232 // Derived classes implement this method by cloning the fields that
1233 // could become altered during the Resolve stage
1235 // Only expressions that are created for the parser need to implement
1238 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1240 throw new NotImplementedException (
1242 "CloneTo not implemented for expression {0}", this.GetType ()));
1246 // Clones an expression created by the parser.
1248 // We only support expressions created by the parser so far, not
1249 // expressions that have been resolved (many more classes would need
1250 // to implement CloneTo).
1252 // This infrastructure is here merely for Lambda expressions which
1253 // compile the same code using different type values for the same
1254 // arguments to find the correct overload
1256 public Expression Clone (CloneContext clonectx)
1258 Expression cloned = (Expression) MemberwiseClone ();
1259 CloneTo (clonectx, cloned);
1265 // Implementation of expression to expression tree conversion
1267 public abstract Expression CreateExpressionTree (ResolveContext ec);
1269 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
1271 return CreateExpressionFactoryCall (ec, name, null, args, loc);
1274 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
1276 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
1279 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
1281 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
1284 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
1286 TypeExpr texpr = TypeManager.expression_type_expr;
1287 if (texpr == null) {
1288 Type t = TypeManager.CoreLookupType (ec.Compiler, "System.Linq.Expressions", "Expression", Kind.Class, true);
1292 TypeManager.expression_type_expr = texpr = new TypeExpression (t, Location.Null);
1300 // Implemented by all expressions which support conversion from
1301 // compiler expression to invokable runtime expression. Used by
1302 // dynamic C# binder.
1304 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
1306 throw new NotImplementedException ("MakeExpression for " + GetType ());
1310 public virtual void MutateHoistedGenericType (AnonymousMethodStorey storey)
1312 // TODO: It should probably be type = storey.MutateType (type);
1317 /// This is just a base class for expressions that can
1318 /// appear on statements (invocations, object creation,
1319 /// assignments, post/pre increment and decrement). The idea
1320 /// being that they would support an extra Emition interface that
1321 /// does not leave a result on the stack.
1323 public abstract class ExpressionStatement : Expression {
1325 public virtual ExpressionStatement ResolveStatement (BlockContext ec)
1327 Expression e = Resolve (ec);
1331 ExpressionStatement es = e as ExpressionStatement;
1333 Error_InvalidExpressionStatement (ec);
1339 /// Requests the expression to be emitted in a `statement'
1340 /// context. This means that no new value is left on the
1341 /// stack after invoking this method (constrasted with
1342 /// Emit that will always leave a value on the stack).
1344 public abstract void EmitStatement (EmitContext ec);
1346 public override void EmitSideEffect (EmitContext ec)
1353 /// This kind of cast is used to encapsulate the child
1354 /// whose type is child.Type into an expression that is
1355 /// reported to return "return_type". This is used to encapsulate
1356 /// expressions which have compatible types, but need to be dealt
1357 /// at higher levels with.
1359 /// For example, a "byte" expression could be encapsulated in one
1360 /// of these as an "unsigned int". The type for the expression
1361 /// would be "unsigned int".
1364 public abstract class TypeCast : Expression
1366 protected readonly Expression child;
1368 protected TypeCast (Expression child, Type return_type)
1370 eclass = child.eclass;
1371 loc = child.Location;
1376 public override Expression CreateExpressionTree (ResolveContext ec)
1378 Arguments args = new Arguments (2);
1379 args.Add (new Argument (child.CreateExpressionTree (ec)));
1380 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1382 if (type.IsPointer || child.Type.IsPointer)
1383 Error_PointerInsideExpressionTree (ec);
1385 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1388 public override Expression DoResolve (ResolveContext ec)
1390 // This should never be invoked, we are born in fully
1391 // initialized state.
1396 public override void Emit (EmitContext ec)
1401 public override bool GetAttributableValue (ResolveContext ec, Type value_type, out object value)
1403 return child.GetAttributableValue (ec, value_type, out value);
1407 public override SLE.Expression MakeExpression (BuilderContext ctx)
1409 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1410 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type) :
1411 SLE.Expression.Convert (child.MakeExpression (ctx), type);
1415 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1417 type = storey.MutateType (type);
1418 child.MutateHoistedGenericType (storey);
1421 protected override void CloneTo (CloneContext clonectx, Expression t)
1426 public override bool IsNull {
1427 get { return child.IsNull; }
1431 public class EmptyCast : TypeCast {
1432 EmptyCast (Expression child, Type target_type)
1433 : base (child, target_type)
1437 public static Expression Create (Expression child, Type type)
1439 Constant c = child as Constant;
1441 return new EmptyConstantCast (c, type);
1443 EmptyCast e = child as EmptyCast;
1445 return new EmptyCast (e.child, type);
1447 return new EmptyCast (child, type);
1450 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1452 child.EmitBranchable (ec, label, on_true);
1455 public override void EmitSideEffect (EmitContext ec)
1457 child.EmitSideEffect (ec);
1462 // Used for predefined class library user casts (no obsolete check, etc.)
1464 public class OperatorCast : TypeCast {
1465 MethodInfo conversion_operator;
1467 public OperatorCast (Expression child, Type target_type)
1468 : this (child, target_type, false)
1472 public OperatorCast (Expression child, Type target_type, bool find_explicit)
1473 : base (child, target_type)
1475 conversion_operator = GetConversionOperator (find_explicit);
1476 if (conversion_operator == null)
1477 throw new InternalErrorException ("Outer conversion routine is out of sync");
1480 // Returns the implicit operator that converts from
1481 // 'child.Type' to our target type (type)
1482 MethodInfo GetConversionOperator (bool find_explicit)
1484 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1488 mi = TypeManager.MemberLookup (child.Type, child.Type, child.Type, MemberTypes.Method,
1489 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1492 mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1493 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1496 foreach (MethodInfo oper in mi) {
1497 AParametersCollection pd = TypeManager.GetParameterData (oper);
1499 if (pd.Types [0] == child.Type && TypeManager.TypeToCoreType (oper.ReturnType) == type)
1506 public override void Emit (EmitContext ec)
1509 ec.ig.Emit (OpCodes.Call, conversion_operator);
1514 /// This is a numeric cast to a Decimal
1516 public class CastToDecimal : OperatorCast {
1517 public CastToDecimal (Expression child)
1518 : this (child, false)
1522 public CastToDecimal (Expression child, bool find_explicit)
1523 : base (child, TypeManager.decimal_type, find_explicit)
1529 /// This is an explicit numeric cast from a Decimal
1531 public class CastFromDecimal : TypeCast
1533 static IDictionary operators;
1535 public CastFromDecimal (Expression child, Type return_type)
1536 : base (child, return_type)
1538 if (child.Type != TypeManager.decimal_type)
1539 throw new InternalErrorException (
1540 "The expected type is Decimal, instead it is " + child.Type.FullName);
1543 // Returns the explicit operator that converts from an
1544 // express of type System.Decimal to 'type'.
1545 public Expression Resolve ()
1547 if (operators == null) {
1548 MemberInfo[] all_oper = TypeManager.MemberLookup (TypeManager.decimal_type,
1549 TypeManager.decimal_type, TypeManager.decimal_type, MemberTypes.Method,
1550 BindingFlags.Static | BindingFlags.Public, "op_Explicit", null);
1552 operators = new System.Collections.Specialized.HybridDictionary ();
1553 foreach (MethodInfo oper in all_oper) {
1554 AParametersCollection pd = TypeManager.GetParameterData (oper);
1555 if (pd.Types [0] == TypeManager.decimal_type)
1556 operators.Add (TypeManager.TypeToCoreType (oper.ReturnType), oper);
1560 return operators.Contains (type) ? this : null;
1563 public override void Emit (EmitContext ec)
1565 ILGenerator ig = ec.ig;
1568 ig.Emit (OpCodes.Call, (MethodInfo)operators [type]);
1574 // Constant specialization of EmptyCast.
1575 // We need to special case this since an empty cast of
1576 // a constant is still a constant.
1578 public class EmptyConstantCast : Constant
1580 public readonly Constant child;
1582 public EmptyConstantCast(Constant child, Type type)
1583 : base (child.Location)
1585 eclass = child.eclass;
1590 public override string AsString ()
1592 return child.AsString ();
1595 public override object GetValue ()
1597 return child.GetValue ();
1600 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
1602 // FIXME: check that 'type' can be converted to 'target_type' first
1603 return child.ConvertExplicitly (in_checked_context, target_type);
1606 public override Expression CreateExpressionTree (ResolveContext ec)
1608 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1609 child.CreateExpressionTree (ec),
1610 new TypeOf (new TypeExpression (type, loc), loc));
1613 Error_PointerInsideExpressionTree (ec);
1615 return CreateExpressionFactoryCall (ec, "Convert", args);
1618 public override Constant Increment ()
1620 return child.Increment ();
1623 public override bool IsDefaultValue {
1624 get { return child.IsDefaultValue; }
1627 public override bool IsNegative {
1628 get { return child.IsNegative; }
1631 public override bool IsNull {
1632 get { return child.IsNull; }
1635 public override bool IsZeroInteger {
1636 get { return child.IsZeroInteger; }
1639 public override void Emit (EmitContext ec)
1644 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1646 child.EmitBranchable (ec, label, on_true);
1648 // Only to make verifier happy
1649 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1650 ec.ig.Emit (OpCodes.Unbox_Any, type);
1653 public override void EmitSideEffect (EmitContext ec)
1655 child.EmitSideEffect (ec);
1658 public override Constant ConvertImplicitly (Type target_type)
1660 // FIXME: Do we need to check user conversions?
1661 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1663 return child.ConvertImplicitly (target_type);
1666 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1668 child.MutateHoistedGenericType (storey);
1674 /// This class is used to wrap literals which belong inside Enums
1676 public class EnumConstant : Constant {
1677 public Constant Child;
1679 public EnumConstant (Constant child, Type enum_type):
1680 base (child.Location)
1682 eclass = child.eclass;
1687 protected EnumConstant ()
1688 : base (Location.Null)
1692 public override Expression DoResolve (ResolveContext ec)
1694 // This should never be invoked, we are born in fully
1695 // initialized state.
1700 public override void Emit (EmitContext ec)
1705 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1707 Child.EmitBranchable (ec, label, on_true);
1710 public override void EmitSideEffect (EmitContext ec)
1712 Child.EmitSideEffect (ec);
1715 public override bool GetAttributableValue (ResolveContext ec, Type value_type, out object value)
1717 value = GetTypedValue ();
1721 public override string GetSignatureForError()
1723 return TypeManager.CSharpName (Type);
1726 public override object GetValue ()
1728 return Child.GetValue ();
1731 public override object GetTypedValue ()
1733 // FIXME: runtime is not ready to work with just emited enums
1734 if (!RootContext.StdLib) {
1735 return Child.GetValue ();
1739 // Small workaround for big problem
1740 // System.Enum.ToObject cannot be called on dynamic types
1741 // EnumBuilder has to be used, but we cannot use EnumBuilder
1742 // because it does not properly support generics
1744 // This works only sometimes
1746 if (TypeManager.IsBeingCompiled (type))
1747 return Child.GetValue ();
1750 return System.Enum.ToObject (type, Child.GetValue ());
1753 public override string AsString ()
1755 return Child.AsString ();
1758 public override Constant Increment()
1760 return new EnumConstant (Child.Increment (), type);
1763 public override bool IsDefaultValue {
1765 return Child.IsDefaultValue;
1769 public override bool IsZeroInteger {
1770 get { return Child.IsZeroInteger; }
1773 public override bool IsNegative {
1775 return Child.IsNegative;
1779 public override Constant ConvertExplicitly(bool in_checked_context, Type target_type)
1781 if (Child.Type == target_type)
1784 return Child.ConvertExplicitly (in_checked_context, target_type);
1787 public override Constant ConvertImplicitly (Type type)
1789 Type this_type = TypeManager.DropGenericTypeArguments (Type);
1790 type = TypeManager.DropGenericTypeArguments (type);
1792 if (this_type == type) {
1793 // This is workaround of mono bug. It can be removed when the latest corlib spreads enough
1794 if (TypeManager.IsEnumType (type.UnderlyingSystemType))
1797 Type child_type = TypeManager.DropGenericTypeArguments (Child.Type);
1798 if (type.UnderlyingSystemType != child_type)
1799 Child = Child.ConvertImplicitly (type.UnderlyingSystemType);
1803 if (!Convert.ImplicitStandardConversionExists (this, type)){
1807 return Child.ConvertImplicitly(type);
1813 /// This kind of cast is used to encapsulate Value Types in objects.
1815 /// The effect of it is to box the value type emitted by the previous
1818 public class BoxedCast : TypeCast {
1820 public BoxedCast (Expression expr, Type target_type)
1821 : base (expr, target_type)
1823 eclass = ExprClass.Value;
1826 public override Expression DoResolve (ResolveContext ec)
1828 // This should never be invoked, we are born in fully
1829 // initialized state.
1834 public override void Emit (EmitContext ec)
1838 ec.ig.Emit (OpCodes.Box, child.Type);
1841 public override void EmitSideEffect (EmitContext ec)
1843 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1844 // so, we need to emit the box+pop instructions in most cases
1845 if (TypeManager.IsStruct (child.Type) &&
1846 (type == TypeManager.object_type || type == TypeManager.value_type))
1847 child.EmitSideEffect (ec);
1849 base.EmitSideEffect (ec);
1853 public class UnboxCast : TypeCast {
1854 public UnboxCast (Expression expr, Type return_type)
1855 : base (expr, return_type)
1859 public override Expression DoResolve (ResolveContext ec)
1861 // This should never be invoked, we are born in fully
1862 // initialized state.
1867 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
1869 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
1870 ec.Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
1871 return base.DoResolveLValue (ec, right_side);
1874 public override void Emit (EmitContext ec)
1878 ILGenerator ig = ec.ig;
1879 ig.Emit (OpCodes.Unbox_Any, type);
1882 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1884 type = storey.MutateType (type);
1885 base.MutateHoistedGenericType (storey);
1890 /// This is used to perform explicit numeric conversions.
1892 /// Explicit numeric conversions might trigger exceptions in a checked
1893 /// context, so they should generate the conv.ovf opcodes instead of
1896 public class ConvCast : TypeCast {
1897 public enum Mode : byte {
1898 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1900 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1901 U2_I1, U2_U1, U2_I2, U2_CH,
1902 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1903 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1904 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1905 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1906 CH_I1, CH_U1, CH_I2,
1907 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1908 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1914 public ConvCast (Expression child, Type return_type, Mode m)
1915 : base (child, return_type)
1920 public override Expression DoResolve (ResolveContext ec)
1922 // This should never be invoked, we are born in fully
1923 // initialized state.
1928 public override string ToString ()
1930 return String.Format ("ConvCast ({0}, {1})", mode, child);
1933 public override void Emit (EmitContext ec)
1935 ILGenerator ig = ec.ig;
1939 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1941 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1942 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1943 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1944 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1945 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1947 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1948 case Mode.U1_CH: /* nothing */ break;
1950 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1951 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1952 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1953 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1954 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1955 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1957 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1958 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1959 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1960 case Mode.U2_CH: /* nothing */ break;
1962 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1963 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1964 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1965 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1966 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1967 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1968 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1970 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1971 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1972 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1973 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1974 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1975 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1977 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1978 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1979 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1980 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1981 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1982 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1983 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1984 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1985 case Mode.I8_I: ig.Emit (OpCodes.Conv_Ovf_U); break;
1987 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1988 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1989 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1990 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1991 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1992 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1993 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1994 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1995 case Mode.U8_I: ig.Emit (OpCodes.Conv_Ovf_U_Un); break;
1997 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1998 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1999 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
2001 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
2002 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
2003 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
2004 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
2005 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
2006 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
2007 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
2008 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
2009 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
2011 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
2012 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
2013 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
2014 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
2015 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
2016 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
2017 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
2018 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
2019 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
2020 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
2022 case Mode.I_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
2026 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
2027 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
2028 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
2029 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
2030 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
2032 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
2033 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
2035 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
2036 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
2037 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
2038 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
2039 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
2040 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
2042 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
2043 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
2044 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
2045 case Mode.U2_CH: /* nothing */ break;
2047 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
2048 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
2049 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
2050 case Mode.I4_U4: /* nothing */ break;
2051 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
2052 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
2053 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
2055 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
2056 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
2057 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
2058 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
2059 case Mode.U4_I4: /* nothing */ break;
2060 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
2062 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
2063 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
2064 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
2065 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
2066 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
2067 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
2068 case Mode.I8_U8: /* nothing */ break;
2069 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
2070 case Mode.I8_I: ig.Emit (OpCodes.Conv_U); break;
2072 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
2073 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
2074 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
2075 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
2076 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
2077 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
2078 case Mode.U8_I8: /* nothing */ break;
2079 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
2080 case Mode.U8_I: ig.Emit (OpCodes.Conv_U); break;
2082 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
2083 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
2084 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
2086 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
2087 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
2088 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
2089 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
2090 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
2091 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
2092 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
2093 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
2094 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
2096 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
2097 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
2098 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
2099 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
2100 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
2101 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
2102 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
2103 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
2104 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
2105 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
2107 case Mode.I_I8: ig.Emit (OpCodes.Conv_U8); break;
2113 public class OpcodeCast : TypeCast {
2116 public OpcodeCast (Expression child, Type return_type, OpCode op)
2117 : base (child, return_type)
2122 public override Expression DoResolve (ResolveContext ec)
2124 // This should never be invoked, we are born in fully
2125 // initialized state.
2130 public override void Emit (EmitContext ec)
2136 public Type UnderlyingType {
2137 get { return child.Type; }
2142 /// This kind of cast is used to encapsulate a child and cast it
2143 /// to the class requested
2145 public sealed class ClassCast : TypeCast {
2146 readonly bool forced;
2148 public ClassCast (Expression child, Type return_type)
2149 : base (child, return_type)
2153 public ClassCast (Expression child, Type return_type, bool forced)
2154 : base (child, return_type)
2156 this.forced = forced;
2159 public override void Emit (EmitContext ec)
2163 bool gen = TypeManager.IsGenericParameter (child.Type);
2165 ec.ig.Emit (OpCodes.Box, child.Type);
2167 if (type.IsGenericParameter) {
2168 ec.ig.Emit (OpCodes.Unbox_Any, type);
2175 ec.ig.Emit (OpCodes.Castclass, type);
2180 // Created during resolving pahse when an expression is wrapped or constantified
2181 // and original expression can be used later (e.g. for expression trees)
2183 public class ReducedExpression : Expression
2185 sealed class ReducedConstantExpression : EmptyConstantCast
2187 readonly Expression orig_expr;
2189 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2190 : base (expr, expr.Type)
2192 this.orig_expr = orig_expr;
2195 public override Constant ConvertImplicitly (Type target_type)
2197 Constant c = base.ConvertImplicitly (target_type);
2199 c = new ReducedConstantExpression (c, orig_expr);
2203 public override Expression CreateExpressionTree (ResolveContext ec)
2205 return orig_expr.CreateExpressionTree (ec);
2208 public override bool GetAttributableValue (ResolveContext ec, Type value_type, out object value)
2211 // Even if resolved result is a constant original expression was not
2212 // and attribute accepts constants only
2214 Attribute.Error_AttributeArgumentNotValid (ec, orig_expr.Location);
2219 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
2221 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
2223 c = new ReducedConstantExpression (c, orig_expr);
2228 sealed class ReducedExpressionStatement : ExpressionStatement
2230 readonly Expression orig_expr;
2231 readonly ExpressionStatement stm;
2233 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
2235 this.orig_expr = orig;
2237 this.loc = orig.Location;
2240 public override Expression CreateExpressionTree (ResolveContext ec)
2242 return orig_expr.CreateExpressionTree (ec);
2245 public override Expression DoResolve (ResolveContext ec)
2247 eclass = stm.eclass;
2252 public override void Emit (EmitContext ec)
2257 public override void EmitStatement (EmitContext ec)
2259 stm.EmitStatement (ec);
2262 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2264 stm.MutateHoistedGenericType (storey);
2268 readonly Expression expr, orig_expr;
2270 private ReducedExpression (Expression expr, Expression orig_expr)
2273 this.orig_expr = orig_expr;
2274 this.loc = orig_expr.Location;
2277 public static Constant Create (Constant expr, Expression original_expr)
2279 return new ReducedConstantExpression (expr, original_expr);
2282 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
2284 return new ReducedExpressionStatement (s, orig);
2287 public static Expression Create (Expression expr, Expression original_expr)
2289 Constant c = expr as Constant;
2291 return Create (c, original_expr);
2293 ExpressionStatement s = expr as ExpressionStatement;
2295 return Create (s, original_expr);
2297 return new ReducedExpression (expr, original_expr);
2300 public override Expression CreateExpressionTree (ResolveContext ec)
2302 return orig_expr.CreateExpressionTree (ec);
2305 public override Expression DoResolve (ResolveContext ec)
2307 eclass = expr.eclass;
2312 public override void Emit (EmitContext ec)
2317 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2319 expr.EmitBranchable (ec, target, on_true);
2323 public override SLE.Expression MakeExpression (BuilderContext ctx)
2325 return orig_expr.MakeExpression (ctx);
2329 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2331 expr.MutateHoistedGenericType (storey);
2336 // Standard composite pattern
2338 public abstract class CompositeExpression : Expression
2342 protected CompositeExpression (Expression expr)
2345 this.loc = expr.Location;
2348 public override Expression CreateExpressionTree (ResolveContext ec)
2350 return expr.CreateExpressionTree (ec);
2353 public Expression Child {
2354 get { return expr; }
2357 public override Expression DoResolve (ResolveContext ec)
2359 expr = expr.Resolve (ec);
2362 eclass = expr.eclass;
2368 public override void Emit (EmitContext ec)
2373 public override bool IsNull {
2374 get { return expr.IsNull; }
2379 // Base of expressions used only to narrow resolve flow
2381 public abstract class ShimExpression : Expression
2383 protected Expression expr;
2385 protected ShimExpression (Expression expr)
2390 protected override void CloneTo (CloneContext clonectx, Expression t)
2395 ShimExpression target = (ShimExpression) t;
2396 target.expr = expr.Clone (clonectx);
2399 public override Expression CreateExpressionTree (ResolveContext ec)
2401 throw new NotSupportedException ("ET");
2404 public override void Emit (EmitContext ec)
2406 throw new InternalErrorException ("Missing Resolve call");
2409 public Expression Expr {
2410 get { return expr; }
2413 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2415 throw new InternalErrorException ("Missing Resolve call");
2420 // Unresolved type name expressions
2422 public abstract class ATypeNameExpression : FullNamedExpression
2425 protected TypeArguments targs;
2427 protected ATypeNameExpression (string name, Location l)
2433 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2440 public bool HasTypeArguments {
2442 return targs != null;
2446 public override bool Equals (object obj)
2448 ATypeNameExpression atne = obj as ATypeNameExpression;
2449 return atne != null && atne.Name == Name &&
2450 (targs == null || targs.Equals (atne.targs));
2453 public override int GetHashCode ()
2455 return Name.GetHashCode ();
2458 public override string GetSignatureForError ()
2460 if (targs != null) {
2461 return TypeManager.RemoveGenericArity (Name) + "<" +
2462 targs.GetSignatureForError () + ">";
2468 public string Name {
2477 public TypeArguments TypeArguments {
2485 /// SimpleName expressions are formed of a single word and only happen at the beginning
2486 /// of a dotted-name.
2488 public class SimpleName : ATypeNameExpression {
2491 public SimpleName (string name, Location l)
2496 public SimpleName (string name, TypeArguments args, Location l)
2497 : base (name, args, l)
2501 public SimpleName (string name, TypeParameter[] type_params, Location l)
2504 targs = new TypeArguments ();
2505 foreach (TypeParameter type_param in type_params)
2506 targs.Add (new TypeParameterExpr (type_param, l));
2509 public static string RemoveGenericArity (string name)
2512 StringBuilder sb = null;
2514 int pos = name.IndexOf ('`', start);
2519 sb.Append (name.Substring (start));
2524 sb = new StringBuilder ();
2525 sb.Append (name.Substring (start, pos-start));
2528 while ((pos < name.Length) && Char.IsNumber (name [pos]))
2532 } while (start < name.Length);
2534 return sb.ToString ();
2537 public SimpleName GetMethodGroup ()
2539 return new SimpleName (RemoveGenericArity (Name), targs, loc);
2542 public static void Error_ObjectRefRequired (ResolveContext ec, Location l, string name)
2544 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope))
2545 ec.Report.Error (236, l,
2546 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2549 ec.Report.Error (120, l,
2550 "An object reference is required to access non-static member `{0}'",
2554 public bool IdenticalNameAndTypeName (IMemberContext mc, Expression resolved_to, Location loc)
2556 return resolved_to != null && resolved_to.Type != null &&
2557 resolved_to.Type.Name == Name &&
2558 (mc.LookupNamespaceOrType (Name, loc, /* ignore_cs0104 = */ true) != null);
2561 public override Expression DoResolve (ResolveContext ec)
2563 return SimpleNameResolve (ec, null, false);
2566 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2568 return SimpleNameResolve (ec, right_side, false);
2572 public Expression DoResolve (ResolveContext ec, bool intermediate)
2574 return SimpleNameResolve (ec, null, intermediate);
2577 static bool IsNestedChild (Type t, Type parent)
2579 while (parent != null) {
2580 if (TypeManager.IsNestedChildOf (t, TypeManager.DropGenericTypeArguments (parent)))
2583 parent = parent.BaseType;
2589 FullNamedExpression ResolveNested (Type t)
2591 if (!TypeManager.IsGenericTypeDefinition (t) && !TypeManager.IsGenericType (t))
2595 while (ds != null && !IsNestedChild (t, ds))
2596 ds = ds.DeclaringType;
2601 Type[] gen_params = TypeManager.GetTypeArguments (t);
2603 int arg_count = targs != null ? targs.Count : 0;
2605 for (; (ds != null) && TypeManager.IsGenericType (ds); ds = ds.DeclaringType) {
2606 Type[] gargs = TypeManager.GetTypeArguments (ds);
2607 if (arg_count + gargs.Length == gen_params.Length) {
2608 TypeArguments new_args = new TypeArguments ();
2609 foreach (Type param in gargs)
2610 new_args.Add (new TypeExpression (param, loc));
2613 new_args.Add (targs);
2615 return new GenericTypeExpr (t, new_args, loc);
2622 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2624 int errors = ec.Compiler.Report.Errors;
2625 FullNamedExpression fne = ec.LookupNamespaceOrType (Name, loc, /*ignore_cs0104=*/ false);
2628 if (fne.Type == null)
2631 FullNamedExpression nested = ResolveNested (fne.Type);
2633 return nested.ResolveAsTypeStep (ec, false);
2635 if (targs != null) {
2636 if (TypeManager.IsGenericType (fne.Type)) {
2637 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2638 return ct.ResolveAsTypeStep (ec, false);
2641 fne.Error_TypeArgumentsCannotBeUsed (ec.Compiler.Report, loc);
2647 if (!HasTypeArguments && Name == "dynamic" && RootContext.Version > LanguageVersion.V_3)
2648 return new DynamicTypeExpr (loc);
2650 if (silent || errors != ec.Compiler.Report.Errors)
2653 Error_TypeOrNamespaceNotFound (ec);
2657 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ec)
2659 if (ec.CurrentType != null) {
2660 if (ec.CurrentTypeDefinition != null) {
2661 MemberCore mc = ec.CurrentTypeDefinition.GetDefinition (Name);
2663 Error_UnexpectedKind (ec.Compiler.Report, mc, "type", GetMemberType (mc), loc);
2668 string ns = ec.CurrentType.Namespace;
2669 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2670 foreach (Assembly a in GlobalRootNamespace.Instance.Assemblies) {
2671 Type type = a.GetType (fullname);
2673 ec.Compiler.Report.SymbolRelatedToPreviousError (type);
2674 Expression.ErrorIsInaccesible (loc, TypeManager.CSharpName (type), ec.Compiler.Report);
2679 if (ec.CurrentTypeDefinition != null) {
2680 Type t = ec.CurrentTypeDefinition.LookupAnyGeneric (Name);
2682 Namespace.Error_InvalidNumberOfTypeArguments (t, loc);
2688 if (targs != null) {
2689 FullNamedExpression retval = ec.LookupNamespaceOrType (SimpleName.RemoveGenericArity (Name), loc, true);
2690 if (retval != null) {
2691 retval.Error_TypeArgumentsCannotBeUsed (ec.Compiler.Report, loc);
2696 NamespaceEntry.Error_NamespaceNotFound (loc, Name, ec.Compiler.Report);
2699 // TODO: I am still not convinced about this. If someone else will need it
2700 // implement this as virtual property in MemberCore hierarchy
2701 public static string GetMemberType (MemberCore mc)
2707 if (mc is FieldBase)
2709 if (mc is MethodCore)
2711 if (mc is EnumMember)
2719 Expression SimpleNameResolve (ResolveContext ec, Expression right_side, bool intermediate)
2725 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2731 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2738 /// 7.5.2: Simple Names.
2740 /// Local Variables and Parameters are handled at
2741 /// parse time, so they never occur as SimpleNames.
2743 /// The `intermediate' flag is used by MemberAccess only
2744 /// and it is used to inform us that it is ok for us to
2745 /// avoid the static check, because MemberAccess might end
2746 /// up resolving the Name as a Type name and the access as
2747 /// a static type access.
2749 /// ie: Type Type; .... { Type.GetType (""); }
2751 /// Type is both an instance variable and a Type; Type.GetType
2752 /// is the static method not an instance method of type.
2754 Expression DoSimpleNameResolve (ResolveContext ec, Expression right_side, bool intermediate)
2756 Expression e = null;
2759 // Stage 1: Performed by the parser (binding to locals or parameters).
2761 Block current_block = ec.CurrentBlock;
2762 if (current_block != null){
2763 LocalInfo vi = current_block.GetLocalInfo (Name);
2765 e = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2767 if (right_side != null) {
2768 e = e.ResolveLValue (ec, right_side);
2770 ResolveFlags rf = ResolveFlags.VariableOrValue;
2772 rf |= ResolveFlags.DisableFlowAnalysis;
2774 e = e.Resolve (ec, rf);
2777 if (targs != null && e != null)
2778 e.Error_TypeArgumentsCannotBeUsed (ec.Report, loc);
2783 e = current_block.Toplevel.GetParameterReference (Name, loc);
2785 if (right_side != null)
2786 e = e.ResolveLValue (ec, right_side);
2790 if (targs != null && e != null)
2791 e.Error_TypeArgumentsCannotBeUsed (ec.Report, loc);
2798 // Stage 2: Lookup members
2801 Type almost_matched_type = null;
2802 ArrayList almost_matched = null;
2803 for (Type lookup_ds = ec.CurrentType; lookup_ds != null; lookup_ds = lookup_ds.DeclaringType) {
2804 e = MemberLookup (ec.Compiler, ec.CurrentType, lookup_ds, Name, loc);
2806 PropertyExpr pe = e as PropertyExpr;
2808 AParametersCollection param = TypeManager.GetParameterData (pe.PropertyInfo);
2810 // since TypeManager.MemberLookup doesn't know if we're doing a lvalue access or not,
2811 // it doesn't know which accessor to check permissions against
2812 if (param.IsEmpty && pe.IsAccessibleFrom (ec.CurrentType, right_side != null))
2814 } else if (e is EventExpr) {
2815 if (((EventExpr) e).IsAccessibleFrom (ec.CurrentType))
2817 } else if (targs != null && e is TypeExpression) {
2818 e = new GenericTypeExpr (e.Type, targs, loc).ResolveAsTypeStep (ec, false);
2826 if (almost_matched == null && almost_matched_members.Count > 0) {
2827 almost_matched_type = lookup_ds;
2828 almost_matched = (ArrayList) almost_matched_members.Clone ();
2833 if (almost_matched == null && almost_matched_members.Count > 0) {
2834 almost_matched_type = ec.CurrentType;
2835 almost_matched = (ArrayList) almost_matched_members.Clone ();
2837 e = ResolveAsTypeStep (ec, true);
2841 if (current_block != null) {
2842 IKnownVariable ikv = current_block.Explicit.GetKnownVariable (Name);
2844 LocalInfo li = ikv as LocalInfo;
2845 // Supress CS0219 warning
2849 Error_VariableIsUsedBeforeItIsDeclared (ec.Report, Name);
2854 if (RootContext.EvalMode){
2855 FieldInfo fi = Evaluator.LookupField (Name);
2857 return new FieldExpr (fi, loc).Resolve (ec);
2860 if (almost_matched != null)
2861 almost_matched_members = almost_matched;
2862 if (almost_matched_type == null)
2863 almost_matched_type = ec.CurrentType;
2865 string type_name = ec.MemberContext.CurrentType == null ? null : ec.MemberContext.CurrentType.Name;
2866 return Error_MemberLookupFailed (ec, ec.CurrentType, null, almost_matched_type, Name,
2867 type_name, AllMemberTypes, AllBindingFlags);
2870 if (e is MemberExpr) {
2871 MemberExpr me = (MemberExpr) e;
2874 if (me.IsInstance) {
2875 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope)) {
2877 // Note that an MemberExpr can be both IsInstance and IsStatic.
2878 // An unresolved MethodGroupExpr can contain both kinds of methods
2879 // and each predicate is true if the MethodGroupExpr contains
2880 // at least one of that kind of method.
2884 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2885 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2890 // Pass the buck to MemberAccess and Invocation.
2892 left = EmptyExpression.Null;
2894 left = ec.GetThis (loc);
2897 left = new TypeExpression (ec.CurrentType, loc);
2900 me = me.ResolveMemberAccess (ec, left, loc, null);
2904 if (targs != null) {
2905 if (!targs.Resolve (ec))
2908 me.SetTypeArguments (ec, targs);
2911 if (!me.IsStatic && (me.InstanceExpression != null && me.InstanceExpression != EmptyExpression.Null) &&
2912 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2913 me.InstanceExpression.Type != me.DeclaringType &&
2914 !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2915 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2916 ec.Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2917 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2921 return (right_side != null)
2922 ? me.DoResolveLValue (ec, right_side)
2923 : me.DoResolve (ec);
2931 /// Represents a namespace or a type. The name of the class was inspired by
2932 /// section 10.8.1 (Fully Qualified Names).
2934 public abstract class FullNamedExpression : Expression
2936 protected override void CloneTo (CloneContext clonectx, Expression target)
2938 // Do nothing, most unresolved type expressions cannot be
2939 // resolved to different type
2942 public override Expression CreateExpressionTree (ResolveContext ec)
2944 throw new NotSupportedException ("ET");
2947 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2949 throw new NotSupportedException ();
2952 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2957 public override void Emit (EmitContext ec)
2959 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2960 GetSignatureForError ());
2965 /// Expression that evaluates to a type
2967 public abstract class TypeExpr : FullNamedExpression {
2968 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2970 TypeExpr t = DoResolveAsTypeStep (ec);
2974 eclass = ExprClass.Type;
2978 override public Expression DoResolve (ResolveContext ec)
2980 return ResolveAsTypeTerminal (ec, false);
2983 public virtual bool CheckAccessLevel (IMemberContext mc)
2985 return mc.CurrentTypeDefinition.CheckAccessLevel (Type);
2988 public virtual bool IsClass {
2989 get { return Type.IsClass; }
2992 public virtual bool IsValueType {
2993 get { return TypeManager.IsStruct (Type); }
2996 public virtual bool IsInterface {
2997 get { return Type.IsInterface; }
3000 public virtual bool IsSealed {
3001 get { return Type.IsSealed; }
3004 public virtual bool CanInheritFrom ()
3006 if (Type == TypeManager.enum_type ||
3007 (Type == TypeManager.value_type && RootContext.StdLib) ||
3008 Type == TypeManager.multicast_delegate_type ||
3009 Type == TypeManager.delegate_type ||
3010 Type == TypeManager.array_type)
3016 protected abstract TypeExpr DoResolveAsTypeStep (IMemberContext ec);
3018 public override bool Equals (object obj)
3020 TypeExpr tobj = obj as TypeExpr;
3024 return Type == tobj.Type;
3027 public override int GetHashCode ()
3029 return Type.GetHashCode ();
3032 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3034 type = storey.MutateType (type);
3039 /// Fully resolved Expression that already evaluated to a type
3041 public class TypeExpression : TypeExpr {
3042 public TypeExpression (Type t, Location l)
3045 eclass = ExprClass.Type;
3049 protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec)
3054 public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
3061 // Used to create types from a fully qualified name. These are just used
3062 // by the parser to setup the core types.
3064 public sealed class TypeLookupExpression : TypeExpr {
3065 readonly string ns_name;
3066 readonly string name;
3068 public TypeLookupExpression (string ns, string name)
3072 eclass = ExprClass.Type;
3075 public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
3078 // It's null only during mscorlib bootstrap when DefineType
3079 // nees to resolve base type of same type
3081 // For instance struct Char : IComparable<char>
3083 // TODO: it could be removed when Resolve starts to use
3084 // DeclSpace instead of Type
3087 Namespace ns = GlobalRootNamespace.Instance.GetNamespace (ns_name, false);
3088 FullNamedExpression fne = ns.Lookup (ec.Compiler, name, loc);
3096 protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec)
3101 public override string GetSignatureForError ()
3104 return TypeManager.CSharpName (ns_name + "." + name, null);
3106 return base.GetSignatureForError ();
3111 /// This class denotes an expression which evaluates to a member
3112 /// of a struct or a class.
3114 public abstract class MemberExpr : Expression
3116 protected bool is_base;
3119 /// The name of this member.
3121 public abstract string Name {
3126 // When base.member is used
3128 public bool IsBase {
3129 get { return is_base; }
3130 set { is_base = value; }
3134 /// Whether this is an instance member.
3136 public abstract bool IsInstance {
3141 /// Whether this is a static member.
3143 public abstract bool IsStatic {
3148 /// The type which declares this member.
3150 public abstract Type DeclaringType {
3155 /// The instance expression associated with this member, if it's a
3156 /// non-static member.
3158 public Expression InstanceExpression;
3160 public static void error176 (ResolveContext ec, Location loc, string name)
3162 ec.Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
3163 "with an instance reference, qualify it with a type name instead", name);
3166 public static void Error_BaseAccessInExpressionTree (ResolveContext ec, Location loc)
3168 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
3171 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3173 if (InstanceExpression != null)
3174 InstanceExpression.MutateHoistedGenericType (storey);
3177 // TODO: possible optimalization
3178 // Cache resolved constant result in FieldBuilder <-> expression map
3179 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, Location loc,
3180 SimpleName original)
3184 // original == null || original.Resolve (...) ==> left
3187 if (left is TypeExpr) {
3188 left = left.ResolveAsBaseTerminal (ec, false);
3192 // TODO: Same problem as in class.cs, TypeTerminal does not
3193 // always do all necessary checks
3194 ObsoleteAttribute oa = AttributeTester.GetObsoleteAttribute (left.Type);
3195 if (oa != null && !ec.IsObsolete) {
3196 AttributeTester.Report_ObsoleteMessage (oa, left.GetSignatureForError (), loc, ec.Report);
3199 GenericTypeExpr ct = left as GenericTypeExpr;
3200 if (ct != null && !ct.CheckConstraints (ec))
3205 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3213 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3216 return ResolveExtensionMemberAccess (ec, left);
3219 InstanceExpression = left;
3223 protected virtual MemberExpr ResolveExtensionMemberAccess (ResolveContext ec, Expression left)
3225 error176 (ec, loc, GetSignatureForError ());
3229 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3234 if (InstanceExpression == EmptyExpression.Null) {
3235 // FIXME: This should not be here at all
3236 SimpleName.Error_ObjectRefRequired (new ResolveContext (ec.MemberContext), loc, GetSignatureForError ());
3240 if (TypeManager.IsValueType (InstanceExpression.Type)) {
3241 if (InstanceExpression is IMemoryLocation) {
3242 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
3244 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
3245 InstanceExpression.Emit (ec);
3247 t.AddressOf (ec, AddressOp.Store);
3250 InstanceExpression.Emit (ec);
3252 if (prepare_for_load)
3253 ec.ig.Emit (OpCodes.Dup);
3256 public virtual void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3258 // TODO: need to get correct member type
3259 ec.Report.Error (307, loc, "The property `{0}' cannot be used with type arguments",
3260 GetSignatureForError ());
3265 /// Represents group of extension methods
3267 public class ExtensionMethodGroupExpr : MethodGroupExpr
3269 readonly NamespaceEntry namespace_entry;
3270 public Expression ExtensionExpression;
3271 Argument extension_argument;
3273 public ExtensionMethodGroupExpr (ArrayList list, NamespaceEntry n, Type extensionType, Location l)
3274 : base (list, extensionType, l)
3276 this.namespace_entry = n;
3279 public override bool IsStatic {
3280 get { return true; }
3283 public bool IsTopLevel {
3284 get { return namespace_entry == null; }
3287 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3289 extension_argument.Expr.MutateHoistedGenericType (storey);
3290 base.MutateHoistedGenericType (storey);
3293 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, bool may_fail, Location loc)
3295 if (arguments == null)
3296 arguments = new Arguments (1);
3298 arguments.Insert (0, new Argument (ExtensionExpression));
3299 MethodGroupExpr mg = ResolveOverloadExtensions (ec, ref arguments, namespace_entry, loc);
3301 // Store resolved argument and restore original arguments
3303 ((ExtensionMethodGroupExpr)mg).extension_argument = arguments [0];
3305 arguments.RemoveAt (0); // Clean-up modified arguments for error reporting
3310 MethodGroupExpr ResolveOverloadExtensions (ResolveContext ec, ref Arguments arguments, NamespaceEntry ns, Location loc)
3312 // Use normal resolve rules
3313 MethodGroupExpr mg = base.OverloadResolve (ec, ref arguments, ns != null, loc);
3321 ExtensionMethodGroupExpr e = ns.LookupExtensionMethod (type, Name, loc);
3323 return base.OverloadResolve (ec, ref arguments, false, loc);
3325 e.ExtensionExpression = ExtensionExpression;
3326 e.SetTypeArguments (ec, type_arguments);
3327 return e.ResolveOverloadExtensions (ec, ref arguments, e.namespace_entry, loc);
3332 /// MethodGroupExpr represents a group of method candidates which
3333 /// can be resolved to the best method overload
3335 public class MethodGroupExpr : MemberExpr
3337 public interface IErrorHandler
3339 bool AmbiguousCall (ResolveContext ec, MethodBase ambiguous);
3340 bool NoExactMatch (ResolveContext ec, MethodBase method);
3343 public IErrorHandler CustomErrorHandler;
3344 public MethodBase [] Methods;
3345 MethodBase best_candidate;
3346 // TODO: make private
3347 public TypeArguments type_arguments;
3348 bool identical_type_name;
3349 bool has_inaccessible_candidates_only;
3353 public MethodGroupExpr (MemberInfo [] mi, Type type, Location l)
3356 Methods = new MethodBase [mi.Length];
3357 mi.CopyTo (Methods, 0);
3360 public MethodGroupExpr (MemberInfo[] mi, Type type, Location l, bool inacessibleCandidatesOnly)
3361 : this (mi, type, l)
3363 has_inaccessible_candidates_only = inacessibleCandidatesOnly;
3366 public MethodGroupExpr (ArrayList list, Type type, Location l)
3370 Methods = (MethodBase[])list.ToArray (typeof (MethodBase));
3372 foreach (MemberInfo m in list){
3373 if (!(m is MethodBase)){
3374 Console.WriteLine ("Name " + m.Name);
3375 Console.WriteLine ("Found a: " + m.GetType ().FullName);
3384 protected MethodGroupExpr (Type type, Location loc)
3387 eclass = ExprClass.MethodGroup;
3388 this.type = InternalType.MethodGroup;
3389 queried_type = type;
3392 public override Type DeclaringType {
3394 return queried_type;
3398 public Type DelegateType {
3400 delegate_type = value;
3404 public bool IdenticalTypeName {
3406 return identical_type_name;
3410 public override string GetSignatureForError ()
3412 if (best_candidate != null)
3413 return TypeManager.CSharpSignature (best_candidate);
3415 return TypeManager.CSharpSignature (Methods [0]);
3418 public override string Name {
3420 return Methods [0].Name;
3424 public override bool IsInstance {
3426 if (best_candidate != null)
3427 return !best_candidate.IsStatic;
3429 foreach (MethodBase mb in Methods)
3437 public override bool IsStatic {
3439 if (best_candidate != null)
3440 return best_candidate.IsStatic;
3442 foreach (MethodBase mb in Methods)
3450 public static explicit operator ConstructorInfo (MethodGroupExpr mg)
3452 return (ConstructorInfo)mg.best_candidate;
3455 public static explicit operator MethodInfo (MethodGroupExpr mg)
3457 return (MethodInfo)mg.best_candidate;
3461 // 7.4.3.3 Better conversion from expression
3462 // Returns : 1 if a->p is better,
3463 // 2 if a->q is better,
3464 // 0 if neither is better
3466 static int BetterExpressionConversion (ResolveContext ec, Argument a, Type p, Type q)
3468 Type argument_type = TypeManager.TypeToCoreType (a.Type);
3469 if (argument_type == InternalType.AnonymousMethod && RootContext.Version > LanguageVersion.ISO_2) {
3471 // Uwrap delegate from Expression<T>
3473 if (TypeManager.DropGenericTypeArguments (p) == TypeManager.expression_type) {
3474 p = TypeManager.GetTypeArguments (p) [0];
3476 if (TypeManager.DropGenericTypeArguments (q) == TypeManager.expression_type) {
3477 q = TypeManager.GetTypeArguments (q) [0];
3480 p = Delegate.GetInvokeMethod (ec.Compiler, null, p).ReturnType;
3481 q = Delegate.GetInvokeMethod (ec.Compiler, null, q).ReturnType;
3482 if (p == TypeManager.void_type && q != TypeManager.void_type)
3484 if (q == TypeManager.void_type && p != TypeManager.void_type)
3487 if (argument_type == p)
3490 if (argument_type == q)
3494 return BetterTypeConversion (ec, p, q);
3498 // 7.4.3.4 Better conversion from type
3500 public static int BetterTypeConversion (ResolveContext ec, Type p, Type q)
3502 if (p == null || q == null)
3503 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3505 if (p == TypeManager.int32_type) {
3506 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3508 } else if (p == TypeManager.int64_type) {
3509 if (q == TypeManager.uint64_type)
3511 } else if (p == TypeManager.sbyte_type) {
3512 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3513 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3515 } else if (p == TypeManager.short_type) {
3516 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3517 q == TypeManager.uint64_type)
3521 if (q == TypeManager.int32_type) {
3522 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3524 } if (q == TypeManager.int64_type) {
3525 if (p == TypeManager.uint64_type)
3527 } else if (q == TypeManager.sbyte_type) {
3528 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3529 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3531 } if (q == TypeManager.short_type) {
3532 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3533 p == TypeManager.uint64_type)
3537 // TODO: this is expensive
3538 Expression p_tmp = new EmptyExpression (p);
3539 Expression q_tmp = new EmptyExpression (q);
3541 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3542 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3544 if (p_to_q && !q_to_p)
3547 if (q_to_p && !p_to_q)
3554 /// Determines "Better function" between candidate
3555 /// and the current best match
3558 /// Returns a boolean indicating :
3559 /// false if candidate ain't better
3560 /// true if candidate is better than the current best match
3562 static bool BetterFunction (ResolveContext ec, Arguments args, int argument_count,
3563 MethodBase candidate, bool candidate_params,
3564 MethodBase best, bool best_params)
3566 AParametersCollection candidate_pd = TypeManager.GetParameterData (candidate);
3567 AParametersCollection best_pd = TypeManager.GetParameterData (best);
3569 bool better_at_least_one = false;
3571 for (int j = 0, c_idx = 0, b_idx = 0; j < argument_count; ++j, ++c_idx, ++b_idx)
3573 Argument a = args [j];
3575 // Provided default argument value is never better
3576 if (a.IsDefaultArgument && candidate_params == best_params)
3579 Type ct = candidate_pd.Types [c_idx];
3580 Type bt = best_pd.Types [b_idx];
3582 if (candidate_params && candidate_pd.FixedParameters [c_idx].ModFlags == Parameter.Modifier.PARAMS)
3584 ct = TypeManager.GetElementType (ct);
3588 if (best_params && best_pd.FixedParameters [b_idx].ModFlags == Parameter.Modifier.PARAMS)
3590 bt = TypeManager.GetElementType (bt);
3598 int result = BetterExpressionConversion (ec, a, ct, bt);
3600 // for each argument, the conversion to 'ct' should be no worse than
3601 // the conversion to 'bt'.
3605 // for at least one argument, the conversion to 'ct' should be better than
3606 // the conversion to 'bt'.
3608 better_at_least_one = true;
3611 if (better_at_least_one)
3615 // This handles the case
3617 // Add (float f1, float f2, float f3);
3618 // Add (params decimal [] foo);
3620 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3621 // first candidate would've chosen as better.
3627 // The two methods have equal parameter types. Now apply tie-breaking rules
3629 if (TypeManager.IsGenericMethod (best)) {
3630 if (!TypeManager.IsGenericMethod (candidate))
3632 } else if (TypeManager.IsGenericMethod (candidate)) {
3637 // This handles the following cases:
3639 // Trim () is better than Trim (params char[] chars)
3640 // Concat (string s1, string s2, string s3) is better than
3641 // Concat (string s1, params string [] srest)
3642 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3644 if (!candidate_params && best_params)
3646 if (candidate_params && !best_params)
3649 int candidate_param_count = candidate_pd.Count;
3650 int best_param_count = best_pd.Count;
3652 if (candidate_param_count != best_param_count)
3653 // can only happen if (candidate_params && best_params)
3654 return candidate_param_count > best_param_count && best_pd.HasParams;
3657 // now, both methods have the same number of parameters, and the parameters have the same types
3658 // Pick the "more specific" signature
3661 MethodBase orig_candidate = TypeManager.DropGenericMethodArguments (candidate);
3662 MethodBase orig_best = TypeManager.DropGenericMethodArguments (best);
3664 AParametersCollection orig_candidate_pd = TypeManager.GetParameterData (orig_candidate);
3665 AParametersCollection orig_best_pd = TypeManager.GetParameterData (orig_best);
3667 bool specific_at_least_once = false;
3668 for (int j = 0; j < candidate_param_count; ++j)
3670 Type ct = orig_candidate_pd.Types [j];
3671 Type bt = orig_best_pd.Types [j];
3674 Type specific = MoreSpecific (ct, bt);
3678 specific_at_least_once = true;
3681 if (specific_at_least_once)
3684 // FIXME: handle lifted operators
3690 protected override MemberExpr ResolveExtensionMemberAccess (ResolveContext ec, Expression left)
3693 return base.ResolveExtensionMemberAccess (ec, left);
3696 // When left side is an expression and at least one candidate method is
3697 // static, it can be extension method
3699 InstanceExpression = left;
3703 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, Location loc,
3704 SimpleName original)
3706 if (!(left is TypeExpr) &&
3707 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3708 identical_type_name = true;
3710 return base.ResolveMemberAccess (ec, left, loc, original);
3713 public override Expression CreateExpressionTree (ResolveContext ec)
3715 if (best_candidate == null) {
3716 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3720 IMethodData md = TypeManager.GetMethod (best_candidate);
3721 if (md != null && md.IsExcluded ())
3722 ec.Report.Error (765, loc,
3723 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3725 return new TypeOfMethod (best_candidate, loc);
3728 override public Expression DoResolve (ResolveContext ec)
3730 if (InstanceExpression != null) {
3731 InstanceExpression = InstanceExpression.DoResolve (ec);
3732 if (InstanceExpression == null)
3739 public void ReportUsageError (ResolveContext ec)
3741 ec.Report.Error (654, loc, "Method `" + DeclaringType + "." +
3742 Name + "()' is referenced without parentheses");
3745 override public void Emit (EmitContext ec)
3747 throw new NotSupportedException ();
3748 // ReportUsageError ();
3751 public void EmitCall (EmitContext ec, Arguments arguments)
3753 Invocation.EmitCall (ec, IsBase, InstanceExpression, best_candidate, arguments, loc);
3756 void Error_AmbiguousCall (ResolveContext ec, MethodBase ambiguous)
3758 if (CustomErrorHandler != null && CustomErrorHandler.AmbiguousCall (ec, ambiguous))
3761 ec.Report.SymbolRelatedToPreviousError (best_candidate);
3762 ec.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
3763 TypeManager.CSharpSignature (ambiguous), TypeManager.CSharpSignature (best_candidate));
3766 protected virtual void Error_InvalidArguments (ResolveContext ec, Location loc, int idx, MethodBase method,
3767 Argument a, AParametersCollection expected_par, Type paramType)
3769 ExtensionMethodGroupExpr emg = this as ExtensionMethodGroupExpr;
3771 if (a is CollectionElementInitializer.ElementInitializerArgument) {
3772 ec.Report.SymbolRelatedToPreviousError (method);
3773 if ((expected_par.FixedParameters [idx].ModFlags & Parameter.Modifier.ISBYREF) != 0) {
3774 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
3775 TypeManager.CSharpSignature (method));
3778 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
3779 TypeManager.CSharpSignature (method));
3780 } else if (TypeManager.IsDelegateType (method.DeclaringType)) {
3781 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
3782 TypeManager.CSharpName (method.DeclaringType));
3784 ec.Report.SymbolRelatedToPreviousError (method);
3786 ec.Report.Error (1928, loc,
3787 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3788 emg.ExtensionExpression.GetSignatureForError (),
3789 emg.Name, TypeManager.CSharpSignature (method));
3791 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
3792 TypeManager.CSharpSignature (method));
3796 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters [idx].ModFlags;
3798 string index = (idx + 1).ToString ();
3799 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
3800 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
3801 if ((mod & Parameter.Modifier.ISBYREF) == 0)
3802 ec.Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
3803 index, Parameter.GetModifierSignature (a.Modifier));
3805 ec.Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
3806 index, Parameter.GetModifierSignature (mod));
3808 string p1 = a.GetSignatureForError ();
3809 string p2 = TypeManager.CSharpName (paramType);
3812 ec.Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
3813 ec.Report.SymbolRelatedToPreviousError (a.Expr.Type);
3814 ec.Report.SymbolRelatedToPreviousError (paramType);
3817 if (idx == 0 && emg != null) {
3818 ec.Report.Error (1929, loc,
3819 "Extension method instance type `{0}' cannot be converted to `{1}'", p1, p2);
3821 ec.Report.Error (1503, loc,
3822 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
3827 public override void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, Type target, bool expl)
3829 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3830 Name, TypeManager.CSharpName (target));
3833 void Error_ArgumentCountWrong (ResolveContext ec, int arg_count)
3835 ec.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
3836 Name, arg_count.ToString ());
3839 protected virtual int GetApplicableParametersCount (MethodBase method, AParametersCollection parameters)
3841 return parameters.Count;
3844 public static bool IsAncestralType (Type first_type, Type second_type)
3846 return first_type != second_type &&
3847 (TypeManager.IsSubclassOf (second_type, first_type) ||
3848 TypeManager.ImplementsInterface (second_type, first_type));
3852 /// Determines if the candidate method is applicable (section 14.4.2.1)
3853 /// to the given set of arguments
3854 /// A return value rates candidate method compatibility,
3855 /// 0 = the best, int.MaxValue = the worst
3857 public int IsApplicable (ResolveContext ec,
3858 ref Arguments arguments, int arg_count, ref MethodBase method, ref bool params_expanded_form)
3860 MethodBase candidate = method;
3862 AParametersCollection pd = TypeManager.GetParameterData (candidate);
3863 int param_count = GetApplicableParametersCount (candidate, pd);
3864 int optional_count = 0;
3866 if (arg_count != param_count) {
3867 for (int i = 0; i < pd.Count; ++i) {
3868 if (pd.FixedParameters [i].HasDefaultValue) {
3869 optional_count = pd.Count - i;
3874 int args_gap = Math.Abs (arg_count - param_count);
3875 if (optional_count != 0) {
3876 if (args_gap > optional_count)
3877 return int.MaxValue - 10000 + args_gap - optional_count;
3879 // Readjust expected number when params used
3882 if (arg_count < param_count)
3884 } else if (arg_count > param_count) {
3885 return int.MaxValue - 10000 + args_gap;
3887 } else if (arg_count != param_count) {
3889 return int.MaxValue - 10000 + args_gap;
3890 if (arg_count < param_count - 1)
3891 return int.MaxValue - 10000 + args_gap;
3894 // Initialize expanded form of a method with 1 params parameter
3895 params_expanded_form = param_count == 1 && pd.HasParams;
3897 // Resize to fit optional arguments
3898 if (optional_count != 0) {
3900 if (arguments == null) {
3901 resized = new Arguments (optional_count);
3903 resized = new Arguments (param_count);
3904 resized.AddRange (arguments);
3907 for (int i = arg_count; i < param_count; ++i)
3909 arguments = resized;
3913 if (arg_count > 0) {
3915 // Shuffle named arguments to the right positions if there are any
3917 if (arguments [arg_count - 1] is NamedArgument) {
3918 arg_count = arguments.Count;
3920 for (int i = 0; i < arg_count; ++i) {
3921 bool arg_moved = false;
3923 NamedArgument na = arguments[i] as NamedArgument;
3927 int index = pd.GetParameterIndexByName (na.Name.Value);
3929 // Named parameter not found or already reordered
3933 // When using parameters which should not be available to the user
3934 if (index >= param_count)
3938 arguments.MarkReorderedArgument (na);
3942 Argument temp = arguments[index];
3943 arguments[index] = arguments[i];
3944 arguments[i] = temp;
3951 arg_count = arguments.Count;
3953 } else if (arguments != null) {
3954 arg_count = arguments.Count;
3958 // 1. Handle generic method using type arguments when specified or type inference
3960 if (TypeManager.IsGenericMethod (candidate)) {
3961 if (type_arguments != null) {
3962 Type [] g_args = candidate.GetGenericArguments ();
3963 if (g_args.Length != type_arguments.Count)
3964 return int.MaxValue - 20000 + Math.Abs (type_arguments.Count - g_args.Length);
3966 // TODO: Don't create new method, create Parameters only
3967 method = ((MethodInfo) candidate).MakeGenericMethod (type_arguments.Arguments);
3969 pd = TypeManager.GetParameterData (candidate);
3971 int score = TypeManager.InferTypeArguments (ec, arguments, ref candidate);
3973 return score - 20000;
3975 if (TypeManager.IsGenericMethodDefinition (candidate))
3976 throw new InternalErrorException ("A generic method `{0}' definition took part in overload resolution",
3977 TypeManager.CSharpSignature (candidate));
3979 pd = TypeManager.GetParameterData (candidate);
3982 if (type_arguments != null)
3983 return int.MaxValue - 15000;
3987 // 2. Each argument has to be implicitly convertible to method parameter
3990 Parameter.Modifier p_mod = 0;
3992 for (int i = 0; i < arg_count; i++) {
3993 Argument a = arguments [i];
3995 if (!pd.FixedParameters [i].HasDefaultValue)
3996 throw new InternalErrorException ();
3998 Expression e = pd.FixedParameters [i].DefaultValue as Constant;
4000 e = new DefaultValueExpression (new TypeExpression (pd.Types [i], loc), loc).Resolve (ec);
4002 arguments [i] = new Argument (e, Argument.AType.Default);
4006 if (p_mod != Parameter.Modifier.PARAMS) {
4007 p_mod = pd.FixedParameters [i].ModFlags & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
4010 params_expanded_form = true;
4013 Parameter.Modifier a_mod = a.Modifier & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
4015 if (!params_expanded_form)
4016 score = IsArgumentCompatible (ec, a_mod, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
4018 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && delegate_type == null) {
4019 // It can be applicable in expanded form
4020 score = IsArgumentCompatible (ec, a_mod, a, 0, TypeManager.GetElementType (pt));
4022 params_expanded_form = true;
4026 if (params_expanded_form)
4028 return (arg_count - i) * 2 + score;
4032 if (arg_count != param_count)
4033 params_expanded_form = true;
4038 int IsArgumentCompatible (ResolveContext ec, Parameter.Modifier arg_mod, Argument argument, Parameter.Modifier param_mod, Type parameter)
4041 // Types have to be identical when ref or out modifer is used
4043 if (arg_mod != 0 || param_mod != 0) {
4044 if (TypeManager.HasElementType (parameter))
4045 parameter = TypeManager.GetElementType (parameter);
4047 Type a_type = argument.Type;
4048 if (TypeManager.HasElementType (a_type))
4049 a_type = TypeManager.GetElementType (a_type);
4051 if (a_type != parameter)
4054 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter))
4058 if (arg_mod != param_mod)
4064 public static bool IsOverride (MethodBase cand_method, MethodBase base_method)
4066 if (!IsAncestralType (base_method.DeclaringType, cand_method.DeclaringType))
4069 AParametersCollection cand_pd = TypeManager.GetParameterData (cand_method);
4070 AParametersCollection base_pd = TypeManager.GetParameterData (base_method);
4072 if (cand_pd.Count != base_pd.Count)
4075 for (int j = 0; j < cand_pd.Count; ++j)
4077 Parameter.Modifier cm = cand_pd.FixedParameters [j].ModFlags;
4078 Parameter.Modifier bm = base_pd.FixedParameters [j].ModFlags;
4079 Type ct = cand_pd.Types [j];
4080 Type bt = base_pd.Types [j];
4082 if (cm != bm || ct != bt)
4089 public static MethodGroupExpr MakeUnionSet (MethodGroupExpr mg1, MethodGroupExpr mg2, Location loc)
4100 ArrayList all = new ArrayList (mg1.Methods);
4101 foreach (MethodBase m in mg2.Methods){
4102 if (!TypeManager.ArrayContainsMethod (mg1.Methods, m, false))
4106 return new MethodGroupExpr (all, null, loc);
4109 static Type MoreSpecific (Type p, Type q)
4111 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4113 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4116 if (TypeManager.HasElementType (p))
4118 Type pe = TypeManager.GetElementType (p);
4119 Type qe = TypeManager.GetElementType (q);
4120 Type specific = MoreSpecific (pe, qe);
4126 else if (TypeManager.IsGenericType (p))
4128 Type[] pargs = TypeManager.GetTypeArguments (p);
4129 Type[] qargs = TypeManager.GetTypeArguments (q);
4131 bool p_specific_at_least_once = false;
4132 bool q_specific_at_least_once = false;
4134 for (int i = 0; i < pargs.Length; i++)
4136 Type specific = MoreSpecific (TypeManager.TypeToCoreType (pargs [i]), TypeManager.TypeToCoreType (qargs [i]));
4137 if (specific == pargs [i])
4138 p_specific_at_least_once = true;
4139 if (specific == qargs [i])
4140 q_specific_at_least_once = true;
4143 if (p_specific_at_least_once && !q_specific_at_least_once)
4145 if (!p_specific_at_least_once && q_specific_at_least_once)
4152 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4154 base.MutateHoistedGenericType (storey);
4156 MethodInfo mi = best_candidate as MethodInfo;
4158 best_candidate = storey.MutateGenericMethod (mi);
4162 best_candidate = storey.MutateConstructor ((ConstructorInfo) this);
4166 /// Find the Applicable Function Members (7.4.2.1)
4168 /// me: Method Group expression with the members to select.
4169 /// it might contain constructors or methods (or anything
4170 /// that maps to a method).
4172 /// Arguments: ArrayList containing resolved Argument objects.
4174 /// loc: The location if we want an error to be reported, or a Null
4175 /// location for "probing" purposes.
4177 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4178 /// that is the best match of me on Arguments.
4181 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments Arguments,
4182 bool may_fail, Location loc)
4184 bool method_params = false;
4185 Type applicable_type = null;
4186 ArrayList candidates = new ArrayList (2);
4187 ArrayList candidate_overrides = null;
4190 // Used to keep a map between the candidate
4191 // and whether it is being considered in its
4192 // normal or expanded form
4194 // false is normal form, true is expanded form
4196 Hashtable candidate_to_form = null;
4197 Hashtable candidates_expanded = null;
4198 Arguments candidate_args = Arguments;
4200 int arg_count = Arguments != null ? Arguments.Count : 0;
4202 if (RootContext.Version == LanguageVersion.ISO_1 && Name == "Invoke" && TypeManager.IsDelegateType (DeclaringType)) {
4204 ec.Report.Error (1533, loc, "Invoke cannot be called directly on a delegate");
4208 int nmethods = Methods.Length;
4212 // Methods marked 'override' don't take part in 'applicable_type'
4213 // computation, nor in the actual overload resolution.
4214 // However, they still need to be emitted instead of a base virtual method.
4215 // So, we salt them away into the 'candidate_overrides' array.
4217 // In case of reflected methods, we replace each overriding method with
4218 // its corresponding base virtual method. This is to improve compatibility
4219 // with non-C# libraries which change the visibility of overrides (#75636)
4222 for (int i = 0; i < Methods.Length; ++i) {
4223 MethodBase m = Methods [i];
4224 if (TypeManager.IsOverride (m)) {
4225 if (candidate_overrides == null)
4226 candidate_overrides = new ArrayList ();
4227 candidate_overrides.Add (m);
4228 m = TypeManager.TryGetBaseDefinition (m);
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 PtrHashtable ();
4271 MethodBase candidate = Methods [i];
4272 candidate_to_form [candidate] = candidate;
4275 if (candidate_args != Arguments) {
4276 if (candidates_expanded == null)
4277 candidates_expanded = new Hashtable (2);
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 AParametersCollection pd = TypeManager.GetParameterData (best_candidate);
4337 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4338 if (arg_count == pd.Count || pd.HasParams) {
4339 if (TypeManager.IsGenericMethodDefinition (best_candidate)) {
4340 if (type_arguments == null) {
4341 ec.Report.Error (411, loc,
4342 "The type arguments for method `{0}' cannot be inferred from " +
4343 "the usage. Try specifying the type arguments explicitly",
4344 TypeManager.CSharpSignature (best_candidate));
4348 Type[] g_args = TypeManager.GetGenericArguments (best_candidate);
4349 if (type_arguments.Count != g_args.Length) {
4350 ec.Report.SymbolRelatedToPreviousError (best_candidate);
4351 ec.Report.Error (305, loc, "Using the generic method `{0}' requires `{1}' type argument(s)",
4352 TypeManager.CSharpSignature (best_candidate),
4353 g_args.Length.ToString ());
4357 if (type_arguments != null && !TypeManager.IsGenericMethod (best_candidate)) {
4358 Error_TypeArgumentsCannotBeUsed (ec.Report, loc);
4363 if (has_inaccessible_candidates_only) {
4364 if (InstanceExpression != null && type != ec.CurrentType && TypeManager.IsNestedFamilyAccessible (ec.CurrentType, best_candidate.DeclaringType)) {
4365 // Although a derived class can access protected members of
4366 // its base class it cannot do so through an instance of the
4367 // base class (CS1540). If the qualifier_type is a base of the
4368 // ec.CurrentType and the lookup succeeds with the latter one,
4369 // then we are in this situation.
4370 Error_CannotAccessProtected (ec, loc, best_candidate, queried_type, ec.CurrentType);
4372 ec.Report.SymbolRelatedToPreviousError (best_candidate);
4373 ErrorIsInaccesible (loc, GetSignatureForError (), ec.Report);
4377 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate, cand_params, may_fail, loc))
4380 if (has_inaccessible_candidates_only)
4383 throw new InternalErrorException ("VerifyArgumentsCompat didn't find any problem with rejected candidate " + best_candidate);
4388 // We failed to find any method with correct argument count
4390 if (Name == ConstructorInfo.ConstructorName) {
4391 ec.Report.SymbolRelatedToPreviousError (queried_type);
4392 ec.Report.Error (1729, loc,
4393 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4394 TypeManager.CSharpName (queried_type), arg_count);
4396 Error_ArgumentCountWrong (ec, arg_count);
4404 // At this point, applicable_type is _one_ of the most derived types
4405 // in the set of types containing the methods in this MethodGroup.
4406 // Filter the candidates so that they only contain methods from the
4407 // most derived types.
4410 int finalized = 0; // Number of finalized candidates
4413 // Invariant: applicable_type is a most derived type
4415 // We'll try to complete Section 14.5.5.1 for 'applicable_type' by
4416 // eliminating all it's base types. At the same time, we'll also move
4417 // every unrelated type to the end of the array, and pick the next
4418 // 'applicable_type'.
4420 Type next_applicable_type = null;
4421 int j = finalized; // where to put the next finalized candidate
4422 int k = finalized; // where to put the next undiscarded candidate
4423 for (int i = finalized; i < candidate_top; ++i) {
4424 MethodBase candidate = (MethodBase) candidates [i];
4425 Type decl_type = candidate.DeclaringType;
4427 if (decl_type == applicable_type) {
4428 candidates [k++] = candidates [j];
4429 candidates [j++] = candidates [i];
4433 if (IsAncestralType (decl_type, applicable_type))
4436 if (next_applicable_type != null &&
4437 IsAncestralType (decl_type, next_applicable_type))
4440 candidates [k++] = candidates [i];
4442 if (next_applicable_type == null ||
4443 IsAncestralType (next_applicable_type, decl_type))
4444 next_applicable_type = decl_type;
4447 applicable_type = next_applicable_type;
4450 } while (applicable_type != null);
4454 // Now we actually find the best method
4457 best_candidate = (MethodBase) candidates [0];
4458 method_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4461 // TODO: Broken inverse order of candidates logic does not work with optional
4462 // parameters used for method overrides and I am not going to fix it for SRE
4464 if (candidates_expanded != null && candidates_expanded.Contains (best_candidate)) {
4465 candidate_args = (Arguments) candidates_expanded [best_candidate];
4466 arg_count = candidate_args.Count;
4469 for (int ix = 1; ix < candidate_top; ix++) {
4470 MethodBase candidate = (MethodBase) candidates [ix];
4472 if (candidate == best_candidate)
4475 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4477 if (BetterFunction (ec, candidate_args, arg_count,
4478 candidate, cand_params,
4479 best_candidate, method_params)) {
4480 best_candidate = candidate;
4481 method_params = cand_params;
4485 // Now check that there are no ambiguities i.e the selected method
4486 // should be better than all the others
4488 MethodBase ambiguous = null;
4489 for (int ix = 1; ix < candidate_top; ix++) {
4490 MethodBase candidate = (MethodBase) candidates [ix];
4492 if (candidate == best_candidate)
4495 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4496 if (!BetterFunction (ec, candidate_args, arg_count,
4497 best_candidate, method_params,
4498 candidate, cand_params))
4501 ec.Report.SymbolRelatedToPreviousError (candidate);
4502 ambiguous = candidate;
4506 if (ambiguous != null) {
4507 Error_AmbiguousCall (ec, ambiguous);
4512 // If the method is a virtual function, pick an override closer to the LHS type.
4514 if (!IsBase && best_candidate.IsVirtual) {
4515 if (TypeManager.IsOverride (best_candidate))
4516 throw new InternalErrorException (
4517 "Should not happen. An 'override' method took part in overload resolution: " + best_candidate);
4519 if (candidate_overrides != null) {
4520 Type[] gen_args = null;
4521 bool gen_override = false;
4522 if (TypeManager.IsGenericMethod (best_candidate))
4523 gen_args = TypeManager.GetGenericArguments (best_candidate);
4525 foreach (MethodBase candidate in candidate_overrides) {
4526 if (TypeManager.IsGenericMethod (candidate)) {
4527 if (gen_args == null)
4530 if (gen_args.Length != TypeManager.GetGenericArguments (candidate).Length)
4533 if (gen_args != null)
4537 if (IsOverride (candidate, best_candidate)) {
4538 gen_override = true;
4539 best_candidate = candidate;
4543 if (gen_override && gen_args != null) {
4544 best_candidate = ((MethodInfo) best_candidate).MakeGenericMethod (gen_args);
4550 // And now check if the arguments are all
4551 // compatible, perform conversions if
4552 // necessary etc. and return if everything is
4555 if (!VerifyArgumentsCompat (ec, ref candidate_args, arg_count, best_candidate,
4556 method_params, may_fail, loc))
4559 if (best_candidate == null)
4562 MethodBase the_method = TypeManager.DropGenericMethodArguments (best_candidate);
4563 if (TypeManager.IsGenericMethodDefinition (the_method) &&
4564 !ConstraintChecker.CheckConstraints (ec, the_method, best_candidate, loc))
4568 // Check ObsoleteAttribute on the best method
4570 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (the_method);
4571 if (oa != null && !ec.IsObsolete)
4572 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
4574 IMethodData data = TypeManager.GetMethod (the_method);
4576 data.SetMemberIsUsed ();
4578 Arguments = candidate_args;
4582 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4584 type_arguments = ta;
4587 public bool VerifyArgumentsCompat (ResolveContext ec, ref Arguments arguments,
4588 int arg_count, MethodBase method,
4589 bool chose_params_expanded,
4590 bool may_fail, Location loc)
4592 AParametersCollection pd = TypeManager.GetParameterData (method);
4593 int param_count = GetApplicableParametersCount (method, pd);
4595 int errors = ec.Report.Errors;
4596 Parameter.Modifier p_mod = 0;
4598 int a_idx = 0, a_pos = 0;
4600 ArrayList params_initializers = null;
4601 bool has_unsafe_arg = method is MethodInfo ? ((MethodInfo) method).ReturnType.IsPointer : false;
4603 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4604 a = arguments [a_idx];
4605 if (p_mod != Parameter.Modifier.PARAMS) {
4606 p_mod = pd.FixedParameters [a_idx].ModFlags;
4607 pt = pd.Types [a_idx];
4608 has_unsafe_arg |= pt.IsPointer;
4610 if (p_mod == Parameter.Modifier.PARAMS) {
4611 if (chose_params_expanded) {
4612 params_initializers = new ArrayList (arg_count - a_idx);
4613 pt = TypeManager.GetElementType (pt);
4619 // Types have to be identical when ref or out modifer is used
4621 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4622 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4625 if (!TypeManager.IsEqual (a.Expr.Type, pt))
4630 NamedArgument na = a as NamedArgument;
4632 int name_index = pd.GetParameterIndexByName (na.Name.Value);
4633 if (name_index < 0 || name_index >= param_count) {
4634 if (DeclaringType != null && TypeManager.IsDelegateType (DeclaringType)) {
4635 ec.Report.SymbolRelatedToPreviousError (DeclaringType);
4636 ec.Report.Error (1746, na.Name.Location,
4637 "The delegate `{0}' does not contain a parameter named `{1}'",
4638 TypeManager.CSharpName (DeclaringType), na.Name.Value);
4640 ec.Report.SymbolRelatedToPreviousError (best_candidate);
4641 ec.Report.Error (1739, na.Name.Location,
4642 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
4643 TypeManager.CSharpSignature (method), na.Name.Value);
4645 } else if (arguments[name_index] != a) {
4646 if (DeclaringType != null && TypeManager.IsDelegateType (DeclaringType))
4647 ec.Report.SymbolRelatedToPreviousError (DeclaringType);
4649 ec.Report.SymbolRelatedToPreviousError (best_candidate);
4651 ec.Report.Error (1744, na.Name.Location,
4652 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
4658 if (delegate_type != null && !Delegate.IsTypeCovariant (a.Expr, pt))
4661 Expression conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4666 // Convert params arguments to an array initializer
4668 if (params_initializers != null) {
4669 // we choose to use 'a.Expr' rather than 'conv' so that
4670 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
4671 params_initializers.Add (a.Expr);
4672 arguments.RemoveAt (a_idx--);
4677 // Update the argument with the implicit conversion
4681 if (a_idx != arg_count) {
4682 if (!may_fail && ec.Report.Errors == errors) {
4683 if (CustomErrorHandler != null)
4684 CustomErrorHandler.NoExactMatch (ec, best_candidate);
4686 Error_InvalidArguments (ec, loc, a_pos, method, a, pd, pt);
4692 // Fill not provided arguments required by params modifier
4694 if (params_initializers == null && pd.HasParams && arg_count + 1 == param_count) {
4695 if (arguments == null)
4696 arguments = new Arguments (1);
4698 pt = pd.Types [param_count - 1];
4699 pt = TypeManager.GetElementType (pt);
4700 has_unsafe_arg |= pt.IsPointer;
4701 params_initializers = new ArrayList (0);
4705 // Append an array argument with all params arguments
4707 if (params_initializers != null) {
4708 arguments.Add (new Argument (
4709 new ArrayCreation (new TypeExpression (pt, loc), "[]",
4710 params_initializers, loc).Resolve (ec)));
4714 if (arg_count < param_count) {
4716 Error_ArgumentCountWrong (ec, arg_count);
4720 if (has_unsafe_arg && !ec.IsUnsafe) {
4722 UnsafeError (ec, loc);
4730 public class ConstantExpr : MemberExpr
4734 public ConstantExpr (FieldInfo constant, Location loc)
4736 this.constant = constant;
4740 public override string Name {
4741 get { throw new NotImplementedException (); }
4744 public override bool IsInstance {
4745 get { return !IsStatic; }
4748 public override bool IsStatic {
4749 get { return constant.IsStatic; }
4752 public override Type DeclaringType {
4753 get { return constant.DeclaringType; }
4756 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, Location loc, SimpleName original)
4758 constant = TypeManager.GetGenericFieldDefinition (constant);
4760 IConstant ic = TypeManager.GetConstant (constant);
4762 if (constant.IsLiteral) {
4763 ic = new ExternalConstant (constant);
4765 ic = ExternalConstant.CreateDecimal (constant);
4766 // HACK: decimal field was not resolved as constant
4768 return new FieldExpr (constant, loc).ResolveMemberAccess (ec, left, loc, original);
4770 TypeManager.RegisterConstant (constant, ic);
4773 return base.ResolveMemberAccess (ec, left, loc, original);
4776 public override Expression CreateExpressionTree (ResolveContext ec)
4778 throw new NotSupportedException ("ET");
4781 public override Expression DoResolve (ResolveContext ec)
4783 IConstant ic = TypeManager.GetConstant (constant);
4784 if (ic.ResolveValue ()) {
4786 ic.CheckObsoleteness (loc);
4789 return ic.CreateConstantReference (loc);
4792 public override void Emit (EmitContext ec)
4794 throw new NotSupportedException ();
4797 public override string GetSignatureForError ()
4799 return TypeManager.GetFullNameSignature (constant);
4804 /// Fully resolved expression that evaluates to a Field
4806 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference {
4807 public FieldInfo FieldInfo;
4808 readonly Type constructed_generic_type;
4809 VariableInfo variable_info;
4811 LocalTemporary temp;
4814 protected FieldExpr (Location l)
4819 public FieldExpr (FieldInfo fi, Location l)
4822 type = TypeManager.TypeToCoreType (fi.FieldType);
4826 public FieldExpr (FieldInfo fi, Type genericType, Location l)
4829 if (TypeManager.IsGenericTypeDefinition (genericType))
4831 this.constructed_generic_type = genericType;
4834 public override string Name {
4836 return FieldInfo.Name;
4840 public override bool IsInstance {
4842 return !FieldInfo.IsStatic;
4846 public override bool IsStatic {
4848 return FieldInfo.IsStatic;
4852 public override Type DeclaringType {
4854 return FieldInfo.DeclaringType;
4858 public override string GetSignatureForError ()
4860 return TypeManager.GetFullNameSignature (FieldInfo);
4863 public VariableInfo VariableInfo {
4865 return variable_info;
4869 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, Location loc,
4870 SimpleName original)
4872 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
4873 Type t = fi.FieldType;
4875 if (t.IsPointer && !ec.IsUnsafe) {
4876 UnsafeError (ec, loc);
4879 return base.ResolveMemberAccess (ec, left, loc, original);
4882 public void SetHasAddressTaken ()
4884 IVariableReference vr = InstanceExpression as IVariableReference;
4886 vr.SetHasAddressTaken ();
4889 public override Expression CreateExpressionTree (ResolveContext ec)
4891 Expression instance;
4892 if (InstanceExpression == null) {
4893 instance = new NullLiteral (loc);
4895 instance = InstanceExpression.CreateExpressionTree (ec);
4898 Arguments args = Arguments.CreateForExpressionTree (ec, null,
4900 CreateTypeOfExpression ());
4902 return CreateExpressionFactoryCall (ec, "Field", args);
4905 public Expression CreateTypeOfExpression ()
4907 return new TypeOfField (GetConstructedFieldInfo (), loc);
4910 override public Expression DoResolve (ResolveContext ec)
4912 return DoResolve (ec, false, false);
4915 Expression DoResolve (ResolveContext ec, bool lvalue_instance, bool out_access)
4917 if (!FieldInfo.IsStatic){
4918 if (InstanceExpression == null){
4920 // This can happen when referencing an instance field using
4921 // a fully qualified type expression: TypeName.InstanceField = xxx
4923 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4927 // Resolve the field's instance expression while flow analysis is turned
4928 // off: when accessing a field "a.b", we must check whether the field
4929 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4931 if (lvalue_instance) {
4932 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
4933 Expression right_side =
4934 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4936 if (InstanceExpression != EmptyExpression.Null)
4937 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
4940 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
4942 if (InstanceExpression != EmptyExpression.Null)
4943 InstanceExpression = InstanceExpression.Resolve (ec, rf);
4946 if (InstanceExpression == null)
4949 using (ec.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
4950 InstanceExpression.CheckMarshalByRefAccess (ec);
4954 // TODO: the code above uses some non-standard multi-resolve rules
4955 if (eclass != ExprClass.Invalid)
4958 if (!ec.IsObsolete) {
4959 FieldBase f = TypeManager.GetField (FieldInfo);
4961 f.CheckObsoleteness (loc);
4963 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
4965 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc, ec.Report);
4969 IFixedBuffer fb = AttributeTester.GetFixedBuffer (FieldInfo);
4970 IVariableReference var = InstanceExpression as IVariableReference;
4973 IFixedExpression fe = InstanceExpression as IFixedExpression;
4974 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
4975 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4978 if (InstanceExpression.eclass != ExprClass.Variable) {
4979 ec.Report.SymbolRelatedToPreviousError (FieldInfo);
4980 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4981 TypeManager.GetFullNameSignature (FieldInfo));
4982 } else if (var != null && var.IsHoisted) {
4983 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
4986 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4989 eclass = ExprClass.Variable;
4991 // If the instance expression is a local variable or parameter.
4992 if (var == null || var.VariableInfo == null)
4995 VariableInfo vi = var.VariableInfo;
4996 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
4999 variable_info = vi.GetSubStruct (FieldInfo.Name);
5000 eclass = ExprClass.Variable;
5004 static readonly int [] codes = {
5005 191, // instance, write access
5006 192, // instance, out access
5007 198, // static, write access
5008 199, // static, out access
5009 1648, // member of value instance, write access
5010 1649, // member of value instance, out access
5011 1650, // member of value static, write access
5012 1651 // member of value static, out access
5015 static readonly string [] msgs = {
5016 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
5017 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5018 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5019 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
5020 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
5021 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5022 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5023 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
5026 // The return value is always null. Returning a value simplifies calling code.
5027 Expression Report_AssignToReadonly (ResolveContext ec, Expression right_side)
5030 if (right_side == EmptyExpression.OutAccess.Instance || right_side == EmptyExpression.LValueMemberOutAccess)
5034 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
5036 ec.Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
5041 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5043 IVariableReference var = InstanceExpression as IVariableReference;
5044 if (var != null && var.VariableInfo != null)
5045 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
5047 bool lvalue_instance = !FieldInfo.IsStatic && TypeManager.IsValueType (FieldInfo.DeclaringType);
5048 bool out_access = right_side == EmptyExpression.OutAccess.Instance || right_side == EmptyExpression.LValueMemberOutAccess;
5050 Expression e = DoResolve (ec, lvalue_instance, out_access);
5055 FieldBase fb = TypeManager.GetField (FieldInfo);
5059 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess.Instance) &&
5060 (fb.ModFlags & Modifiers.VOLATILE) != 0) {
5061 ec.Report.Warning (420, 1, loc,
5062 "`{0}': A volatile field references will not be treated as volatile",
5063 fb.GetSignatureForError ());
5067 if (FieldInfo.IsInitOnly) {
5068 // InitOnly fields can only be assigned in constructors or initializers
5069 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
5070 return Report_AssignToReadonly (ec, right_side);
5072 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
5073 Type ctype = ec.CurrentType;
5075 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
5076 if (!TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
5077 return Report_AssignToReadonly (ec, right_side);
5078 // static InitOnly fields cannot be assigned-to in an instance constructor
5079 if (IsStatic && !ec.IsStatic)
5080 return Report_AssignToReadonly (ec, right_side);
5081 // instance constructors can't modify InitOnly fields of other instances of the same type
5082 if (!IsStatic && !(InstanceExpression is This))
5083 return Report_AssignToReadonly (ec, right_side);
5087 if (right_side == EmptyExpression.OutAccess.Instance &&
5088 !IsStatic && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type)) {
5089 ec.Report.SymbolRelatedToPreviousError (DeclaringType);
5090 ec.Report.Warning (197, 1, loc,
5091 "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",
5092 GetSignatureForError ());
5095 eclass = ExprClass.Variable;
5099 bool is_marshal_by_ref ()
5101 return !IsStatic && TypeManager.IsStruct (Type) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type);
5104 public override void CheckMarshalByRefAccess (ResolveContext ec)
5106 if (is_marshal_by_ref () && !(InstanceExpression is This)) {
5107 ec.Report.SymbolRelatedToPreviousError (DeclaringType);
5108 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",
5109 GetSignatureForError ());
5113 public override int GetHashCode ()
5115 return FieldInfo.GetHashCode ();
5118 public bool IsFixed {
5121 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
5123 IVariableReference variable = InstanceExpression as IVariableReference;
5124 if (variable != null)
5125 return TypeManager.IsStruct (InstanceExpression.Type) && variable.IsFixed;
5127 IFixedExpression fe = InstanceExpression as IFixedExpression;
5128 return fe != null && fe.IsFixed;
5132 public bool IsHoisted {
5134 IVariableReference hv = InstanceExpression as IVariableReference;
5135 return hv != null && hv.IsHoisted;
5139 public override bool Equals (object obj)
5141 FieldExpr fe = obj as FieldExpr;
5145 if (FieldInfo != fe.FieldInfo)
5148 if (InstanceExpression == null || fe.InstanceExpression == null)
5151 return InstanceExpression.Equals (fe.InstanceExpression);
5154 public void Emit (EmitContext ec, bool leave_copy)
5156 ILGenerator ig = ec.ig;
5157 bool is_volatile = false;
5159 FieldBase f = TypeManager.GetField (FieldInfo);
5161 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
5164 f.SetMemberIsUsed ();
5167 if (FieldInfo.IsStatic){
5169 ig.Emit (OpCodes.Volatile);
5171 ig.Emit (OpCodes.Ldsfld, GetConstructedFieldInfo ());
5174 EmitInstance (ec, false);
5176 // Optimization for build-in types
5177 if (TypeManager.IsStruct (type) && TypeManager.IsEqual (type, ec.MemberContext.CurrentType)) {
5178 LoadFromPtr (ig, type);
5180 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
5182 ig.Emit (OpCodes.Ldflda, GetConstructedFieldInfo ());
5183 ig.Emit (OpCodes.Ldflda, ff.Element);
5186 ig.Emit (OpCodes.Volatile);
5188 ig.Emit (OpCodes.Ldfld, GetConstructedFieldInfo ());
5194 ec.ig.Emit (OpCodes.Dup);
5195 if (!FieldInfo.IsStatic) {
5196 temp = new LocalTemporary (this.Type);
5202 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5204 FieldAttributes fa = FieldInfo.Attributes;
5205 bool is_static = (fa & FieldAttributes.Static) != 0;
5206 ILGenerator ig = ec.ig;
5208 prepared = prepare_for_load;
5209 EmitInstance (ec, prepared);
5213 ec.ig.Emit (OpCodes.Dup);
5214 if (!FieldInfo.IsStatic) {
5215 temp = new LocalTemporary (this.Type);
5220 FieldBase f = TypeManager.GetField (FieldInfo);
5222 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
5223 ig.Emit (OpCodes.Volatile);
5229 ig.Emit (OpCodes.Stsfld, GetConstructedFieldInfo ());
5231 ig.Emit (OpCodes.Stfld, GetConstructedFieldInfo ());
5240 public override void Emit (EmitContext ec)
5245 public override void EmitSideEffect (EmitContext ec)
5247 FieldBase f = TypeManager.GetField (FieldInfo);
5248 bool is_volatile = f != null && (f.ModFlags & Modifiers.VOLATILE) != 0;
5250 if (is_volatile || is_marshal_by_ref ())
5251 base.EmitSideEffect (ec);
5254 public override void Error_VariableIsUsedBeforeItIsDeclared (Report r, string name)
5257 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the field `{1}'",
5258 name, GetSignatureForError ());
5261 public void AddressOf (EmitContext ec, AddressOp mode)
5263 ILGenerator ig = ec.ig;
5265 FieldBase f = TypeManager.GetField (FieldInfo);
5267 if ((mode & AddressOp.Store) != 0)
5269 if ((mode & AddressOp.Load) != 0)
5270 f.SetMemberIsUsed ();
5274 // Handle initonly fields specially: make a copy and then
5275 // get the address of the copy.
5278 if (FieldInfo.IsInitOnly){
5280 if (ec.HasSet (EmitContext.Options.ConstructorScope)){
5281 if (FieldInfo.IsStatic){
5293 local = ig.DeclareLocal (type);
5294 ig.Emit (OpCodes.Stloc, local);
5295 ig.Emit (OpCodes.Ldloca, local);
5300 if (FieldInfo.IsStatic){
5301 ig.Emit (OpCodes.Ldsflda, GetConstructedFieldInfo ());
5304 EmitInstance (ec, false);
5305 ig.Emit (OpCodes.Ldflda, GetConstructedFieldInfo ());
5309 FieldInfo GetConstructedFieldInfo ()
5311 if (constructed_generic_type == null)
5314 return TypeBuilder.GetField (constructed_generic_type, FieldInfo);
5318 public SLE.Expression MakeAssignExpression (BuilderContext ctx)
5320 return MakeExpression (ctx);
5323 public override SLE.Expression MakeExpression (BuilderContext ctx)
5325 return SLE.Expression.Field (InstanceExpression.MakeExpression (ctx), FieldInfo);
5329 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5331 FieldInfo = storey.MutateField (FieldInfo);
5332 base.MutateHoistedGenericType (storey);
5338 /// Expression that evaluates to a Property. The Assign class
5339 /// might set the `Value' expression if we are in an assignment.
5341 /// This is not an LValue because we need to re-write the expression, we
5342 /// can not take data from the stack and store it.
5344 public class PropertyExpr : MemberExpr, IDynamicAssign
5346 public readonly PropertyInfo PropertyInfo;
5347 MethodInfo getter, setter;
5351 TypeArguments targs;
5353 LocalTemporary temp;
5356 public PropertyExpr (Type container_type, PropertyInfo pi, Location l)
5359 eclass = ExprClass.PropertyAccess;
5363 type = TypeManager.TypeToCoreType (pi.PropertyType);
5365 ResolveAccessors (container_type);
5368 public override string Name {
5370 return PropertyInfo.Name;
5374 public override bool IsInstance {
5380 public override bool IsStatic {
5386 public override Expression CreateExpressionTree (ResolveContext ec)
5389 if (IsSingleDimensionalArrayLength ()) {
5390 args = new Arguments (1);
5391 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5392 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
5396 Error_BaseAccessInExpressionTree (ec, loc);
5400 args = new Arguments (2);
5401 if (InstanceExpression == null)
5402 args.Add (new Argument (new NullLiteral (loc)));
5404 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5405 args.Add (new Argument (new TypeOfMethod (getter, loc)));
5406 return CreateExpressionFactoryCall (ec, "Property", args);
5409 public Expression CreateSetterTypeOfExpression ()
5411 return new TypeOfMethod (setter, loc);
5414 public override Type DeclaringType {
5416 return PropertyInfo.DeclaringType;
5420 public override string GetSignatureForError ()
5422 return TypeManager.GetFullNameSignature (PropertyInfo);
5425 void FindAccessors (Type invocation_type)
5427 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
5428 BindingFlags.Static | BindingFlags.Instance |
5429 BindingFlags.DeclaredOnly;
5431 Type current = PropertyInfo.DeclaringType;
5432 for (; current != null; current = current.BaseType) {
5433 MemberInfo[] group = TypeManager.MemberLookup (
5434 invocation_type, invocation_type, current,
5435 MemberTypes.Property, flags, PropertyInfo.Name, null);
5440 if (group.Length != 1)
5441 // Oooops, can this ever happen ?
5444 PropertyInfo pi = (PropertyInfo) group [0];
5447 getter = pi.GetGetMethod (true);
5450 setter = pi.GetSetMethod (true);
5452 MethodInfo accessor = getter != null ? getter : setter;
5454 if (!accessor.IsVirtual)
5460 // We also perform the permission checking here, as the PropertyInfo does not
5461 // hold the information for the accessibility of its setter/getter
5463 // TODO: Refactor to use some kind of cache together with GetPropertyFromAccessor
5464 void ResolveAccessors (Type container_type)
5466 FindAccessors (container_type);
5468 if (getter != null) {
5469 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
5470 IMethodData md = TypeManager.GetMethod (the_getter);
5472 md.SetMemberIsUsed ();
5474 is_static = getter.IsStatic;
5477 if (setter != null) {
5478 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
5479 IMethodData md = TypeManager.GetMethod (the_setter);
5481 md.SetMemberIsUsed ();
5483 is_static = setter.IsStatic;
5488 public SLE.Expression MakeAssignExpression (BuilderContext ctx)
5490 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), setter);
5493 public override SLE.Expression MakeExpression (BuilderContext ctx)
5495 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), getter);
5499 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5501 if (InstanceExpression != null)
5502 InstanceExpression.MutateHoistedGenericType (storey);
5504 type = storey.MutateType (type);
5506 getter = storey.MutateGenericMethod (getter);
5508 setter = storey.MutateGenericMethod (setter);
5511 bool InstanceResolve (ResolveContext ec, bool lvalue_instance, bool must_do_cs1540_check)
5514 InstanceExpression = null;
5518 if (InstanceExpression == null) {
5519 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5523 InstanceExpression = InstanceExpression.DoResolve (ec);
5524 if (lvalue_instance && InstanceExpression != null)
5525 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess);
5527 if (InstanceExpression == null)
5530 InstanceExpression.CheckMarshalByRefAccess (ec);
5532 if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) &&
5533 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.CurrentType) &&
5534 !TypeManager.IsNestedChildOf (ec.CurrentType, InstanceExpression.Type) &&
5535 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.CurrentType)) {
5536 ec.Report.SymbolRelatedToPreviousError (PropertyInfo);
5537 Error_CannotAccessProtected (ec, loc, PropertyInfo, InstanceExpression.Type, ec.CurrentType);
5544 void Error_PropertyNotFound (ResolveContext ec, MethodInfo mi, bool getter)
5546 // TODO: correctly we should compare arguments but it will lead to bigger changes
5547 if (mi is MethodBuilder) {
5548 Error_TypeDoesNotContainDefinition (ec, loc, PropertyInfo.DeclaringType, Name);
5552 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
5554 AParametersCollection iparams = TypeManager.GetParameterData (mi);
5555 sig.Append (getter ? "get_" : "set_");
5557 sig.Append (iparams.GetSignatureForError ());
5559 ec.Report.SymbolRelatedToPreviousError (mi);
5560 ec.Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
5561 Name, sig.ToString ());
5564 public bool IsAccessibleFrom (Type invocation_type, bool lvalue)
5567 MethodInfo accessor = lvalue ? setter : getter;
5568 if (accessor == null && lvalue)
5570 return accessor != null && IsAccessorAccessible (invocation_type, accessor, out dummy);
5573 bool IsSingleDimensionalArrayLength ()
5575 if (DeclaringType != TypeManager.array_type || getter == null || Name != "Length")
5578 string t_name = InstanceExpression.Type.Name;
5579 int t_name_len = t_name.Length;
5580 return t_name_len > 2 && t_name [t_name_len - 2] == '[';
5583 public override Expression DoResolve (ResolveContext ec)
5588 bool must_do_cs1540_check = false;
5589 ec.Report.DisableReporting ();
5590 bool res = ResolveGetter (ec, ref must_do_cs1540_check);
5591 ec.Report.EnableReporting ();
5594 if (InstanceExpression != null) {
5595 Type expr_type = InstanceExpression.Type;
5596 ExtensionMethodGroupExpr ex_method_lookup = ec.LookupExtensionMethod (expr_type, Name, loc);
5597 if (ex_method_lookup != null) {
5598 ex_method_lookup.ExtensionExpression = InstanceExpression;
5599 ex_method_lookup.SetTypeArguments (ec, targs);
5600 return ex_method_lookup.DoResolve (ec);
5604 ResolveGetter (ec, ref must_do_cs1540_check);
5608 if (!InstanceResolve (ec, false, must_do_cs1540_check))
5612 // Only base will allow this invocation to happen.
5614 if (IsBase && getter.IsAbstract) {
5615 Error_CannotCallAbstractBase (ec, TypeManager.GetFullNameSignature (PropertyInfo));
5618 if (PropertyInfo.PropertyType.IsPointer && !ec.IsUnsafe){
5619 UnsafeError (ec, loc);
5622 if (!ec.IsObsolete) {
5623 PropertyBase pb = TypeManager.GetProperty (PropertyInfo);
5625 pb.CheckObsoleteness (loc);
5627 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (PropertyInfo);
5629 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
5638 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5640 if (right_side == EmptyExpression.OutAccess.Instance) {
5641 if (ec.CurrentBlock.Toplevel.GetParameterReference (PropertyInfo.Name, loc) is MemberAccess) {
5642 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5645 right_side.DoResolveLValue (ec, this);
5650 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5651 Error_CannotModifyIntermediateExpressionValue (ec);
5654 if (setter == null){
5656 // The following condition happens if the PropertyExpr was
5657 // created, but is invalid (ie, the property is inaccessible),
5658 // and we did not want to embed the knowledge about this in
5659 // the caller routine. This only avoids double error reporting.
5664 if (ec.CurrentBlock.Toplevel.GetParameterReference (PropertyInfo.Name, loc) is MemberAccess) {
5665 ec.Report.Error (1947, loc, "A range variable `{0}' cannot be assigned to. Consider using `let' clause to store the value",
5668 ec.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
5669 GetSignatureForError ());
5674 if (targs != null) {
5675 base.SetTypeArguments (ec, targs);
5679 if (TypeManager.GetParameterData (setter).Count != 1){
5680 Error_PropertyNotFound (ec, setter, false);
5684 bool must_do_cs1540_check;
5685 if (!IsAccessorAccessible (ec.CurrentType, setter, out must_do_cs1540_check)) {
5686 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
5687 if (pm != null && pm.HasCustomAccessModifier) {
5688 ec.Report.SymbolRelatedToPreviousError (pm);
5689 ec.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5690 TypeManager.CSharpSignature (setter));
5693 ec.Report.SymbolRelatedToPreviousError (setter);
5694 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter), ec.Report);
5699 if (!InstanceResolve (ec, TypeManager.IsStruct (PropertyInfo.DeclaringType), must_do_cs1540_check))
5703 // Only base will allow this invocation to happen.
5705 if (IsBase && setter.IsAbstract){
5706 Error_CannotCallAbstractBase (ec, TypeManager.GetFullNameSignature (PropertyInfo));
5709 if (PropertyInfo.PropertyType.IsPointer && !ec.IsUnsafe) {
5710 UnsafeError (ec, loc);
5713 if (!ec.IsObsolete) {
5714 PropertyBase pb = TypeManager.GetProperty (PropertyInfo);
5716 pb.CheckObsoleteness (loc);
5718 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (PropertyInfo);
5720 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
5727 public override void Emit (EmitContext ec)
5732 public void Emit (EmitContext ec, bool leave_copy)
5735 // Special case: length of single dimension array property is turned into ldlen
5737 if (IsSingleDimensionalArrayLength ()) {
5739 EmitInstance (ec, false);
5740 ec.ig.Emit (OpCodes.Ldlen);
5741 ec.ig.Emit (OpCodes.Conv_I4);
5745 Invocation.EmitCall (ec, IsBase, InstanceExpression, getter, null, loc, prepared, false);
5748 ec.ig.Emit (OpCodes.Dup);
5750 temp = new LocalTemporary (this.Type);
5757 // Implements the IAssignMethod interface for assignments
5759 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5761 Expression my_source = source;
5763 if (prepare_for_load) {
5768 ec.ig.Emit (OpCodes.Dup);
5770 temp = new LocalTemporary (this.Type);
5774 } else if (leave_copy) {
5776 temp = new LocalTemporary (this.Type);
5781 Arguments args = new Arguments (1);
5782 args.Add (new Argument (my_source));
5784 Invocation.EmitCall (ec, IsBase, InstanceExpression, setter, args, loc, false, prepared);
5792 bool ResolveGetter (ResolveContext ec, ref bool must_do_cs1540_check)
5794 if (targs != null) {
5795 base.SetTypeArguments (ec, targs);
5799 if (getter != null) {
5800 if (TypeManager.GetParameterData (getter).Count != 0) {
5801 Error_PropertyNotFound (ec, getter, true);
5806 if (getter == null) {
5808 // The following condition happens if the PropertyExpr was
5809 // created, but is invalid (ie, the property is inaccessible),
5810 // and we did not want to embed the knowledge about this in
5811 // the caller routine. This only avoids double error reporting.
5816 if (InstanceExpression != EmptyExpression.Null) {
5817 ec.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5818 TypeManager.GetFullNameSignature (PropertyInfo));
5823 if (getter != null &&
5824 !IsAccessorAccessible (ec.CurrentType, getter, out must_do_cs1540_check)) {
5825 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
5826 if (pm != null && pm.HasCustomAccessModifier) {
5827 ec.Report.SymbolRelatedToPreviousError (pm);
5828 ec.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5829 TypeManager.CSharpSignature (getter));
5831 ec.Report.SymbolRelatedToPreviousError (getter);
5832 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter), ec.Report);
5841 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5848 /// Fully resolved expression that evaluates to an Event
5850 public class EventExpr : MemberExpr {
5851 public readonly EventInfo EventInfo;
5854 MethodInfo add_accessor, remove_accessor;
5856 public EventExpr (EventInfo ei, Location loc)
5860 eclass = ExprClass.EventAccess;
5862 add_accessor = TypeManager.GetAddMethod (ei);
5863 remove_accessor = TypeManager.GetRemoveMethod (ei);
5864 if (add_accessor.IsStatic || remove_accessor.IsStatic)
5867 if (EventInfo is MyEventBuilder){
5868 MyEventBuilder eb = (MyEventBuilder) EventInfo;
5869 type = eb.EventType;
5872 type = EventInfo.EventHandlerType;
5875 public override string Name {
5877 return EventInfo.Name;
5881 public override bool IsInstance {
5887 public override bool IsStatic {
5893 public override Type DeclaringType {
5895 return EventInfo.DeclaringType;
5899 public void Error_AssignmentEventOnly (ResolveContext ec)
5901 ec.Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5902 GetSignatureForError ());
5905 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, Location loc,
5906 SimpleName original)
5909 // If the event is local to this class, we transform ourselves into a FieldExpr
5912 if (EventInfo.DeclaringType == ec.CurrentType ||
5913 TypeManager.IsNestedChildOf(ec.CurrentType, EventInfo.DeclaringType)) {
5915 // TODO: Breaks dynamic binder as currect context fields are imported and not compiled
5916 EventField mi = TypeManager.GetEventField (EventInfo);
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.FieldBuilder, 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.DoResolve (ec);
5952 if (InstanceExpression == null)
5955 if (IsBase && add_accessor.IsAbstract) {
5956 Error_CannotCallAbstractBase (ec, TypeManager.CSharpSignature(add_accessor));
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 (EventInfo);
5971 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo), ec.Report);
5978 public bool IsAccessibleFrom (Type invocation_type)
5981 return IsAccessorAccessible (invocation_type, add_accessor, out dummy) &&
5982 IsAccessorAccessible (invocation_type, remove_accessor, 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 public override Expression DoResolve (ResolveContext ec)
5999 bool must_do_cs1540_check;
6000 if (!(IsAccessorAccessible (ec.CurrentType, add_accessor, out must_do_cs1540_check) &&
6001 IsAccessorAccessible (ec.CurrentType, remove_accessor, out must_do_cs1540_check))) {
6002 ec.Report.SymbolRelatedToPreviousError (EventInfo);
6003 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo), ec.Report);
6007 if (!InstanceResolve (ec, must_do_cs1540_check))
6010 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6011 Error_CannotAssign (ec);
6015 if (!ec.IsObsolete) {
6016 EventField ev = TypeManager.GetEventField (EventInfo);
6018 ev.CheckObsoleteness (loc);
6020 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (EventInfo);
6022 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
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 (EventInfo.DeclaringType));
6042 public override string GetSignatureForError ()
6044 return TypeManager.CSharpSignature (EventInfo);
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, is_add ? add_accessor : remove_accessor, args, loc);
6055 public class TemporaryVariable : VariableReference
6059 public TemporaryVariable (Type type, Location loc)
6063 eclass = ExprClass.Variable;
6066 public override Expression CreateExpressionTree (ResolveContext ec)
6068 throw new NotSupportedException ("ET");
6071 public override Expression DoResolve (ResolveContext ec)
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 DoResolve (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 ArrayList initializer;
6148 public VarExpr (Location loc)
6153 public ArrayList VariableInitializer {
6155 this.initializer = value;
6159 public bool InferType (ResolveContext ec, Expression right_side)
6162 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
6164 type = right_side.Type;
6165 if (type == TypeManager.null_type || type == TypeManager.void_type || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
6166 ec.Report.Error (815, loc, "An implicitly typed local variable declaration cannot be initialized with `{0}'",
6167 right_side.GetSignatureForError ());
6171 eclass = ExprClass.Variable;
6175 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
6177 if (RootContext.Version < LanguageVersion.V_3)
6178 base.Error_TypeOrNamespaceNotFound (ec);
6180 ec.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");
6183 public override TypeExpr ResolveAsContextualType (IMemberContext rc, bool silent)
6185 TypeExpr te = base.ResolveAsContextualType (rc, true);
6189 if (RootContext.Version < LanguageVersion.V_3)
6190 rc.Compiler.Report.FeatureIsNotAvailable (loc, "implicitly typed local variable");
6192 if (initializer == null)
6195 if (initializer.Count > 1) {
6196 Location loc_init = ((CSharpParser.VariableDeclaration) initializer[1]).Location;
6197 rc.Compiler.Report.Error (819, loc_init, "An implicitly typed local variable declaration cannot include multiple declarators");
6202 Expression variable_initializer = ((CSharpParser.VariableDeclaration) initializer[0]).expression_or_array_initializer;
6203 if (variable_initializer == null) {
6204 rc.Compiler.Report.Error (818, loc, "An implicitly typed local variable declarator must include an initializer");