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;
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 public override Expression DoResolve (ResolveContext ec)
1689 // This should never be invoked, we are born in fully
1690 // initialized state.
1695 public override void Emit (EmitContext ec)
1700 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1702 Child.EmitBranchable (ec, label, on_true);
1705 public override void EmitSideEffect (EmitContext ec)
1707 Child.EmitSideEffect (ec);
1710 public override bool GetAttributableValue (ResolveContext ec, Type value_type, out object value)
1712 value = GetTypedValue ();
1716 public override string GetSignatureForError()
1718 return TypeManager.CSharpName (Type);
1721 public override object GetValue ()
1723 return Child.GetValue ();
1726 public override object GetTypedValue ()
1728 // FIXME: runtime is not ready to work with just emited enums
1729 if (!RootContext.StdLib) {
1730 return Child.GetValue ();
1734 // Small workaround for big problem
1735 // System.Enum.ToObject cannot be called on dynamic types
1736 // EnumBuilder has to be used, but we cannot use EnumBuilder
1737 // because it does not properly support generics
1739 // This works only sometimes
1741 if (type.Module == RootContext.ToplevelTypes.Builder)
1742 return Child.GetValue ();
1745 return System.Enum.ToObject (type, Child.GetValue ());
1748 public override string AsString ()
1750 return Child.AsString ();
1753 public override Constant Increment()
1755 return new EnumConstant (Child.Increment (), type);
1758 public override bool IsDefaultValue {
1760 return Child.IsDefaultValue;
1764 public override bool IsZeroInteger {
1765 get { return Child.IsZeroInteger; }
1768 public override bool IsNegative {
1770 return Child.IsNegative;
1774 public override Constant ConvertExplicitly(bool in_checked_context, Type target_type)
1776 if (Child.Type == target_type)
1779 return Child.ConvertExplicitly (in_checked_context, target_type);
1782 public override Constant ConvertImplicitly (Type type)
1784 Type this_type = TypeManager.DropGenericTypeArguments (Type);
1785 type = TypeManager.DropGenericTypeArguments (type);
1787 if (this_type == type) {
1788 // This is workaround of mono bug. It can be removed when the latest corlib spreads enough
1789 if (TypeManager.IsEnumType (type.UnderlyingSystemType))
1792 Type child_type = TypeManager.DropGenericTypeArguments (Child.Type);
1793 if (type.UnderlyingSystemType != child_type)
1794 Child = Child.ConvertImplicitly (type.UnderlyingSystemType);
1798 if (!Convert.ImplicitStandardConversionExists (this, type)){
1802 return Child.ConvertImplicitly(type);
1808 /// This kind of cast is used to encapsulate Value Types in objects.
1810 /// The effect of it is to box the value type emitted by the previous
1813 public class BoxedCast : TypeCast {
1815 public BoxedCast (Expression expr, Type target_type)
1816 : base (expr, target_type)
1818 eclass = ExprClass.Value;
1821 public override Expression DoResolve (ResolveContext ec)
1823 // This should never be invoked, we are born in fully
1824 // initialized state.
1829 public override void Emit (EmitContext ec)
1833 ec.ig.Emit (OpCodes.Box, child.Type);
1836 public override void EmitSideEffect (EmitContext ec)
1838 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1839 // so, we need to emit the box+pop instructions in most cases
1840 if (TypeManager.IsStruct (child.Type) &&
1841 (type == TypeManager.object_type || type == TypeManager.value_type))
1842 child.EmitSideEffect (ec);
1844 base.EmitSideEffect (ec);
1848 public class UnboxCast : TypeCast {
1849 public UnboxCast (Expression expr, Type return_type)
1850 : base (expr, return_type)
1854 public override Expression DoResolve (ResolveContext ec)
1856 // This should never be invoked, we are born in fully
1857 // initialized state.
1862 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
1864 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
1865 ec.Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
1866 return base.DoResolveLValue (ec, right_side);
1869 public override void Emit (EmitContext ec)
1873 ILGenerator ig = ec.ig;
1874 ig.Emit (OpCodes.Unbox_Any, type);
1877 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1879 type = storey.MutateType (type);
1880 base.MutateHoistedGenericType (storey);
1885 /// This is used to perform explicit numeric conversions.
1887 /// Explicit numeric conversions might trigger exceptions in a checked
1888 /// context, so they should generate the conv.ovf opcodes instead of
1891 public class ConvCast : TypeCast {
1892 public enum Mode : byte {
1893 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1895 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1896 U2_I1, U2_U1, U2_I2, U2_CH,
1897 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1898 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1899 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1900 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1901 CH_I1, CH_U1, CH_I2,
1902 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1903 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1909 public ConvCast (Expression child, Type return_type, Mode m)
1910 : base (child, return_type)
1915 public override Expression DoResolve (ResolveContext ec)
1917 // This should never be invoked, we are born in fully
1918 // initialized state.
1923 public override string ToString ()
1925 return String.Format ("ConvCast ({0}, {1})", mode, child);
1928 public override void Emit (EmitContext ec)
1930 ILGenerator ig = ec.ig;
1934 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1936 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1937 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1938 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1939 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1940 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1942 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1943 case Mode.U1_CH: /* nothing */ break;
1945 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1946 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1947 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1948 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1949 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1950 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1952 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1953 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1954 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1955 case Mode.U2_CH: /* nothing */ break;
1957 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1958 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1959 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1960 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1961 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1962 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1963 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1965 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1966 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1967 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1968 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1969 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1970 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1972 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1973 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1974 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1975 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1976 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1977 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1978 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1979 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1980 case Mode.I8_I: ig.Emit (OpCodes.Conv_Ovf_U); break;
1982 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1983 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1984 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1985 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1986 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1987 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1988 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1989 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1990 case Mode.U8_I: ig.Emit (OpCodes.Conv_Ovf_U_Un); break;
1992 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1993 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1994 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1996 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1997 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1998 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1999 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
2000 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
2001 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
2002 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
2003 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
2004 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
2006 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
2007 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
2008 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
2009 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
2010 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
2011 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
2012 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
2013 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
2014 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
2015 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
2017 case Mode.I_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
2021 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
2022 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
2023 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
2024 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
2025 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
2027 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
2028 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
2030 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
2031 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
2032 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
2033 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
2034 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
2035 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
2037 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
2038 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
2039 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
2040 case Mode.U2_CH: /* nothing */ break;
2042 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
2043 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
2044 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
2045 case Mode.I4_U4: /* nothing */ break;
2046 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
2047 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
2048 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
2050 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
2051 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
2052 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
2053 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
2054 case Mode.U4_I4: /* nothing */ break;
2055 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
2057 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
2058 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
2059 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
2060 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
2061 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
2062 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
2063 case Mode.I8_U8: /* nothing */ break;
2064 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
2065 case Mode.I8_I: ig.Emit (OpCodes.Conv_U); break;
2067 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
2068 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
2069 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
2070 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
2071 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
2072 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
2073 case Mode.U8_I8: /* nothing */ break;
2074 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
2075 case Mode.U8_I: ig.Emit (OpCodes.Conv_U); break;
2077 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
2078 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
2079 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
2081 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
2082 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
2083 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
2084 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
2085 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
2086 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
2087 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
2088 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
2089 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
2091 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
2092 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
2093 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
2094 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
2095 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
2096 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
2097 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
2098 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
2099 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
2100 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
2102 case Mode.I_I8: ig.Emit (OpCodes.Conv_U8); break;
2108 public class OpcodeCast : TypeCast {
2111 public OpcodeCast (Expression child, Type return_type, OpCode op)
2112 : base (child, return_type)
2117 public override Expression DoResolve (ResolveContext ec)
2119 // This should never be invoked, we are born in fully
2120 // initialized state.
2125 public override void Emit (EmitContext ec)
2131 public Type UnderlyingType {
2132 get { return child.Type; }
2137 /// This kind of cast is used to encapsulate a child and cast it
2138 /// to the class requested
2140 public sealed class ClassCast : TypeCast {
2141 readonly bool forced;
2143 public ClassCast (Expression child, Type return_type)
2144 : base (child, return_type)
2148 public ClassCast (Expression child, Type return_type, bool forced)
2149 : base (child, return_type)
2151 this.forced = forced;
2154 public override void Emit (EmitContext ec)
2158 bool gen = TypeManager.IsGenericParameter (child.Type);
2160 ec.ig.Emit (OpCodes.Box, child.Type);
2162 if (type.IsGenericParameter) {
2163 ec.ig.Emit (OpCodes.Unbox_Any, type);
2170 ec.ig.Emit (OpCodes.Castclass, type);
2175 // Created during resolving pahse when an expression is wrapped or constantified
2176 // and original expression can be used later (e.g. for expression trees)
2178 public class ReducedExpression : Expression
2180 sealed class ReducedConstantExpression : EmptyConstantCast
2182 readonly Expression orig_expr;
2184 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2185 : base (expr, expr.Type)
2187 this.orig_expr = orig_expr;
2190 public override Constant ConvertImplicitly (Type target_type)
2192 Constant c = base.ConvertImplicitly (target_type);
2194 c = new ReducedConstantExpression (c, orig_expr);
2198 public override Expression CreateExpressionTree (ResolveContext ec)
2200 return orig_expr.CreateExpressionTree (ec);
2203 public override bool GetAttributableValue (ResolveContext ec, Type value_type, out object value)
2206 // Even if resolved result is a constant original expression was not
2207 // and attribute accepts constants only
2209 Attribute.Error_AttributeArgumentNotValid (ec, orig_expr.Location);
2214 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
2216 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
2218 c = new ReducedConstantExpression (c, orig_expr);
2223 sealed class ReducedExpressionStatement : ExpressionStatement
2225 readonly Expression orig_expr;
2226 readonly ExpressionStatement stm;
2228 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
2230 this.orig_expr = orig;
2232 this.loc = orig.Location;
2235 public override Expression CreateExpressionTree (ResolveContext ec)
2237 return orig_expr.CreateExpressionTree (ec);
2240 public override Expression DoResolve (ResolveContext ec)
2242 eclass = stm.eclass;
2247 public override void Emit (EmitContext ec)
2252 public override void EmitStatement (EmitContext ec)
2254 stm.EmitStatement (ec);
2257 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2259 stm.MutateHoistedGenericType (storey);
2263 readonly Expression expr, orig_expr;
2265 private ReducedExpression (Expression expr, Expression orig_expr)
2268 this.orig_expr = orig_expr;
2269 this.loc = orig_expr.Location;
2272 public static Constant Create (Constant expr, Expression original_expr)
2274 return new ReducedConstantExpression (expr, original_expr);
2277 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
2279 return new ReducedExpressionStatement (s, orig);
2282 public static Expression Create (Expression expr, Expression original_expr)
2284 Constant c = expr as Constant;
2286 return Create (c, original_expr);
2288 ExpressionStatement s = expr as ExpressionStatement;
2290 return Create (s, original_expr);
2292 return new ReducedExpression (expr, original_expr);
2295 public override Expression CreateExpressionTree (ResolveContext ec)
2297 return orig_expr.CreateExpressionTree (ec);
2300 public override Expression DoResolve (ResolveContext ec)
2302 eclass = expr.eclass;
2307 public override void Emit (EmitContext ec)
2312 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2314 expr.EmitBranchable (ec, target, on_true);
2318 public override SLE.Expression MakeExpression (BuilderContext ctx)
2320 return orig_expr.MakeExpression (ctx);
2324 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2326 expr.MutateHoistedGenericType (storey);
2331 // Base of expressions used only to narrow resolve flow
2333 public abstract class ShimExpression : Expression
2335 protected Expression expr;
2337 protected ShimExpression (Expression expr)
2342 protected override void CloneTo (CloneContext clonectx, Expression t)
2347 ShimExpression target = (ShimExpression) t;
2348 target.expr = expr.Clone (clonectx);
2351 public override Expression CreateExpressionTree (ResolveContext ec)
2353 throw new NotSupportedException ("ET");
2356 public override void Emit (EmitContext ec)
2358 throw new InternalErrorException ("Missing Resolve call");
2361 public Expression Expr {
2362 get { return expr; }
2365 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2367 throw new InternalErrorException ("Missing Resolve call");
2372 // Unresolved type name expressions
2374 public abstract class ATypeNameExpression : FullNamedExpression
2377 protected TypeArguments targs;
2379 protected ATypeNameExpression (string name, Location l)
2385 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2392 public bool HasTypeArguments {
2394 return targs != null;
2398 public override bool Equals (object obj)
2400 ATypeNameExpression atne = obj as ATypeNameExpression;
2401 return atne != null && atne.Name == Name &&
2402 (targs == null || targs.Equals (atne.targs));
2405 public override int GetHashCode ()
2407 return Name.GetHashCode ();
2410 public override string GetSignatureForError ()
2412 if (targs != null) {
2413 return TypeManager.RemoveGenericArity (Name) + "<" +
2414 targs.GetSignatureForError () + ">";
2420 public string Name {
2429 public TypeArguments TypeArguments {
2437 /// SimpleName expressions are formed of a single word and only happen at the beginning
2438 /// of a dotted-name.
2440 public class SimpleName : ATypeNameExpression {
2443 public SimpleName (string name, Location l)
2448 public SimpleName (string name, TypeArguments args, Location l)
2449 : base (name, args, l)
2453 public SimpleName (string name, TypeParameter[] type_params, Location l)
2456 targs = new TypeArguments ();
2457 foreach (TypeParameter type_param in type_params)
2458 targs.Add (new TypeParameterExpr (type_param, l));
2461 public static string RemoveGenericArity (string name)
2464 StringBuilder sb = null;
2466 int pos = name.IndexOf ('`', start);
2471 sb.Append (name.Substring (start));
2476 sb = new StringBuilder ();
2477 sb.Append (name.Substring (start, pos-start));
2480 while ((pos < name.Length) && Char.IsNumber (name [pos]))
2484 } while (start < name.Length);
2486 return sb.ToString ();
2489 public SimpleName GetMethodGroup ()
2491 return new SimpleName (RemoveGenericArity (Name), targs, loc);
2494 public static void Error_ObjectRefRequired (ResolveContext ec, Location l, string name)
2496 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope))
2497 ec.Report.Error (236, l,
2498 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2501 ec.Report.Error (120, l,
2502 "An object reference is required to access non-static member `{0}'",
2506 public bool IdenticalNameAndTypeName (IMemberContext mc, Expression resolved_to, Location loc)
2508 return resolved_to != null && resolved_to.Type != null &&
2509 resolved_to.Type.Name == Name &&
2510 (mc.LookupNamespaceOrType (Name, loc, /* ignore_cs0104 = */ true) != null);
2513 public override Expression DoResolve (ResolveContext ec)
2515 return SimpleNameResolve (ec, null, false);
2518 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2520 return SimpleNameResolve (ec, right_side, false);
2524 public Expression DoResolve (ResolveContext ec, bool intermediate)
2526 return SimpleNameResolve (ec, null, intermediate);
2529 static bool IsNestedChild (Type t, Type parent)
2531 while (parent != null) {
2532 if (TypeManager.IsNestedChildOf (t, TypeManager.DropGenericTypeArguments (parent)))
2535 parent = parent.BaseType;
2541 FullNamedExpression ResolveNested (Type t)
2543 if (!TypeManager.IsGenericTypeDefinition (t) && !TypeManager.IsGenericType (t))
2547 while (ds != null && !IsNestedChild (t, ds))
2548 ds = ds.DeclaringType;
2553 Type[] gen_params = TypeManager.GetTypeArguments (t);
2555 int arg_count = targs != null ? targs.Count : 0;
2557 for (; (ds != null) && TypeManager.IsGenericType (ds); ds = ds.DeclaringType) {
2558 Type[] gargs = TypeManager.GetTypeArguments (ds);
2559 if (arg_count + gargs.Length == gen_params.Length) {
2560 TypeArguments new_args = new TypeArguments ();
2561 foreach (Type param in gargs)
2562 new_args.Add (new TypeExpression (param, loc));
2565 new_args.Add (targs);
2567 return new GenericTypeExpr (t, new_args, loc);
2574 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2576 int errors = ec.Compiler.Report.Errors;
2577 FullNamedExpression fne = ec.LookupNamespaceOrType (Name, loc, /*ignore_cs0104=*/ false);
2580 if (fne.Type == null)
2583 FullNamedExpression nested = ResolveNested (fne.Type);
2585 return nested.ResolveAsTypeStep (ec, false);
2587 if (targs != null) {
2588 if (TypeManager.IsGenericType (fne.Type)) {
2589 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2590 return ct.ResolveAsTypeStep (ec, false);
2593 fne.Error_TypeArgumentsCannotBeUsed (ec.Compiler.Report, loc);
2599 if (!HasTypeArguments && Name == "dynamic" && RootContext.Version > LanguageVersion.V_3)
2600 return new DynamicTypeExpr (loc);
2602 if (silent || errors != ec.Compiler.Report.Errors)
2605 Error_TypeOrNamespaceNotFound (ec);
2609 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ec)
2611 if (ec.CurrentType != null) {
2612 if (ec.CurrentTypeDefinition != null) {
2613 MemberCore mc = ec.CurrentTypeDefinition.GetDefinition (Name);
2615 Error_UnexpectedKind (ec.Compiler.Report, mc, "type", GetMemberType (mc), loc);
2620 string ns = ec.CurrentType.Namespace;
2621 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2622 foreach (Assembly a in GlobalRootNamespace.Instance.Assemblies) {
2623 Type type = a.GetType (fullname);
2625 ec.Compiler.Report.SymbolRelatedToPreviousError (type);
2626 Expression.ErrorIsInaccesible (loc, TypeManager.CSharpName (type), ec.Compiler.Report);
2631 if (ec.CurrentTypeDefinition != null) {
2632 Type t = ec.CurrentTypeDefinition.LookupAnyGeneric (Name);
2634 Namespace.Error_InvalidNumberOfTypeArguments (t, loc);
2640 if (targs != null) {
2641 FullNamedExpression retval = ec.LookupNamespaceOrType (SimpleName.RemoveGenericArity (Name), loc, true);
2642 if (retval != null) {
2643 retval.Error_TypeArgumentsCannotBeUsed (ec.Compiler.Report, loc);
2648 NamespaceEntry.Error_NamespaceNotFound (loc, Name, ec.Compiler.Report);
2651 // TODO: I am still not convinced about this. If someone else will need it
2652 // implement this as virtual property in MemberCore hierarchy
2653 public static string GetMemberType (MemberCore mc)
2659 if (mc is FieldBase)
2661 if (mc is MethodCore)
2663 if (mc is EnumMember)
2671 Expression SimpleNameResolve (ResolveContext ec, Expression right_side, bool intermediate)
2677 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2683 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2690 /// 7.5.2: Simple Names.
2692 /// Local Variables and Parameters are handled at
2693 /// parse time, so they never occur as SimpleNames.
2695 /// The `intermediate' flag is used by MemberAccess only
2696 /// and it is used to inform us that it is ok for us to
2697 /// avoid the static check, because MemberAccess might end
2698 /// up resolving the Name as a Type name and the access as
2699 /// a static type access.
2701 /// ie: Type Type; .... { Type.GetType (""); }
2703 /// Type is both an instance variable and a Type; Type.GetType
2704 /// is the static method not an instance method of type.
2706 Expression DoSimpleNameResolve (ResolveContext ec, Expression right_side, bool intermediate)
2708 Expression e = null;
2711 // Stage 1: Performed by the parser (binding to locals or parameters).
2713 Block current_block = ec.CurrentBlock;
2714 if (current_block != null){
2715 LocalInfo vi = current_block.GetLocalInfo (Name);
2717 e = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2719 if (right_side != null) {
2720 e = e.ResolveLValue (ec, right_side);
2722 ResolveFlags rf = ResolveFlags.VariableOrValue;
2724 rf |= ResolveFlags.DisableFlowAnalysis;
2726 e = e.Resolve (ec, rf);
2729 if (targs != null && e != null)
2730 e.Error_TypeArgumentsCannotBeUsed (ec.Report, loc);
2735 e = current_block.Toplevel.GetParameterReference (Name, loc);
2737 if (right_side != null)
2738 e = e.ResolveLValue (ec, right_side);
2742 if (targs != null && e != null)
2743 e.Error_TypeArgumentsCannotBeUsed (ec.Report, loc);
2750 // Stage 2: Lookup members
2753 Type almost_matched_type = null;
2754 ArrayList almost_matched = null;
2755 for (Type lookup_ds = ec.CurrentType; lookup_ds != null; lookup_ds = lookup_ds.DeclaringType) {
2756 e = MemberLookup (ec.Compiler, ec.CurrentType, lookup_ds, Name, loc);
2758 PropertyExpr pe = e as PropertyExpr;
2760 AParametersCollection param = TypeManager.GetParameterData (pe.PropertyInfo);
2762 // since TypeManager.MemberLookup doesn't know if we're doing a lvalue access or not,
2763 // it doesn't know which accessor to check permissions against
2764 if (param.IsEmpty && pe.IsAccessibleFrom (ec.CurrentType, right_side != null))
2766 } else if (e is EventExpr) {
2767 if (((EventExpr) e).IsAccessibleFrom (ec.CurrentType))
2769 } else if (targs != null && e is TypeExpression) {
2770 e = new GenericTypeExpr (e.Type, targs, loc).ResolveAsTypeStep (ec, false);
2778 if (almost_matched == null && almost_matched_members.Count > 0) {
2779 almost_matched_type = lookup_ds;
2780 almost_matched = (ArrayList) almost_matched_members.Clone ();
2785 if (almost_matched == null && almost_matched_members.Count > 0) {
2786 almost_matched_type = ec.CurrentType;
2787 almost_matched = (ArrayList) almost_matched_members.Clone ();
2789 e = ResolveAsTypeStep (ec, true);
2793 if (current_block != null) {
2794 IKnownVariable ikv = current_block.Explicit.GetKnownVariable (Name);
2796 LocalInfo li = ikv as LocalInfo;
2797 // Supress CS0219 warning
2801 Error_VariableIsUsedBeforeItIsDeclared (ec.Report, Name);
2806 if (RootContext.EvalMode){
2807 FieldInfo fi = Evaluator.LookupField (Name);
2809 return new FieldExpr (fi, loc).Resolve (ec);
2812 if (almost_matched != null)
2813 almost_matched_members = almost_matched;
2814 if (almost_matched_type == null)
2815 almost_matched_type = ec.CurrentType;
2817 string type_name = ec.MemberContext.CurrentType == null ? null : ec.MemberContext.CurrentType.Name;
2818 return Error_MemberLookupFailed (ec, ec.CurrentType, null, almost_matched_type, Name,
2819 type_name, AllMemberTypes, AllBindingFlags);
2822 if (e is MemberExpr) {
2823 MemberExpr me = (MemberExpr) e;
2826 if (me.IsInstance) {
2827 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope)) {
2829 // Note that an MemberExpr can be both IsInstance and IsStatic.
2830 // An unresolved MethodGroupExpr can contain both kinds of methods
2831 // and each predicate is true if the MethodGroupExpr contains
2832 // at least one of that kind of method.
2836 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2837 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2842 // Pass the buck to MemberAccess and Invocation.
2844 left = EmptyExpression.Null;
2846 left = ec.GetThis (loc);
2849 left = new TypeExpression (ec.CurrentType, loc);
2852 me = me.ResolveMemberAccess (ec, left, loc, null);
2856 if (targs != null) {
2857 if (!targs.Resolve (ec))
2860 me.SetTypeArguments (ec, targs);
2863 if (!me.IsStatic && (me.InstanceExpression != null && me.InstanceExpression != EmptyExpression.Null) &&
2864 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2865 me.InstanceExpression.Type != me.DeclaringType &&
2866 !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2867 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2868 ec.Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2869 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2873 return (right_side != null)
2874 ? me.DoResolveLValue (ec, right_side)
2875 : me.DoResolve (ec);
2883 /// Represents a namespace or a type. The name of the class was inspired by
2884 /// section 10.8.1 (Fully Qualified Names).
2886 public abstract class FullNamedExpression : Expression
2888 protected override void CloneTo (CloneContext clonectx, Expression target)
2890 // Do nothing, most unresolved type expressions cannot be
2891 // resolved to different type
2894 public override Expression CreateExpressionTree (ResolveContext ec)
2896 throw new NotSupportedException ("ET");
2899 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2901 throw new NotSupportedException ();
2904 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2909 public override void Emit (EmitContext ec)
2911 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2912 GetSignatureForError ());
2917 /// Expression that evaluates to a type
2919 public abstract class TypeExpr : FullNamedExpression {
2920 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2922 TypeExpr t = DoResolveAsTypeStep (ec);
2926 eclass = ExprClass.Type;
2930 override public Expression DoResolve (ResolveContext ec)
2932 return ResolveAsTypeTerminal (ec, false);
2935 public virtual bool CheckAccessLevel (IMemberContext mc)
2937 return mc.CurrentTypeDefinition.CheckAccessLevel (Type);
2940 public virtual bool IsClass {
2941 get { return Type.IsClass; }
2944 public virtual bool IsValueType {
2945 get { return TypeManager.IsStruct (Type); }
2948 public virtual bool IsInterface {
2949 get { return Type.IsInterface; }
2952 public virtual bool IsSealed {
2953 get { return Type.IsSealed; }
2956 public virtual bool CanInheritFrom ()
2958 if (Type == TypeManager.enum_type ||
2959 (Type == TypeManager.value_type && RootContext.StdLib) ||
2960 Type == TypeManager.multicast_delegate_type ||
2961 Type == TypeManager.delegate_type ||
2962 Type == TypeManager.array_type)
2968 protected abstract TypeExpr DoResolveAsTypeStep (IMemberContext ec);
2970 public override bool Equals (object obj)
2972 TypeExpr tobj = obj as TypeExpr;
2976 return Type == tobj.Type;
2979 public override int GetHashCode ()
2981 return Type.GetHashCode ();
2984 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2986 type = storey.MutateType (type);
2991 /// Fully resolved Expression that already evaluated to a type
2993 public class TypeExpression : TypeExpr {
2994 public TypeExpression (Type t, Location l)
2997 eclass = ExprClass.Type;
3001 protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec)
3006 public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
3013 // Used to create types from a fully qualified name. These are just used
3014 // by the parser to setup the core types.
3016 public sealed class TypeLookupExpression : TypeExpr {
3017 readonly string ns_name;
3018 readonly string name;
3020 public TypeLookupExpression (string ns, string name)
3024 eclass = ExprClass.Type;
3027 public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
3030 // It's null only during mscorlib bootstrap when DefineType
3031 // nees to resolve base type of same type
3033 // For instance struct Char : IComparable<char>
3035 // TODO: it could be removed when Resolve starts to use
3036 // DeclSpace instead of Type
3039 Namespace ns = GlobalRootNamespace.Instance.GetNamespace (ns_name, false);
3040 FullNamedExpression fne = ns.Lookup (ec.Compiler, name, loc);
3048 protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec)
3053 public override string GetSignatureForError ()
3056 return TypeManager.CSharpName (ns_name + "." + name, null);
3058 return base.GetSignatureForError ();
3063 /// This class denotes an expression which evaluates to a member
3064 /// of a struct or a class.
3066 public abstract class MemberExpr : Expression
3068 protected bool is_base;
3071 /// The name of this member.
3073 public abstract string Name {
3078 // When base.member is used
3080 public bool IsBase {
3081 get { return is_base; }
3082 set { is_base = value; }
3086 /// Whether this is an instance member.
3088 public abstract bool IsInstance {
3093 /// Whether this is a static member.
3095 public abstract bool IsStatic {
3100 /// The type which declares this member.
3102 public abstract Type DeclaringType {
3107 /// The instance expression associated with this member, if it's a
3108 /// non-static member.
3110 public Expression InstanceExpression;
3112 public static void error176 (ResolveContext ec, Location loc, string name)
3114 ec.Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
3115 "with an instance reference, qualify it with a type name instead", name);
3118 public static void Error_BaseAccessInExpressionTree (ResolveContext ec, Location loc)
3120 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
3123 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3125 if (InstanceExpression != null)
3126 InstanceExpression.MutateHoistedGenericType (storey);
3129 // TODO: possible optimalization
3130 // Cache resolved constant result in FieldBuilder <-> expression map
3131 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, Location loc,
3132 SimpleName original)
3136 // original == null || original.Resolve (...) ==> left
3139 if (left is TypeExpr) {
3140 left = left.ResolveAsBaseTerminal (ec, false);
3144 // TODO: Same problem as in class.cs, TypeTerminal does not
3145 // always do all necessary checks
3146 ObsoleteAttribute oa = AttributeTester.GetObsoleteAttribute (left.Type);
3147 if (oa != null && !ec.IsObsolete) {
3148 AttributeTester.Report_ObsoleteMessage (oa, left.GetSignatureForError (), loc, ec.Report);
3151 GenericTypeExpr ct = left as GenericTypeExpr;
3152 if (ct != null && !ct.CheckConstraints (ec))
3157 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3165 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3168 return ResolveExtensionMemberAccess (ec, left);
3171 InstanceExpression = left;
3175 protected virtual MemberExpr ResolveExtensionMemberAccess (ResolveContext ec, Expression left)
3177 error176 (ec, loc, GetSignatureForError ());
3181 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3186 if (InstanceExpression == EmptyExpression.Null) {
3187 // FIXME: This should not be here at all
3188 SimpleName.Error_ObjectRefRequired (new ResolveContext (ec.MemberContext), loc, GetSignatureForError ());
3192 if (TypeManager.IsValueType (InstanceExpression.Type)) {
3193 if (InstanceExpression is IMemoryLocation) {
3194 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
3196 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
3197 InstanceExpression.Emit (ec);
3199 t.AddressOf (ec, AddressOp.Store);
3202 InstanceExpression.Emit (ec);
3204 if (prepare_for_load)
3205 ec.ig.Emit (OpCodes.Dup);
3208 public virtual void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3210 // TODO: need to get correct member type
3211 ec.Report.Error (307, loc, "The property `{0}' cannot be used with type arguments",
3212 GetSignatureForError ());
3217 /// Represents group of extension methods
3219 public class ExtensionMethodGroupExpr : MethodGroupExpr
3221 readonly NamespaceEntry namespace_entry;
3222 public Expression ExtensionExpression;
3223 Argument extension_argument;
3225 public ExtensionMethodGroupExpr (ArrayList list, NamespaceEntry n, Type extensionType, Location l)
3226 : base (list, extensionType, l)
3228 this.namespace_entry = n;
3231 public override bool IsStatic {
3232 get { return true; }
3235 public bool IsTopLevel {
3236 get { return namespace_entry == null; }
3239 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3241 extension_argument.Expr.MutateHoistedGenericType (storey);
3242 base.MutateHoistedGenericType (storey);
3245 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, bool may_fail, Location loc)
3247 if (arguments == null)
3248 arguments = new Arguments (1);
3250 arguments.Insert (0, new Argument (ExtensionExpression));
3251 MethodGroupExpr mg = ResolveOverloadExtensions (ec, ref arguments, namespace_entry, loc);
3253 // Store resolved argument and restore original arguments
3255 ((ExtensionMethodGroupExpr)mg).extension_argument = arguments [0];
3257 arguments.RemoveAt (0); // Clean-up modified arguments for error reporting
3262 MethodGroupExpr ResolveOverloadExtensions (ResolveContext ec, ref Arguments arguments, NamespaceEntry ns, Location loc)
3264 // Use normal resolve rules
3265 MethodGroupExpr mg = base.OverloadResolve (ec, ref arguments, ns != null, loc);
3273 ExtensionMethodGroupExpr e = ns.LookupExtensionMethod (type, Name, loc);
3275 return base.OverloadResolve (ec, ref arguments, false, loc);
3277 e.ExtensionExpression = ExtensionExpression;
3278 e.SetTypeArguments (ec, type_arguments);
3279 return e.ResolveOverloadExtensions (ec, ref arguments, e.namespace_entry, loc);
3284 /// MethodGroupExpr represents a group of method candidates which
3285 /// can be resolved to the best method overload
3287 public class MethodGroupExpr : MemberExpr
3289 public interface IErrorHandler
3291 bool AmbiguousCall (ResolveContext ec, MethodBase ambiguous);
3292 bool NoExactMatch (ResolveContext ec, MethodBase method);
3295 public IErrorHandler CustomErrorHandler;
3296 public MethodBase [] Methods;
3297 MethodBase best_candidate;
3298 // TODO: make private
3299 public TypeArguments type_arguments;
3300 bool identical_type_name;
3301 bool has_inaccessible_candidates_only;
3305 public MethodGroupExpr (MemberInfo [] mi, Type type, Location l)
3308 Methods = new MethodBase [mi.Length];
3309 mi.CopyTo (Methods, 0);
3312 public MethodGroupExpr (MemberInfo[] mi, Type type, Location l, bool inacessibleCandidatesOnly)
3313 : this (mi, type, l)
3315 has_inaccessible_candidates_only = inacessibleCandidatesOnly;
3318 public MethodGroupExpr (ArrayList list, Type type, Location l)
3322 Methods = (MethodBase[])list.ToArray (typeof (MethodBase));
3324 foreach (MemberInfo m in list){
3325 if (!(m is MethodBase)){
3326 Console.WriteLine ("Name " + m.Name);
3327 Console.WriteLine ("Found a: " + m.GetType ().FullName);
3336 protected MethodGroupExpr (Type type, Location loc)
3339 eclass = ExprClass.MethodGroup;
3340 this.type = InternalType.MethodGroup;
3341 queried_type = type;
3344 public override Type DeclaringType {
3346 return queried_type;
3350 public Type DelegateType {
3352 delegate_type = value;
3356 public bool IdenticalTypeName {
3358 return identical_type_name;
3362 public override string GetSignatureForError ()
3364 if (best_candidate != null)
3365 return TypeManager.CSharpSignature (best_candidate);
3367 return TypeManager.CSharpSignature (Methods [0]);
3370 public override string Name {
3372 return Methods [0].Name;
3376 public override bool IsInstance {
3378 if (best_candidate != null)
3379 return !best_candidate.IsStatic;
3381 foreach (MethodBase mb in Methods)
3389 public override bool IsStatic {
3391 if (best_candidate != null)
3392 return best_candidate.IsStatic;
3394 foreach (MethodBase mb in Methods)
3402 public static explicit operator ConstructorInfo (MethodGroupExpr mg)
3404 return (ConstructorInfo)mg.best_candidate;
3407 public static explicit operator MethodInfo (MethodGroupExpr mg)
3409 return (MethodInfo)mg.best_candidate;
3413 // 7.4.3.3 Better conversion from expression
3414 // Returns : 1 if a->p is better,
3415 // 2 if a->q is better,
3416 // 0 if neither is better
3418 static int BetterExpressionConversion (ResolveContext ec, Argument a, Type p, Type q)
3420 Type argument_type = TypeManager.TypeToCoreType (a.Type);
3421 if (argument_type == InternalType.AnonymousMethod && RootContext.Version > LanguageVersion.ISO_2) {
3423 // Uwrap delegate from Expression<T>
3425 if (TypeManager.DropGenericTypeArguments (p) == TypeManager.expression_type) {
3426 p = TypeManager.GetTypeArguments (p) [0];
3428 if (TypeManager.DropGenericTypeArguments (q) == TypeManager.expression_type) {
3429 q = TypeManager.GetTypeArguments (q) [0];
3432 p = Delegate.GetInvokeMethod (ec.Compiler, null, p).ReturnType;
3433 q = Delegate.GetInvokeMethod (ec.Compiler, null, q).ReturnType;
3434 if (p == TypeManager.void_type && q != TypeManager.void_type)
3436 if (q == TypeManager.void_type && p != TypeManager.void_type)
3439 if (argument_type == p)
3442 if (argument_type == q)
3446 return BetterTypeConversion (ec, p, q);
3450 // 7.4.3.4 Better conversion from type
3452 public static int BetterTypeConversion (ResolveContext ec, Type p, Type q)
3454 if (p == null || q == null)
3455 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3457 if (p == TypeManager.int32_type) {
3458 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3460 } else if (p == TypeManager.int64_type) {
3461 if (q == TypeManager.uint64_type)
3463 } else if (p == TypeManager.sbyte_type) {
3464 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3465 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3467 } else if (p == TypeManager.short_type) {
3468 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3469 q == TypeManager.uint64_type)
3473 if (q == TypeManager.int32_type) {
3474 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3476 } if (q == TypeManager.int64_type) {
3477 if (p == TypeManager.uint64_type)
3479 } else if (q == TypeManager.sbyte_type) {
3480 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3481 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3483 } if (q == TypeManager.short_type) {
3484 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3485 p == TypeManager.uint64_type)
3489 // TODO: this is expensive
3490 Expression p_tmp = new EmptyExpression (p);
3491 Expression q_tmp = new EmptyExpression (q);
3493 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3494 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3496 if (p_to_q && !q_to_p)
3499 if (q_to_p && !p_to_q)
3506 /// Determines "Better function" between candidate
3507 /// and the current best match
3510 /// Returns a boolean indicating :
3511 /// false if candidate ain't better
3512 /// true if candidate is better than the current best match
3514 static bool BetterFunction (ResolveContext ec, Arguments args, int argument_count,
3515 MethodBase candidate, bool candidate_params,
3516 MethodBase best, bool best_params)
3518 AParametersCollection candidate_pd = TypeManager.GetParameterData (candidate);
3519 AParametersCollection best_pd = TypeManager.GetParameterData (best);
3521 bool better_at_least_one = false;
3523 for (int j = 0, c_idx = 0, b_idx = 0; j < argument_count; ++j, ++c_idx, ++b_idx)
3525 Argument a = args [j];
3527 // Provided default argument value is never better
3528 if (a.IsDefaultArgument && candidate_params == best_params)
3531 Type ct = candidate_pd.Types [c_idx];
3532 Type bt = best_pd.Types [b_idx];
3534 if (candidate_params && candidate_pd.FixedParameters [c_idx].ModFlags == Parameter.Modifier.PARAMS)
3536 ct = TypeManager.GetElementType (ct);
3540 if (best_params && best_pd.FixedParameters [b_idx].ModFlags == Parameter.Modifier.PARAMS)
3542 bt = TypeManager.GetElementType (bt);
3550 int result = BetterExpressionConversion (ec, a, ct, bt);
3552 // for each argument, the conversion to 'ct' should be no worse than
3553 // the conversion to 'bt'.
3557 // for at least one argument, the conversion to 'ct' should be better than
3558 // the conversion to 'bt'.
3560 better_at_least_one = true;
3563 if (better_at_least_one)
3567 // This handles the case
3569 // Add (float f1, float f2, float f3);
3570 // Add (params decimal [] foo);
3572 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3573 // first candidate would've chosen as better.
3579 // The two methods have equal parameter types. Now apply tie-breaking rules
3581 if (TypeManager.IsGenericMethod (best)) {
3582 if (!TypeManager.IsGenericMethod (candidate))
3584 } else if (TypeManager.IsGenericMethod (candidate)) {
3589 // This handles the following cases:
3591 // Trim () is better than Trim (params char[] chars)
3592 // Concat (string s1, string s2, string s3) is better than
3593 // Concat (string s1, params string [] srest)
3594 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3596 if (!candidate_params && best_params)
3598 if (candidate_params && !best_params)
3601 int candidate_param_count = candidate_pd.Count;
3602 int best_param_count = best_pd.Count;
3604 if (candidate_param_count != best_param_count)
3605 // can only happen if (candidate_params && best_params)
3606 return candidate_param_count > best_param_count && best_pd.HasParams;
3609 // now, both methods have the same number of parameters, and the parameters have the same types
3610 // Pick the "more specific" signature
3613 MethodBase orig_candidate = TypeManager.DropGenericMethodArguments (candidate);
3614 MethodBase orig_best = TypeManager.DropGenericMethodArguments (best);
3616 AParametersCollection orig_candidate_pd = TypeManager.GetParameterData (orig_candidate);
3617 AParametersCollection orig_best_pd = TypeManager.GetParameterData (orig_best);
3619 bool specific_at_least_once = false;
3620 for (int j = 0; j < candidate_param_count; ++j)
3622 Type ct = orig_candidate_pd.Types [j];
3623 Type bt = orig_best_pd.Types [j];
3626 Type specific = MoreSpecific (ct, bt);
3630 specific_at_least_once = true;
3633 if (specific_at_least_once)
3636 // FIXME: handle lifted operators
3642 protected override MemberExpr ResolveExtensionMemberAccess (ResolveContext ec, Expression left)
3645 return base.ResolveExtensionMemberAccess (ec, left);
3648 // When left side is an expression and at least one candidate method is
3649 // static, it can be extension method
3651 InstanceExpression = left;
3655 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, Location loc,
3656 SimpleName original)
3658 if (!(left is TypeExpr) &&
3659 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3660 identical_type_name = true;
3662 return base.ResolveMemberAccess (ec, left, loc, original);
3665 public override Expression CreateExpressionTree (ResolveContext ec)
3667 if (best_candidate == null) {
3668 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3672 IMethodData md = TypeManager.GetMethod (best_candidate);
3673 if (md != null && md.IsExcluded ())
3674 ec.Report.Error (765, loc,
3675 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3677 return new TypeOfMethod (best_candidate, loc);
3680 override public Expression DoResolve (ResolveContext ec)
3682 if (InstanceExpression != null) {
3683 InstanceExpression = InstanceExpression.DoResolve (ec);
3684 if (InstanceExpression == null)
3691 public void ReportUsageError (ResolveContext ec)
3693 ec.Report.Error (654, loc, "Method `" + DeclaringType + "." +
3694 Name + "()' is referenced without parentheses");
3697 override public void Emit (EmitContext ec)
3699 throw new NotSupportedException ();
3700 // ReportUsageError ();
3703 public void EmitCall (EmitContext ec, Arguments arguments)
3705 Invocation.EmitCall (ec, IsBase, InstanceExpression, best_candidate, arguments, loc);
3708 void Error_AmbiguousCall (ResolveContext ec, MethodBase ambiguous)
3710 if (CustomErrorHandler != null && CustomErrorHandler.AmbiguousCall (ec, ambiguous))
3713 ec.Report.SymbolRelatedToPreviousError (best_candidate);
3714 ec.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
3715 TypeManager.CSharpSignature (ambiguous), TypeManager.CSharpSignature (best_candidate));
3718 protected virtual void Error_InvalidArguments (ResolveContext ec, Location loc, int idx, MethodBase method,
3719 Argument a, AParametersCollection expected_par, Type paramType)
3721 ExtensionMethodGroupExpr emg = this as ExtensionMethodGroupExpr;
3723 if (a is CollectionElementInitializer.ElementInitializerArgument) {
3724 ec.Report.SymbolRelatedToPreviousError (method);
3725 if ((expected_par.FixedParameters [idx].ModFlags & Parameter.Modifier.ISBYREF) != 0) {
3726 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
3727 TypeManager.CSharpSignature (method));
3730 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
3731 TypeManager.CSharpSignature (method));
3732 } else if (TypeManager.IsDelegateType (method.DeclaringType)) {
3733 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
3734 TypeManager.CSharpName (method.DeclaringType));
3736 ec.Report.SymbolRelatedToPreviousError (method);
3738 ec.Report.Error (1928, loc,
3739 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3740 emg.ExtensionExpression.GetSignatureForError (),
3741 emg.Name, TypeManager.CSharpSignature (method));
3743 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
3744 TypeManager.CSharpSignature (method));
3748 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters [idx].ModFlags;
3750 string index = (idx + 1).ToString ();
3751 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
3752 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
3753 if ((mod & Parameter.Modifier.ISBYREF) == 0)
3754 ec.Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
3755 index, Parameter.GetModifierSignature (a.Modifier));
3757 ec.Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
3758 index, Parameter.GetModifierSignature (mod));
3760 string p1 = a.GetSignatureForError ();
3761 string p2 = TypeManager.CSharpName (paramType);
3764 ec.Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
3765 ec.Report.SymbolRelatedToPreviousError (a.Expr.Type);
3766 ec.Report.SymbolRelatedToPreviousError (paramType);
3769 if (idx == 0 && emg != null) {
3770 ec.Report.Error (1929, loc,
3771 "Extension method instance type `{0}' cannot be converted to `{1}'", p1, p2);
3773 ec.Report.Error (1503, loc,
3774 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
3779 public override void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, Type target, bool expl)
3781 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3782 Name, TypeManager.CSharpName (target));
3785 void Error_ArgumentCountWrong (ResolveContext ec, int arg_count)
3787 ec.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
3788 Name, arg_count.ToString ());
3791 protected virtual int GetApplicableParametersCount (MethodBase method, AParametersCollection parameters)
3793 return parameters.Count;
3796 public static bool IsAncestralType (Type first_type, Type second_type)
3798 return first_type != second_type &&
3799 (TypeManager.IsSubclassOf (second_type, first_type) ||
3800 TypeManager.ImplementsInterface (second_type, first_type));
3804 /// Determines if the candidate method is applicable (section 14.4.2.1)
3805 /// to the given set of arguments
3806 /// A return value rates candidate method compatibility,
3807 /// 0 = the best, int.MaxValue = the worst
3809 public int IsApplicable (ResolveContext ec,
3810 ref Arguments arguments, int arg_count, ref MethodBase method, ref bool params_expanded_form)
3812 MethodBase candidate = method;
3814 AParametersCollection pd = TypeManager.GetParameterData (candidate);
3815 int param_count = GetApplicableParametersCount (candidate, pd);
3816 int optional_count = 0;
3818 if (arg_count != param_count) {
3819 for (int i = 0; i < pd.Count; ++i) {
3820 if (pd.FixedParameters [i].HasDefaultValue) {
3821 optional_count = pd.Count - i;
3826 int args_gap = Math.Abs (arg_count - param_count);
3827 if (optional_count != 0) {
3828 if (args_gap > optional_count)
3829 return int.MaxValue - 10000 + args_gap - optional_count;
3831 // Readjust expected number when params used
3834 if (arg_count < param_count)
3836 } else if (arg_count > param_count) {
3837 return int.MaxValue - 10000 + args_gap;
3839 } else if (arg_count != param_count) {
3841 return int.MaxValue - 10000 + args_gap;
3842 if (arg_count < param_count - 1)
3843 return int.MaxValue - 10000 + args_gap;
3846 // Initialize expanded form of a method with 1 params parameter
3847 params_expanded_form = param_count == 1 && pd.HasParams;
3849 // Resize to fit optional arguments
3850 if (optional_count != 0) {
3852 if (arguments == null) {
3853 resized = new Arguments (optional_count);
3855 resized = new Arguments (param_count);
3856 resized.AddRange (arguments);
3859 for (int i = arg_count; i < param_count; ++i)
3861 arguments = resized;
3865 if (arg_count > 0) {
3867 // Shuffle named arguments to the right positions if there are any
3869 if (arguments [arg_count - 1] is NamedArgument) {
3870 arg_count = arguments.Count;
3872 for (int i = 0; i < arg_count; ++i) {
3873 bool arg_moved = false;
3875 NamedArgument na = arguments[i] as NamedArgument;
3879 int index = pd.GetParameterIndexByName (na.Name.Value);
3881 // Named parameter not found or already reordered
3885 // When using parameters which should not be available to the user
3886 if (index >= param_count)
3890 arguments.MarkReorderedArgument (na);
3894 Argument temp = arguments[index];
3895 arguments[index] = arguments[i];
3896 arguments[i] = temp;
3903 arg_count = arguments.Count;
3905 } else if (arguments != null) {
3906 arg_count = arguments.Count;
3910 // 1. Handle generic method using type arguments when specified or type inference
3912 if (TypeManager.IsGenericMethod (candidate)) {
3913 if (type_arguments != null) {
3914 Type [] g_args = candidate.GetGenericArguments ();
3915 if (g_args.Length != type_arguments.Count)
3916 return int.MaxValue - 20000 + Math.Abs (type_arguments.Count - g_args.Length);
3918 // TODO: Don't create new method, create Parameters only
3919 method = ((MethodInfo) candidate).MakeGenericMethod (type_arguments.Arguments);
3921 pd = TypeManager.GetParameterData (candidate);
3923 int score = TypeManager.InferTypeArguments (ec, arguments, ref candidate);
3925 return score - 20000;
3927 if (TypeManager.IsGenericMethodDefinition (candidate))
3928 throw new InternalErrorException ("A generic method `{0}' definition took part in overload resolution",
3929 TypeManager.CSharpSignature (candidate));
3931 pd = TypeManager.GetParameterData (candidate);
3934 if (type_arguments != null)
3935 return int.MaxValue - 15000;
3939 // 2. Each argument has to be implicitly convertible to method parameter
3942 Parameter.Modifier p_mod = 0;
3944 for (int i = 0; i < arg_count; i++) {
3945 Argument a = arguments [i];
3947 if (!pd.FixedParameters [i].HasDefaultValue)
3948 throw new InternalErrorException ();
3950 Expression e = pd.FixedParameters [i].DefaultValue as Constant;
3952 e = new DefaultValueExpression (new TypeExpression (pd.Types [i], loc), loc).Resolve (ec);
3954 arguments [i] = new Argument (e, Argument.AType.Default);
3958 if (p_mod != Parameter.Modifier.PARAMS) {
3959 p_mod = pd.FixedParameters [i].ModFlags & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3962 params_expanded_form = true;
3965 Parameter.Modifier a_mod = a.Modifier & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3967 if (!params_expanded_form)
3968 score = IsArgumentCompatible (ec, a_mod, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
3970 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && delegate_type == null) {
3971 // It can be applicable in expanded form
3972 score = IsArgumentCompatible (ec, a_mod, a, 0, TypeManager.GetElementType (pt));
3974 params_expanded_form = true;
3978 if (params_expanded_form)
3980 return (arg_count - i) * 2 + score;
3984 if (arg_count != param_count)
3985 params_expanded_form = true;
3990 int IsArgumentCompatible (ResolveContext ec, Parameter.Modifier arg_mod, Argument argument, Parameter.Modifier param_mod, Type parameter)
3993 // Types have to be identical when ref or out modifer is used
3995 if (arg_mod != 0 || param_mod != 0) {
3996 if (TypeManager.HasElementType (parameter))
3997 parameter = TypeManager.GetElementType (parameter);
3999 Type a_type = argument.Type;
4000 if (TypeManager.HasElementType (a_type))
4001 a_type = TypeManager.GetElementType (a_type);
4003 if (a_type != parameter)
4006 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter))
4010 if (arg_mod != param_mod)
4016 public static bool IsOverride (MethodBase cand_method, MethodBase base_method)
4018 if (!IsAncestralType (base_method.DeclaringType, cand_method.DeclaringType))
4021 AParametersCollection cand_pd = TypeManager.GetParameterData (cand_method);
4022 AParametersCollection base_pd = TypeManager.GetParameterData (base_method);
4024 if (cand_pd.Count != base_pd.Count)
4027 for (int j = 0; j < cand_pd.Count; ++j)
4029 Parameter.Modifier cm = cand_pd.FixedParameters [j].ModFlags;
4030 Parameter.Modifier bm = base_pd.FixedParameters [j].ModFlags;
4031 Type ct = cand_pd.Types [j];
4032 Type bt = base_pd.Types [j];
4034 if (cm != bm || ct != bt)
4041 public static MethodGroupExpr MakeUnionSet (MethodGroupExpr mg1, MethodGroupExpr mg2, Location loc)
4052 ArrayList all = new ArrayList (mg1.Methods);
4053 foreach (MethodBase m in mg2.Methods){
4054 if (!TypeManager.ArrayContainsMethod (mg1.Methods, m, false))
4058 return new MethodGroupExpr (all, null, loc);
4061 static Type MoreSpecific (Type p, Type q)
4063 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4065 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4068 if (TypeManager.HasElementType (p))
4070 Type pe = TypeManager.GetElementType (p);
4071 Type qe = TypeManager.GetElementType (q);
4072 Type specific = MoreSpecific (pe, qe);
4078 else if (TypeManager.IsGenericType (p))
4080 Type[] pargs = TypeManager.GetTypeArguments (p);
4081 Type[] qargs = TypeManager.GetTypeArguments (q);
4083 bool p_specific_at_least_once = false;
4084 bool q_specific_at_least_once = false;
4086 for (int i = 0; i < pargs.Length; i++)
4088 Type specific = MoreSpecific (TypeManager.TypeToCoreType (pargs [i]), TypeManager.TypeToCoreType (qargs [i]));
4089 if (specific == pargs [i])
4090 p_specific_at_least_once = true;
4091 if (specific == qargs [i])
4092 q_specific_at_least_once = true;
4095 if (p_specific_at_least_once && !q_specific_at_least_once)
4097 if (!p_specific_at_least_once && q_specific_at_least_once)
4104 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4106 base.MutateHoistedGenericType (storey);
4108 MethodInfo mi = best_candidate as MethodInfo;
4110 best_candidate = storey.MutateGenericMethod (mi);
4114 best_candidate = storey.MutateConstructor ((ConstructorInfo) this);
4118 /// Find the Applicable Function Members (7.4.2.1)
4120 /// me: Method Group expression with the members to select.
4121 /// it might contain constructors or methods (or anything
4122 /// that maps to a method).
4124 /// Arguments: ArrayList containing resolved Argument objects.
4126 /// loc: The location if we want an error to be reported, or a Null
4127 /// location for "probing" purposes.
4129 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4130 /// that is the best match of me on Arguments.
4133 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments Arguments,
4134 bool may_fail, Location loc)
4136 bool method_params = false;
4137 Type applicable_type = null;
4138 ArrayList candidates = new ArrayList (2);
4139 ArrayList candidate_overrides = null;
4142 // Used to keep a map between the candidate
4143 // and whether it is being considered in its
4144 // normal or expanded form
4146 // false is normal form, true is expanded form
4148 Hashtable candidate_to_form = null;
4149 Hashtable candidates_expanded = null;
4150 Arguments candidate_args = Arguments;
4152 int arg_count = Arguments != null ? Arguments.Count : 0;
4154 if (RootContext.Version == LanguageVersion.ISO_1 && Name == "Invoke" && TypeManager.IsDelegateType (DeclaringType)) {
4156 ec.Report.Error (1533, loc, "Invoke cannot be called directly on a delegate");
4160 int nmethods = Methods.Length;
4164 // Methods marked 'override' don't take part in 'applicable_type'
4165 // computation, nor in the actual overload resolution.
4166 // However, they still need to be emitted instead of a base virtual method.
4167 // So, we salt them away into the 'candidate_overrides' array.
4169 // In case of reflected methods, we replace each overriding method with
4170 // its corresponding base virtual method. This is to improve compatibility
4171 // with non-C# libraries which change the visibility of overrides (#75636)
4174 for (int i = 0; i < Methods.Length; ++i) {
4175 MethodBase m = Methods [i];
4176 if (TypeManager.IsOverride (m)) {
4177 if (candidate_overrides == null)
4178 candidate_overrides = new ArrayList ();
4179 candidate_overrides.Add (m);
4180 m = TypeManager.TryGetBaseDefinition (m);
4189 // Enable message recording, it's used mainly by lambda expressions
4191 SessionReportPrinter msg_recorder = new SessionReportPrinter ();
4192 ReportPrinter prev_recorder = ec.Report.SetPrinter (msg_recorder);
4195 // First we construct the set of applicable methods
4197 bool is_sorted = true;
4198 int best_candidate_rate = int.MaxValue;
4199 for (int i = 0; i < nmethods; i++) {
4200 Type decl_type = Methods [i].DeclaringType;
4203 // If we have already found an applicable method
4204 // we eliminate all base types (Section 14.5.5.1)
4206 if (applicable_type != null && IsAncestralType (decl_type, applicable_type))
4210 // Check if candidate is applicable (section 14.4.2.1)
4212 bool params_expanded_form = false;
4213 int candidate_rate = IsApplicable (ec, ref candidate_args, arg_count, ref Methods [i], ref params_expanded_form);
4215 if (candidate_rate < best_candidate_rate) {
4216 best_candidate_rate = candidate_rate;
4217 best_candidate = Methods [i];
4220 if (params_expanded_form) {
4221 if (candidate_to_form == null)
4222 candidate_to_form = new PtrHashtable ();
4223 MethodBase candidate = Methods [i];
4224 candidate_to_form [candidate] = candidate;
4227 if (candidate_args != Arguments) {
4228 if (candidates_expanded == null)
4229 candidates_expanded = new Hashtable (2);
4231 candidates_expanded.Add (Methods [i], candidate_args);
4232 candidate_args = Arguments;
4235 if (candidate_rate != 0 || has_inaccessible_candidates_only) {
4236 if (msg_recorder != null)
4237 msg_recorder.EndSession ();
4241 msg_recorder = null;
4242 candidates.Add (Methods [i]);
4244 if (applicable_type == null)
4245 applicable_type = decl_type;
4246 else if (applicable_type != decl_type) {
4248 if (IsAncestralType (applicable_type, decl_type))
4249 applicable_type = decl_type;
4253 ec.Report.SetPrinter (prev_recorder);
4254 if (msg_recorder != null && !msg_recorder.IsEmpty) {
4256 msg_recorder.Merge (prev_recorder);
4261 int candidate_top = candidates.Count;
4263 if (applicable_type == null) {
4265 // When we found a top level method which does not match and it's
4266 // not an extension method. We start extension methods lookup from here
4268 if (InstanceExpression != null) {
4269 ExtensionMethodGroupExpr ex_method_lookup = ec.LookupExtensionMethod (type, Name, loc);
4270 if (ex_method_lookup != null) {
4271 ex_method_lookup.ExtensionExpression = InstanceExpression;
4272 ex_method_lookup.SetTypeArguments (ec, type_arguments);
4273 return ex_method_lookup.OverloadResolve (ec, ref Arguments, may_fail, loc);
4281 // Okay so we have failed to find exact match so we
4282 // return error info about the closest match
4284 if (best_candidate != null) {
4285 if (CustomErrorHandler != null && !has_inaccessible_candidates_only && CustomErrorHandler.NoExactMatch (ec, best_candidate))
4288 AParametersCollection pd = TypeManager.GetParameterData (best_candidate);
4289 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4290 if (arg_count == pd.Count || pd.HasParams) {
4291 if (TypeManager.IsGenericMethodDefinition (best_candidate)) {
4292 if (type_arguments == null) {
4293 ec.Report.Error (411, loc,
4294 "The type arguments for method `{0}' cannot be inferred from " +
4295 "the usage. Try specifying the type arguments explicitly",
4296 TypeManager.CSharpSignature (best_candidate));
4300 Type[] g_args = TypeManager.GetGenericArguments (best_candidate);
4301 if (type_arguments.Count != g_args.Length) {
4302 ec.Report.SymbolRelatedToPreviousError (best_candidate);
4303 ec.Report.Error (305, loc, "Using the generic method `{0}' requires `{1}' type argument(s)",
4304 TypeManager.CSharpSignature (best_candidate),
4305 g_args.Length.ToString ());
4309 if (type_arguments != null && !TypeManager.IsGenericMethod (best_candidate)) {
4310 Error_TypeArgumentsCannotBeUsed (ec.Report, loc);
4315 if (has_inaccessible_candidates_only) {
4316 if (InstanceExpression != null && type != ec.CurrentType && TypeManager.IsNestedFamilyAccessible (ec.CurrentType, best_candidate.DeclaringType)) {
4317 // Although a derived class can access protected members of
4318 // its base class it cannot do so through an instance of the
4319 // base class (CS1540). If the qualifier_type is a base of the
4320 // ec.CurrentType and the lookup succeeds with the latter one,
4321 // then we are in this situation.
4322 Error_CannotAccessProtected (ec, loc, best_candidate, queried_type, ec.CurrentType);
4324 ec.Report.SymbolRelatedToPreviousError (best_candidate);
4325 ErrorIsInaccesible (loc, GetSignatureForError (), ec.Report);
4329 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate, cand_params, may_fail, loc))
4332 if (has_inaccessible_candidates_only)
4335 throw new InternalErrorException ("VerifyArgumentsCompat didn't find any problem with rejected candidate " + best_candidate);
4340 // We failed to find any method with correct argument count
4342 if (Name == ConstructorInfo.ConstructorName) {
4343 ec.Report.SymbolRelatedToPreviousError (queried_type);
4344 ec.Report.Error (1729, loc,
4345 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4346 TypeManager.CSharpName (queried_type), arg_count);
4348 Error_ArgumentCountWrong (ec, arg_count);
4356 // At this point, applicable_type is _one_ of the most derived types
4357 // in the set of types containing the methods in this MethodGroup.
4358 // Filter the candidates so that they only contain methods from the
4359 // most derived types.
4362 int finalized = 0; // Number of finalized candidates
4365 // Invariant: applicable_type is a most derived type
4367 // We'll try to complete Section 14.5.5.1 for 'applicable_type' by
4368 // eliminating all it's base types. At the same time, we'll also move
4369 // every unrelated type to the end of the array, and pick the next
4370 // 'applicable_type'.
4372 Type next_applicable_type = null;
4373 int j = finalized; // where to put the next finalized candidate
4374 int k = finalized; // where to put the next undiscarded candidate
4375 for (int i = finalized; i < candidate_top; ++i) {
4376 MethodBase candidate = (MethodBase) candidates [i];
4377 Type decl_type = candidate.DeclaringType;
4379 if (decl_type == applicable_type) {
4380 candidates [k++] = candidates [j];
4381 candidates [j++] = candidates [i];
4385 if (IsAncestralType (decl_type, applicable_type))
4388 if (next_applicable_type != null &&
4389 IsAncestralType (decl_type, next_applicable_type))
4392 candidates [k++] = candidates [i];
4394 if (next_applicable_type == null ||
4395 IsAncestralType (next_applicable_type, decl_type))
4396 next_applicable_type = decl_type;
4399 applicable_type = next_applicable_type;
4402 } while (applicable_type != null);
4406 // Now we actually find the best method
4409 best_candidate = (MethodBase) candidates [0];
4410 method_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4413 // TODO: Broken inverse order of candidates logic does not work with optional
4414 // parameters used for method overrides and I am not going to fix it for SRE
4416 if (candidates_expanded != null && candidates_expanded.Contains (best_candidate)) {
4417 candidate_args = (Arguments) candidates_expanded [best_candidate];
4418 arg_count = candidate_args.Count;
4421 for (int ix = 1; ix < candidate_top; ix++) {
4422 MethodBase candidate = (MethodBase) candidates [ix];
4424 if (candidate == best_candidate)
4427 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4429 if (BetterFunction (ec, candidate_args, arg_count,
4430 candidate, cand_params,
4431 best_candidate, method_params)) {
4432 best_candidate = candidate;
4433 method_params = cand_params;
4437 // Now check that there are no ambiguities i.e the selected method
4438 // should be better than all the others
4440 MethodBase ambiguous = null;
4441 for (int ix = 1; ix < candidate_top; ix++) {
4442 MethodBase candidate = (MethodBase) candidates [ix];
4444 if (candidate == best_candidate)
4447 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4448 if (!BetterFunction (ec, candidate_args, arg_count,
4449 best_candidate, method_params,
4450 candidate, cand_params))
4453 ec.Report.SymbolRelatedToPreviousError (candidate);
4454 ambiguous = candidate;
4458 if (ambiguous != null) {
4459 Error_AmbiguousCall (ec, ambiguous);
4464 // If the method is a virtual function, pick an override closer to the LHS type.
4466 if (!IsBase && best_candidate.IsVirtual) {
4467 if (TypeManager.IsOverride (best_candidate))
4468 throw new InternalErrorException (
4469 "Should not happen. An 'override' method took part in overload resolution: " + best_candidate);
4471 if (candidate_overrides != null) {
4472 Type[] gen_args = null;
4473 bool gen_override = false;
4474 if (TypeManager.IsGenericMethod (best_candidate))
4475 gen_args = TypeManager.GetGenericArguments (best_candidate);
4477 foreach (MethodBase candidate in candidate_overrides) {
4478 if (TypeManager.IsGenericMethod (candidate)) {
4479 if (gen_args == null)
4482 if (gen_args.Length != TypeManager.GetGenericArguments (candidate).Length)
4485 if (gen_args != null)
4489 if (IsOverride (candidate, best_candidate)) {
4490 gen_override = true;
4491 best_candidate = candidate;
4495 if (gen_override && gen_args != null) {
4496 best_candidate = ((MethodInfo) best_candidate).MakeGenericMethod (gen_args);
4502 // And now check if the arguments are all
4503 // compatible, perform conversions if
4504 // necessary etc. and return if everything is
4507 if (!VerifyArgumentsCompat (ec, ref candidate_args, arg_count, best_candidate,
4508 method_params, may_fail, loc))
4511 if (best_candidate == null)
4514 MethodBase the_method = TypeManager.DropGenericMethodArguments (best_candidate);
4515 if (TypeManager.IsGenericMethodDefinition (the_method) &&
4516 !ConstraintChecker.CheckConstraints (ec, the_method, best_candidate, loc))
4520 // Check ObsoleteAttribute on the best method
4522 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (the_method);
4523 if (oa != null && !ec.IsObsolete)
4524 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
4526 IMethodData data = TypeManager.GetMethod (the_method);
4528 data.SetMemberIsUsed ();
4530 Arguments = candidate_args;
4534 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4536 type_arguments = ta;
4539 public bool VerifyArgumentsCompat (ResolveContext ec, ref Arguments arguments,
4540 int arg_count, MethodBase method,
4541 bool chose_params_expanded,
4542 bool may_fail, Location loc)
4544 AParametersCollection pd = TypeManager.GetParameterData (method);
4545 int param_count = GetApplicableParametersCount (method, pd);
4547 int errors = ec.Report.Errors;
4548 Parameter.Modifier p_mod = 0;
4550 int a_idx = 0, a_pos = 0;
4552 ArrayList params_initializers = null;
4553 bool has_unsafe_arg = method is MethodInfo ? ((MethodInfo) method).ReturnType.IsPointer : false;
4555 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4556 a = arguments [a_idx];
4557 if (p_mod != Parameter.Modifier.PARAMS) {
4558 p_mod = pd.FixedParameters [a_idx].ModFlags;
4559 pt = pd.Types [a_idx];
4560 has_unsafe_arg |= pt.IsPointer;
4562 if (p_mod == Parameter.Modifier.PARAMS) {
4563 if (chose_params_expanded) {
4564 params_initializers = new ArrayList (arg_count - a_idx);
4565 pt = TypeManager.GetElementType (pt);
4571 // Types have to be identical when ref or out modifer is used
4573 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4574 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4577 if (!TypeManager.IsEqual (a.Expr.Type, pt))
4582 NamedArgument na = a as NamedArgument;
4584 int name_index = pd.GetParameterIndexByName (na.Name.Value);
4585 if (name_index < 0 || name_index >= param_count) {
4586 if (DeclaringType != null && TypeManager.IsDelegateType (DeclaringType)) {
4587 ec.Report.SymbolRelatedToPreviousError (DeclaringType);
4588 ec.Report.Error (1746, na.Name.Location,
4589 "The delegate `{0}' does not contain a parameter named `{1}'",
4590 TypeManager.CSharpName (DeclaringType), na.Name.Value);
4592 ec.Report.SymbolRelatedToPreviousError (best_candidate);
4593 ec.Report.Error (1739, na.Name.Location,
4594 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
4595 TypeManager.CSharpSignature (method), na.Name.Value);
4597 } else if (arguments[name_index] != a) {
4598 if (DeclaringType != null && TypeManager.IsDelegateType (DeclaringType))
4599 ec.Report.SymbolRelatedToPreviousError (DeclaringType);
4601 ec.Report.SymbolRelatedToPreviousError (best_candidate);
4603 ec.Report.Error (1744, na.Name.Location,
4604 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
4610 if (delegate_type != null && !Delegate.IsTypeCovariant (a.Expr, pt))
4613 Expression conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4618 // Convert params arguments to an array initializer
4620 if (params_initializers != null) {
4621 // we choose to use 'a.Expr' rather than 'conv' so that
4622 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
4623 params_initializers.Add (a.Expr);
4624 arguments.RemoveAt (a_idx--);
4629 // Update the argument with the implicit conversion
4633 if (a_idx != arg_count) {
4634 if (!may_fail && ec.Report.Errors == errors) {
4635 if (CustomErrorHandler != null)
4636 CustomErrorHandler.NoExactMatch (ec, best_candidate);
4638 Error_InvalidArguments (ec, loc, a_pos, method, a, pd, pt);
4644 // Fill not provided arguments required by params modifier
4646 if (params_initializers == null && pd.HasParams && arg_count + 1 == param_count) {
4647 if (arguments == null)
4648 arguments = new Arguments (1);
4650 pt = pd.Types [param_count - 1];
4651 pt = TypeManager.GetElementType (pt);
4652 has_unsafe_arg |= pt.IsPointer;
4653 params_initializers = new ArrayList (0);
4657 // Append an array argument with all params arguments
4659 if (params_initializers != null) {
4660 arguments.Add (new Argument (
4661 new ArrayCreation (new TypeExpression (pt, loc), "[]",
4662 params_initializers, loc).Resolve (ec)));
4666 if (arg_count < param_count) {
4668 Error_ArgumentCountWrong (ec, arg_count);
4672 if (has_unsafe_arg && !ec.IsUnsafe) {
4674 UnsafeError (ec, loc);
4682 public class ConstantExpr : MemberExpr
4686 public ConstantExpr (FieldInfo constant, Location loc)
4688 this.constant = constant;
4692 public override string Name {
4693 get { throw new NotImplementedException (); }
4696 public override bool IsInstance {
4697 get { return !IsStatic; }
4700 public override bool IsStatic {
4701 get { return constant.IsStatic; }
4704 public override Type DeclaringType {
4705 get { return constant.DeclaringType; }
4708 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, Location loc, SimpleName original)
4710 constant = TypeManager.GetGenericFieldDefinition (constant);
4712 IConstant ic = TypeManager.GetConstant (constant);
4714 if (constant.IsLiteral) {
4715 ic = new ExternalConstant (constant);
4717 ic = ExternalConstant.CreateDecimal (constant);
4718 // HACK: decimal field was not resolved as constant
4720 return new FieldExpr (constant, loc).ResolveMemberAccess (ec, left, loc, original);
4722 TypeManager.RegisterConstant (constant, ic);
4725 return base.ResolveMemberAccess (ec, left, loc, original);
4728 public override Expression CreateExpressionTree (ResolveContext ec)
4730 throw new NotSupportedException ("ET");
4733 public override Expression DoResolve (ResolveContext ec)
4735 IConstant ic = TypeManager.GetConstant (constant);
4736 if (ic.ResolveValue ()) {
4738 ic.CheckObsoleteness (loc);
4741 return ic.CreateConstantReference (loc);
4744 public override void Emit (EmitContext ec)
4746 throw new NotSupportedException ();
4749 public override string GetSignatureForError ()
4751 return TypeManager.GetFullNameSignature (constant);
4756 /// Fully resolved expression that evaluates to a Field
4758 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference {
4759 public FieldInfo FieldInfo;
4760 readonly Type constructed_generic_type;
4761 VariableInfo variable_info;
4763 LocalTemporary temp;
4766 protected FieldExpr (Location l)
4771 public FieldExpr (FieldInfo fi, Location l)
4774 type = TypeManager.TypeToCoreType (fi.FieldType);
4778 public FieldExpr (FieldInfo fi, Type genericType, Location l)
4781 if (TypeManager.IsGenericTypeDefinition (genericType))
4783 this.constructed_generic_type = genericType;
4786 public override string Name {
4788 return FieldInfo.Name;
4792 public override bool IsInstance {
4794 return !FieldInfo.IsStatic;
4798 public override bool IsStatic {
4800 return FieldInfo.IsStatic;
4804 public override Type DeclaringType {
4806 return FieldInfo.DeclaringType;
4810 public override string GetSignatureForError ()
4812 return TypeManager.GetFullNameSignature (FieldInfo);
4815 public VariableInfo VariableInfo {
4817 return variable_info;
4821 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, Location loc,
4822 SimpleName original)
4824 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
4825 Type t = fi.FieldType;
4827 if (t.IsPointer && !ec.IsUnsafe) {
4828 UnsafeError (ec, loc);
4831 return base.ResolveMemberAccess (ec, left, loc, original);
4834 public void SetHasAddressTaken ()
4836 IVariableReference vr = InstanceExpression as IVariableReference;
4838 vr.SetHasAddressTaken ();
4841 public override Expression CreateExpressionTree (ResolveContext ec)
4843 Expression instance;
4844 if (InstanceExpression == null) {
4845 instance = new NullLiteral (loc);
4847 instance = InstanceExpression.CreateExpressionTree (ec);
4850 Arguments args = Arguments.CreateForExpressionTree (ec, null,
4852 CreateTypeOfExpression ());
4854 return CreateExpressionFactoryCall (ec, "Field", args);
4857 public Expression CreateTypeOfExpression ()
4859 return new TypeOfField (GetConstructedFieldInfo (), loc);
4862 override public Expression DoResolve (ResolveContext ec)
4864 return DoResolve (ec, false, false);
4867 Expression DoResolve (ResolveContext ec, bool lvalue_instance, bool out_access)
4869 if (!FieldInfo.IsStatic){
4870 if (InstanceExpression == null){
4872 // This can happen when referencing an instance field using
4873 // a fully qualified type expression: TypeName.InstanceField = xxx
4875 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4879 // Resolve the field's instance expression while flow analysis is turned
4880 // off: when accessing a field "a.b", we must check whether the field
4881 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4883 if (lvalue_instance) {
4884 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
4885 Expression right_side =
4886 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4888 if (InstanceExpression != EmptyExpression.Null)
4889 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
4892 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
4894 if (InstanceExpression != EmptyExpression.Null)
4895 InstanceExpression = InstanceExpression.Resolve (ec, rf);
4898 if (InstanceExpression == null)
4901 using (ec.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
4902 InstanceExpression.CheckMarshalByRefAccess (ec);
4906 // TODO: the code above uses some non-standard multi-resolve rules
4907 if (eclass != ExprClass.Invalid)
4910 if (!ec.IsObsolete) {
4911 FieldBase f = TypeManager.GetField (FieldInfo);
4913 f.CheckObsoleteness (loc);
4915 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
4917 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc, ec.Report);
4921 IFixedBuffer fb = AttributeTester.GetFixedBuffer (FieldInfo);
4922 IVariableReference var = InstanceExpression as IVariableReference;
4925 IFixedExpression fe = InstanceExpression as IFixedExpression;
4926 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
4927 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4930 if (InstanceExpression.eclass != ExprClass.Variable) {
4931 ec.Report.SymbolRelatedToPreviousError (FieldInfo);
4932 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4933 TypeManager.GetFullNameSignature (FieldInfo));
4934 } else if (var != null && var.IsHoisted) {
4935 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
4938 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4941 eclass = ExprClass.Variable;
4943 // If the instance expression is a local variable or parameter.
4944 if (var == null || var.VariableInfo == null)
4947 VariableInfo vi = var.VariableInfo;
4948 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
4951 variable_info = vi.GetSubStruct (FieldInfo.Name);
4952 eclass = ExprClass.Variable;
4956 static readonly int [] codes = {
4957 191, // instance, write access
4958 192, // instance, out access
4959 198, // static, write access
4960 199, // static, out access
4961 1648, // member of value instance, write access
4962 1649, // member of value instance, out access
4963 1650, // member of value static, write access
4964 1651 // member of value static, out access
4967 static readonly string [] msgs = {
4968 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4969 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4970 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4971 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4972 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4973 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4974 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4975 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4978 // The return value is always null. Returning a value simplifies calling code.
4979 Expression Report_AssignToReadonly (ResolveContext ec, Expression right_side)
4982 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4986 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4988 ec.Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4993 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
4995 IVariableReference var = InstanceExpression as IVariableReference;
4996 if (var != null && var.VariableInfo != null)
4997 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
4999 bool lvalue_instance = !FieldInfo.IsStatic && TypeManager.IsValueType (FieldInfo.DeclaringType);
5000 bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
5002 Expression e = DoResolve (ec, lvalue_instance, out_access);
5007 FieldBase fb = TypeManager.GetField (FieldInfo);
5011 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
5012 (fb.ModFlags & Modifiers.VOLATILE) != 0) {
5013 ec.Report.Warning (420, 1, loc,
5014 "`{0}': A volatile field references will not be treated as volatile",
5015 fb.GetSignatureForError ());
5019 if (FieldInfo.IsInitOnly) {
5020 // InitOnly fields can only be assigned in constructors or initializers
5021 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
5022 return Report_AssignToReadonly (ec, right_side);
5024 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
5025 Type ctype = ec.CurrentType;
5027 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
5028 if (!TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
5029 return Report_AssignToReadonly (ec, right_side);
5030 // static InitOnly fields cannot be assigned-to in an instance constructor
5031 if (IsStatic && !ec.IsStatic)
5032 return Report_AssignToReadonly (ec, right_side);
5033 // instance constructors can't modify InitOnly fields of other instances of the same type
5034 if (!IsStatic && !(InstanceExpression is This))
5035 return Report_AssignToReadonly (ec, right_side);
5039 if (right_side == EmptyExpression.OutAccess &&
5040 !IsStatic && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type)) {
5041 ec.Report.SymbolRelatedToPreviousError (DeclaringType);
5042 ec.Report.Warning (197, 1, loc,
5043 "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",
5044 GetSignatureForError ());
5047 eclass = ExprClass.Variable;
5051 bool is_marshal_by_ref ()
5053 return !IsStatic && TypeManager.IsStruct (Type) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type);
5056 public override void CheckMarshalByRefAccess (ResolveContext ec)
5058 if (is_marshal_by_ref () && !(InstanceExpression is This)) {
5059 ec.Report.SymbolRelatedToPreviousError (DeclaringType);
5060 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",
5061 GetSignatureForError ());
5065 public override int GetHashCode ()
5067 return FieldInfo.GetHashCode ();
5070 public bool IsFixed {
5073 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
5075 IVariableReference variable = InstanceExpression as IVariableReference;
5076 if (variable != null)
5077 return TypeManager.IsStruct (InstanceExpression.Type) && variable.IsFixed;
5079 IFixedExpression fe = InstanceExpression as IFixedExpression;
5080 return fe != null && fe.IsFixed;
5084 public bool IsHoisted {
5086 IVariableReference hv = InstanceExpression as IVariableReference;
5087 return hv != null && hv.IsHoisted;
5091 public override bool Equals (object obj)
5093 FieldExpr fe = obj as FieldExpr;
5097 if (FieldInfo != fe.FieldInfo)
5100 if (InstanceExpression == null || fe.InstanceExpression == null)
5103 return InstanceExpression.Equals (fe.InstanceExpression);
5106 public void Emit (EmitContext ec, bool leave_copy)
5108 ILGenerator ig = ec.ig;
5109 bool is_volatile = false;
5111 FieldBase f = TypeManager.GetField (FieldInfo);
5113 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
5116 f.SetMemberIsUsed ();
5119 if (FieldInfo.IsStatic){
5121 ig.Emit (OpCodes.Volatile);
5123 ig.Emit (OpCodes.Ldsfld, GetConstructedFieldInfo ());
5126 EmitInstance (ec, false);
5128 // Optimization for build-in types
5129 if (TypeManager.IsStruct (type) && TypeManager.IsEqual (type, ec.MemberContext.CurrentType)) {
5130 LoadFromPtr (ig, type);
5132 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
5134 ig.Emit (OpCodes.Ldflda, GetConstructedFieldInfo ());
5135 ig.Emit (OpCodes.Ldflda, ff.Element);
5138 ig.Emit (OpCodes.Volatile);
5140 ig.Emit (OpCodes.Ldfld, GetConstructedFieldInfo ());
5146 ec.ig.Emit (OpCodes.Dup);
5147 if (!FieldInfo.IsStatic) {
5148 temp = new LocalTemporary (this.Type);
5154 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5156 FieldAttributes fa = FieldInfo.Attributes;
5157 bool is_static = (fa & FieldAttributes.Static) != 0;
5158 ILGenerator ig = ec.ig;
5160 prepared = prepare_for_load;
5161 EmitInstance (ec, prepared);
5165 ec.ig.Emit (OpCodes.Dup);
5166 if (!FieldInfo.IsStatic) {
5167 temp = new LocalTemporary (this.Type);
5172 FieldBase f = TypeManager.GetField (FieldInfo);
5174 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
5175 ig.Emit (OpCodes.Volatile);
5181 ig.Emit (OpCodes.Stsfld, GetConstructedFieldInfo ());
5183 ig.Emit (OpCodes.Stfld, GetConstructedFieldInfo ());
5192 public override void Emit (EmitContext ec)
5197 public override void EmitSideEffect (EmitContext ec)
5199 FieldBase f = TypeManager.GetField (FieldInfo);
5200 bool is_volatile = f != null && (f.ModFlags & Modifiers.VOLATILE) != 0;
5202 if (is_volatile || is_marshal_by_ref ())
5203 base.EmitSideEffect (ec);
5206 public override void Error_VariableIsUsedBeforeItIsDeclared (Report r, string name)
5209 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the field `{1}'",
5210 name, GetSignatureForError ());
5213 public void AddressOf (EmitContext ec, AddressOp mode)
5215 ILGenerator ig = ec.ig;
5217 FieldBase f = TypeManager.GetField (FieldInfo);
5219 if ((mode & AddressOp.Store) != 0)
5221 if ((mode & AddressOp.Load) != 0)
5222 f.SetMemberIsUsed ();
5226 // Handle initonly fields specially: make a copy and then
5227 // get the address of the copy.
5230 if (FieldInfo.IsInitOnly){
5232 if (ec.HasSet (EmitContext.Options.ConstructorScope)){
5233 if (FieldInfo.IsStatic){
5245 local = ig.DeclareLocal (type);
5246 ig.Emit (OpCodes.Stloc, local);
5247 ig.Emit (OpCodes.Ldloca, local);
5252 if (FieldInfo.IsStatic){
5253 ig.Emit (OpCodes.Ldsflda, GetConstructedFieldInfo ());
5256 EmitInstance (ec, false);
5257 ig.Emit (OpCodes.Ldflda, GetConstructedFieldInfo ());
5261 FieldInfo GetConstructedFieldInfo ()
5263 if (constructed_generic_type == null)
5266 return TypeBuilder.GetField (constructed_generic_type, FieldInfo);
5270 public SLE.Expression MakeAssignExpression (BuilderContext ctx)
5272 return MakeExpression (ctx);
5275 public override SLE.Expression MakeExpression (BuilderContext ctx)
5277 return SLE.Expression.Field (InstanceExpression.MakeExpression (ctx), FieldInfo);
5281 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5283 FieldInfo = storey.MutateField (FieldInfo);
5284 base.MutateHoistedGenericType (storey);
5290 /// Expression that evaluates to a Property. The Assign class
5291 /// might set the `Value' expression if we are in an assignment.
5293 /// This is not an LValue because we need to re-write the expression, we
5294 /// can not take data from the stack and store it.
5296 public class PropertyExpr : MemberExpr, IDynamicAssign
5298 public readonly PropertyInfo PropertyInfo;
5299 MethodInfo getter, setter;
5303 TypeArguments targs;
5305 LocalTemporary temp;
5308 public PropertyExpr (Type container_type, PropertyInfo pi, Location l)
5311 eclass = ExprClass.PropertyAccess;
5315 type = TypeManager.TypeToCoreType (pi.PropertyType);
5317 ResolveAccessors (container_type);
5320 public override string Name {
5322 return PropertyInfo.Name;
5326 public override bool IsInstance {
5332 public override bool IsStatic {
5338 public override Expression CreateExpressionTree (ResolveContext ec)
5341 if (IsSingleDimensionalArrayLength ()) {
5342 args = new Arguments (1);
5343 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5344 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
5348 Error_BaseAccessInExpressionTree (ec, loc);
5352 args = new Arguments (2);
5353 if (InstanceExpression == null)
5354 args.Add (new Argument (new NullLiteral (loc)));
5356 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5357 args.Add (new Argument (new TypeOfMethod (getter, loc)));
5358 return CreateExpressionFactoryCall (ec, "Property", args);
5361 public Expression CreateSetterTypeOfExpression ()
5363 return new TypeOfMethod (setter, loc);
5366 public override Type DeclaringType {
5368 return PropertyInfo.DeclaringType;
5372 public override string GetSignatureForError ()
5374 return TypeManager.GetFullNameSignature (PropertyInfo);
5377 void FindAccessors (Type invocation_type)
5379 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
5380 BindingFlags.Static | BindingFlags.Instance |
5381 BindingFlags.DeclaredOnly;
5383 Type current = PropertyInfo.DeclaringType;
5384 for (; current != null; current = current.BaseType) {
5385 MemberInfo[] group = TypeManager.MemberLookup (
5386 invocation_type, invocation_type, current,
5387 MemberTypes.Property, flags, PropertyInfo.Name, null);
5392 if (group.Length != 1)
5393 // Oooops, can this ever happen ?
5396 PropertyInfo pi = (PropertyInfo) group [0];
5399 getter = pi.GetGetMethod (true);
5402 setter = pi.GetSetMethod (true);
5404 MethodInfo accessor = getter != null ? getter : setter;
5406 if (!accessor.IsVirtual)
5412 // We also perform the permission checking here, as the PropertyInfo does not
5413 // hold the information for the accessibility of its setter/getter
5415 // TODO: Refactor to use some kind of cache together with GetPropertyFromAccessor
5416 void ResolveAccessors (Type container_type)
5418 FindAccessors (container_type);
5420 if (getter != null) {
5421 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
5422 IMethodData md = TypeManager.GetMethod (the_getter);
5424 md.SetMemberIsUsed ();
5426 is_static = getter.IsStatic;
5429 if (setter != null) {
5430 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
5431 IMethodData md = TypeManager.GetMethod (the_setter);
5433 md.SetMemberIsUsed ();
5435 is_static = setter.IsStatic;
5440 public SLE.Expression MakeAssignExpression (BuilderContext ctx)
5442 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), setter);
5445 public override SLE.Expression MakeExpression (BuilderContext ctx)
5447 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), getter);
5451 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5453 if (InstanceExpression != null)
5454 InstanceExpression.MutateHoistedGenericType (storey);
5456 type = storey.MutateType (type);
5458 getter = storey.MutateGenericMethod (getter);
5460 setter = storey.MutateGenericMethod (setter);
5463 bool InstanceResolve (ResolveContext ec, bool lvalue_instance, bool must_do_cs1540_check)
5466 InstanceExpression = null;
5470 if (InstanceExpression == null) {
5471 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5475 InstanceExpression = InstanceExpression.DoResolve (ec);
5476 if (lvalue_instance && InstanceExpression != null)
5477 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess);
5479 if (InstanceExpression == null)
5482 InstanceExpression.CheckMarshalByRefAccess (ec);
5484 if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) &&
5485 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.CurrentType) &&
5486 !TypeManager.IsNestedChildOf (ec.CurrentType, InstanceExpression.Type) &&
5487 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.CurrentType)) {
5488 ec.Report.SymbolRelatedToPreviousError (PropertyInfo);
5489 Error_CannotAccessProtected (ec, loc, PropertyInfo, InstanceExpression.Type, ec.CurrentType);
5496 void Error_PropertyNotFound (ResolveContext ec, MethodInfo mi, bool getter)
5498 // TODO: correctly we should compare arguments but it will lead to bigger changes
5499 if (mi is MethodBuilder) {
5500 Error_TypeDoesNotContainDefinition (ec, loc, PropertyInfo.DeclaringType, Name);
5504 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
5506 AParametersCollection iparams = TypeManager.GetParameterData (mi);
5507 sig.Append (getter ? "get_" : "set_");
5509 sig.Append (iparams.GetSignatureForError ());
5511 ec.Report.SymbolRelatedToPreviousError (mi);
5512 ec.Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
5513 Name, sig.ToString ());
5516 public bool IsAccessibleFrom (Type invocation_type, bool lvalue)
5519 MethodInfo accessor = lvalue ? setter : getter;
5520 if (accessor == null && lvalue)
5522 return accessor != null && IsAccessorAccessible (invocation_type, accessor, out dummy);
5525 bool IsSingleDimensionalArrayLength ()
5527 if (DeclaringType != TypeManager.array_type || getter == null || Name != "Length")
5530 string t_name = InstanceExpression.Type.Name;
5531 int t_name_len = t_name.Length;
5532 return t_name_len > 2 && t_name [t_name_len - 2] == '[';
5535 public override Expression DoResolve (ResolveContext ec)
5540 bool must_do_cs1540_check = false;
5541 ec.Report.DisableReporting ();
5542 bool res = ResolveGetter (ec, ref must_do_cs1540_check);
5543 ec.Report.EnableReporting ();
5546 if (InstanceExpression != null) {
5547 Type expr_type = InstanceExpression.Type;
5548 ExtensionMethodGroupExpr ex_method_lookup = ec.LookupExtensionMethod (expr_type, Name, loc);
5549 if (ex_method_lookup != null) {
5550 ex_method_lookup.ExtensionExpression = InstanceExpression;
5551 ex_method_lookup.SetTypeArguments (ec, targs);
5552 return ex_method_lookup.DoResolve (ec);
5556 ResolveGetter (ec, ref must_do_cs1540_check);
5560 if (!InstanceResolve (ec, false, must_do_cs1540_check))
5564 // Only base will allow this invocation to happen.
5566 if (IsBase && getter.IsAbstract) {
5567 Error_CannotCallAbstractBase (ec, TypeManager.GetFullNameSignature (PropertyInfo));
5570 if (PropertyInfo.PropertyType.IsPointer && !ec.IsUnsafe){
5571 UnsafeError (ec, loc);
5574 if (!ec.IsObsolete) {
5575 PropertyBase pb = TypeManager.GetProperty (PropertyInfo);
5577 pb.CheckObsoleteness (loc);
5579 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (PropertyInfo);
5581 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
5590 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5592 if (right_side == EmptyExpression.OutAccess) {
5593 if (ec.CurrentBlock.Toplevel.GetParameterReference (PropertyInfo.Name, loc) is MemberAccess) {
5594 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5597 ec.Report.Error (206, loc, "A property or indexer `{0}' may not be passed as `ref' or `out' parameter",
5598 GetSignatureForError ());
5603 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5604 Error_CannotModifyIntermediateExpressionValue (ec);
5607 if (setter == null){
5609 // The following condition happens if the PropertyExpr was
5610 // created, but is invalid (ie, the property is inaccessible),
5611 // and we did not want to embed the knowledge about this in
5612 // the caller routine. This only avoids double error reporting.
5617 if (ec.CurrentBlock.Toplevel.GetParameterReference (PropertyInfo.Name, loc) is MemberAccess) {
5618 ec.Report.Error (1947, loc, "A range variable `{0}' cannot be assigned to. Consider using `let' clause to store the value",
5621 ec.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
5622 GetSignatureForError ());
5627 if (targs != null) {
5628 base.SetTypeArguments (ec, targs);
5632 if (TypeManager.GetParameterData (setter).Count != 1){
5633 Error_PropertyNotFound (ec, setter, false);
5637 bool must_do_cs1540_check;
5638 if (!IsAccessorAccessible (ec.CurrentType, setter, out must_do_cs1540_check)) {
5639 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
5640 if (pm != null && pm.HasCustomAccessModifier) {
5641 ec.Report.SymbolRelatedToPreviousError (pm);
5642 ec.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5643 TypeManager.CSharpSignature (setter));
5646 ec.Report.SymbolRelatedToPreviousError (setter);
5647 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter), ec.Report);
5652 if (!InstanceResolve (ec, TypeManager.IsStruct (PropertyInfo.DeclaringType), must_do_cs1540_check))
5656 // Only base will allow this invocation to happen.
5658 if (IsBase && setter.IsAbstract){
5659 Error_CannotCallAbstractBase (ec, TypeManager.GetFullNameSignature (PropertyInfo));
5662 if (PropertyInfo.PropertyType.IsPointer && !ec.IsUnsafe) {
5663 UnsafeError (ec, loc);
5666 if (!ec.IsObsolete) {
5667 PropertyBase pb = TypeManager.GetProperty (PropertyInfo);
5669 pb.CheckObsoleteness (loc);
5671 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (PropertyInfo);
5673 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
5680 public override void Emit (EmitContext ec)
5685 public void Emit (EmitContext ec, bool leave_copy)
5688 // Special case: length of single dimension array property is turned into ldlen
5690 if (IsSingleDimensionalArrayLength ()) {
5692 EmitInstance (ec, false);
5693 ec.ig.Emit (OpCodes.Ldlen);
5694 ec.ig.Emit (OpCodes.Conv_I4);
5698 Invocation.EmitCall (ec, IsBase, InstanceExpression, getter, null, loc, prepared, false);
5701 ec.ig.Emit (OpCodes.Dup);
5703 temp = new LocalTemporary (this.Type);
5710 // Implements the IAssignMethod interface for assignments
5712 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5714 Expression my_source = source;
5716 if (prepare_for_load) {
5721 ec.ig.Emit (OpCodes.Dup);
5723 temp = new LocalTemporary (this.Type);
5727 } else if (leave_copy) {
5729 temp = new LocalTemporary (this.Type);
5734 Arguments args = new Arguments (1);
5735 args.Add (new Argument (my_source));
5737 Invocation.EmitCall (ec, IsBase, InstanceExpression, setter, args, loc, false, prepared);
5745 bool ResolveGetter (ResolveContext ec, ref bool must_do_cs1540_check)
5747 if (targs != null) {
5748 base.SetTypeArguments (ec, targs);
5752 if (getter != null) {
5753 if (TypeManager.GetParameterData (getter).Count != 0) {
5754 Error_PropertyNotFound (ec, getter, true);
5759 if (getter == null) {
5761 // The following condition happens if the PropertyExpr was
5762 // created, but is invalid (ie, the property is inaccessible),
5763 // and we did not want to embed the knowledge about this in
5764 // the caller routine. This only avoids double error reporting.
5769 if (InstanceExpression != EmptyExpression.Null) {
5770 ec.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5771 TypeManager.GetFullNameSignature (PropertyInfo));
5776 if (getter != null &&
5777 !IsAccessorAccessible (ec.CurrentType, getter, out must_do_cs1540_check)) {
5778 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
5779 if (pm != null && pm.HasCustomAccessModifier) {
5780 ec.Report.SymbolRelatedToPreviousError (pm);
5781 ec.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5782 TypeManager.CSharpSignature (getter));
5784 ec.Report.SymbolRelatedToPreviousError (getter);
5785 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter), ec.Report);
5794 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5801 /// Fully resolved expression that evaluates to an Event
5803 public class EventExpr : MemberExpr {
5804 public readonly EventInfo EventInfo;
5807 MethodInfo add_accessor, remove_accessor;
5809 public EventExpr (EventInfo ei, Location loc)
5813 eclass = ExprClass.EventAccess;
5815 add_accessor = TypeManager.GetAddMethod (ei);
5816 remove_accessor = TypeManager.GetRemoveMethod (ei);
5817 if (add_accessor.IsStatic || remove_accessor.IsStatic)
5820 if (EventInfo is MyEventBuilder){
5821 MyEventBuilder eb = (MyEventBuilder) EventInfo;
5822 type = eb.EventType;
5825 type = EventInfo.EventHandlerType;
5828 public override string Name {
5830 return EventInfo.Name;
5834 public override bool IsInstance {
5840 public override bool IsStatic {
5846 public override Type DeclaringType {
5848 return EventInfo.DeclaringType;
5852 public void Error_AssignmentEventOnly (ResolveContext ec)
5854 ec.Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5855 GetSignatureForError ());
5858 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, Location loc,
5859 SimpleName original)
5862 // If the event is local to this class, we transform ourselves into a FieldExpr
5865 if (EventInfo.DeclaringType == ec.CurrentType ||
5866 TypeManager.IsNestedChildOf(ec.CurrentType, EventInfo.DeclaringType)) {
5867 EventField mi = TypeManager.GetEventField (EventInfo);
5871 mi.CheckObsoleteness (loc);
5873 if ((mi.ModFlags & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0 && !ec.HasSet (ResolveContext.Options.CompoundAssignmentScope))
5874 Error_AssignmentEventOnly (ec);
5876 FieldExpr ml = new FieldExpr (mi.BackingField.FieldBuilder, loc);
5878 InstanceExpression = null;
5880 return ml.ResolveMemberAccess (ec, left, loc, original);
5884 if (left is This && !ec.HasSet (ResolveContext.Options.CompoundAssignmentScope))
5885 Error_AssignmentEventOnly (ec);
5887 return base.ResolveMemberAccess (ec, left, loc, original);
5890 bool InstanceResolve (ResolveContext ec, bool must_do_cs1540_check)
5893 InstanceExpression = null;
5897 if (InstanceExpression == null) {
5898 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5902 InstanceExpression = InstanceExpression.DoResolve (ec);
5903 if (InstanceExpression == null)
5906 if (IsBase && add_accessor.IsAbstract) {
5907 Error_CannotCallAbstractBase (ec, TypeManager.CSharpSignature(add_accessor));
5912 // This is using the same mechanism as the CS1540 check in PropertyExpr.
5913 // However, in the Event case, we reported a CS0122 instead.
5915 // TODO: Exact copy from PropertyExpr
5917 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
5918 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.CurrentType) &&
5919 !TypeManager.IsNestedChildOf (ec.CurrentType, InstanceExpression.Type) &&
5920 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.CurrentType)) {
5921 ec.Report.SymbolRelatedToPreviousError (EventInfo);
5922 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo), ec.Report);
5929 public bool IsAccessibleFrom (Type invocation_type)
5932 return IsAccessorAccessible (invocation_type, add_accessor, out dummy) &&
5933 IsAccessorAccessible (invocation_type, remove_accessor, out dummy);
5936 public override Expression CreateExpressionTree (ResolveContext ec)
5938 throw new NotSupportedException ("ET");
5941 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5943 // contexts where an LValue is valid have already devolved to FieldExprs
5944 Error_CannotAssign (ec);
5948 public override Expression DoResolve (ResolveContext ec)
5950 bool must_do_cs1540_check;
5951 if (!(IsAccessorAccessible (ec.CurrentType, add_accessor, out must_do_cs1540_check) &&
5952 IsAccessorAccessible (ec.CurrentType, remove_accessor, out must_do_cs1540_check))) {
5953 ec.Report.SymbolRelatedToPreviousError (EventInfo);
5954 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo), ec.Report);
5958 if (!InstanceResolve (ec, must_do_cs1540_check))
5961 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
5962 Error_CannotAssign (ec);
5966 if (!ec.IsObsolete) {
5967 EventField ev = TypeManager.GetEventField (EventInfo);
5969 ev.CheckObsoleteness (loc);
5971 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (EventInfo);
5973 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
5980 public override void Emit (EmitContext ec)
5982 throw new NotSupportedException ();
5983 //Error_CannotAssign ();
5986 public void Error_CannotAssign (ResolveContext ec)
5988 ec.Report.Error (70, loc,
5989 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
5990 GetSignatureForError (), TypeManager.CSharpName (EventInfo.DeclaringType));
5993 public override string GetSignatureForError ()
5995 return TypeManager.CSharpSignature (EventInfo);
5998 public void EmitAddOrRemove (EmitContext ec, bool is_add, Expression source)
6000 Arguments args = new Arguments (1);
6001 args.Add (new Argument (source));
6002 Invocation.EmitCall (ec, IsBase, InstanceExpression, is_add ? add_accessor : remove_accessor, args, loc);
6006 public class TemporaryVariable : VariableReference
6010 public TemporaryVariable (Type type, Location loc)
6014 eclass = ExprClass.Variable;
6017 public override Expression CreateExpressionTree (ResolveContext ec)
6019 throw new NotSupportedException ("ET");
6022 public override Expression DoResolve (ResolveContext ec)
6027 TypeExpr te = new TypeExpression (type, loc);
6028 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
6029 if (!li.Resolve (ec))
6033 // Don't capture temporary variables except when using
6034 // iterator redirection
6036 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.IsIterator && ec.IsVariableCapturingRequired) {
6037 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
6038 storey.CaptureLocalVariable (ec, li);
6044 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6046 return DoResolve (ec);
6049 public override void Emit (EmitContext ec)
6054 public void EmitAssign (EmitContext ec, Expression source)
6056 EmitAssign (ec, source, false, false);
6059 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6061 return li.HoistedVariableReference;
6064 public override bool IsFixed {
6065 get { return true; }
6068 public override bool IsRef {
6069 get { return false; }
6072 public override string Name {
6073 get { throw new NotImplementedException (); }
6076 public override void SetHasAddressTaken ()
6078 throw new NotImplementedException ();
6081 protected override ILocalVariable Variable {
6085 public override VariableInfo VariableInfo {
6086 get { throw new NotImplementedException (); }
6091 /// Handles `var' contextual keyword; var becomes a keyword only
6092 /// if no type called var exists in a variable scope
6094 class VarExpr : SimpleName
6096 // Used for error reporting only
6097 ArrayList initializer;
6099 public VarExpr (Location loc)
6104 public ArrayList VariableInitializer {
6106 this.initializer = value;
6110 public bool InferType (ResolveContext ec, Expression right_side)
6113 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
6115 type = right_side.Type;
6116 if (type == TypeManager.null_type || type == TypeManager.void_type || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
6117 ec.Report.Error (815, loc, "An implicitly typed local variable declaration cannot be initialized with `{0}'",
6118 right_side.GetSignatureForError ());
6122 eclass = ExprClass.Variable;
6126 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
6128 if (RootContext.Version < LanguageVersion.V_3)
6129 base.Error_TypeOrNamespaceNotFound (ec);
6131 ec.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");
6134 public override TypeExpr ResolveAsContextualType (IMemberContext rc, bool silent)
6136 TypeExpr te = base.ResolveAsContextualType (rc, true);
6140 if (RootContext.Version < LanguageVersion.V_3)
6141 rc.Compiler.Report.FeatureIsNotAvailable (loc, "implicitly typed local variable");
6143 if (initializer == null)
6146 if (initializer.Count > 1) {
6147 Location loc_init = ((CSharpParser.VariableDeclaration) initializer[1]).Location;
6148 rc.Compiler.Report.Error (819, loc_init, "An implicitly typed local variable declaration cannot include multiple declarators");
6153 Expression variable_initializer = ((CSharpParser.VariableDeclaration) initializer[0]).expression_or_array_initializer;
6154 if (variable_initializer == null) {
6155 rc.Compiler.Report.Error (818, loc, "An implicitly typed local variable declarator must include an initializer");