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 protected EnumConstant ()
1688 : base (Location.Null)
1692 public override Expression DoResolve (ResolveContext ec)
1694 // This should never be invoked, we are born in fully
1695 // initialized state.
1700 public override void Emit (EmitContext ec)
1705 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1707 Child.EmitBranchable (ec, label, on_true);
1710 public override void EmitSideEffect (EmitContext ec)
1712 Child.EmitSideEffect (ec);
1715 public override bool GetAttributableValue (ResolveContext ec, Type value_type, out object value)
1717 value = GetTypedValue ();
1721 public override string GetSignatureForError()
1723 return TypeManager.CSharpName (Type);
1726 public override object GetValue ()
1728 return Child.GetValue ();
1731 public override object GetTypedValue ()
1733 // FIXME: runtime is not ready to work with just emited enums
1734 if (!RootContext.StdLib) {
1735 return Child.GetValue ();
1739 // Small workaround for big problem
1740 // System.Enum.ToObject cannot be called on dynamic types
1741 // EnumBuilder has to be used, but we cannot use EnumBuilder
1742 // because it does not properly support generics
1744 // This works only sometimes
1746 if (TypeManager.IsBeingCompiled (type))
1747 return Child.GetValue ();
1750 return System.Enum.ToObject (type, Child.GetValue ());
1753 public override string AsString ()
1755 return Child.AsString ();
1758 public override Constant Increment()
1760 return new EnumConstant (Child.Increment (), type);
1763 public override bool IsDefaultValue {
1765 return Child.IsDefaultValue;
1769 public override bool IsZeroInteger {
1770 get { return Child.IsZeroInteger; }
1773 public override bool IsNegative {
1775 return Child.IsNegative;
1779 public override Constant ConvertExplicitly(bool in_checked_context, Type target_type)
1781 if (Child.Type == target_type)
1784 return Child.ConvertExplicitly (in_checked_context, target_type);
1787 public override Constant ConvertImplicitly (Type type)
1789 Type this_type = TypeManager.DropGenericTypeArguments (Type);
1790 type = TypeManager.DropGenericTypeArguments (type);
1792 if (this_type == type) {
1793 // This is workaround of mono bug. It can be removed when the latest corlib spreads enough
1794 if (TypeManager.IsEnumType (type.UnderlyingSystemType))
1797 Type child_type = TypeManager.DropGenericTypeArguments (Child.Type);
1798 if (type.UnderlyingSystemType != child_type)
1799 Child = Child.ConvertImplicitly (type.UnderlyingSystemType);
1803 if (!Convert.ImplicitStandardConversionExists (this, type)){
1807 return Child.ConvertImplicitly(type);
1813 /// This kind of cast is used to encapsulate Value Types in objects.
1815 /// The effect of it is to box the value type emitted by the previous
1818 public class BoxedCast : TypeCast {
1820 public BoxedCast (Expression expr, Type target_type)
1821 : base (expr, target_type)
1823 eclass = ExprClass.Value;
1826 public override Expression DoResolve (ResolveContext ec)
1828 // This should never be invoked, we are born in fully
1829 // initialized state.
1834 public override void Emit (EmitContext ec)
1838 ec.ig.Emit (OpCodes.Box, child.Type);
1841 public override void EmitSideEffect (EmitContext ec)
1843 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1844 // so, we need to emit the box+pop instructions in most cases
1845 if (TypeManager.IsStruct (child.Type) &&
1846 (type == TypeManager.object_type || type == TypeManager.value_type))
1847 child.EmitSideEffect (ec);
1849 base.EmitSideEffect (ec);
1853 public class UnboxCast : TypeCast {
1854 public UnboxCast (Expression expr, Type return_type)
1855 : base (expr, return_type)
1859 public override Expression DoResolve (ResolveContext ec)
1861 // This should never be invoked, we are born in fully
1862 // initialized state.
1867 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
1869 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
1870 ec.Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
1871 return base.DoResolveLValue (ec, right_side);
1874 public override void Emit (EmitContext ec)
1878 ILGenerator ig = ec.ig;
1879 ig.Emit (OpCodes.Unbox_Any, type);
1882 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1884 type = storey.MutateType (type);
1885 base.MutateHoistedGenericType (storey);
1890 /// This is used to perform explicit numeric conversions.
1892 /// Explicit numeric conversions might trigger exceptions in a checked
1893 /// context, so they should generate the conv.ovf opcodes instead of
1896 public class ConvCast : TypeCast {
1897 public enum Mode : byte {
1898 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1900 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1901 U2_I1, U2_U1, U2_I2, U2_CH,
1902 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1903 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1904 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1905 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1906 CH_I1, CH_U1, CH_I2,
1907 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1908 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1914 public ConvCast (Expression child, Type return_type, Mode m)
1915 : base (child, return_type)
1920 public override Expression DoResolve (ResolveContext ec)
1922 // This should never be invoked, we are born in fully
1923 // initialized state.
1928 public override string ToString ()
1930 return String.Format ("ConvCast ({0}, {1})", mode, child);
1933 public override void Emit (EmitContext ec)
1935 ILGenerator ig = ec.ig;
1939 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1941 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1942 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1943 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1944 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1945 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1947 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1948 case Mode.U1_CH: /* nothing */ break;
1950 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1951 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1952 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1953 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1954 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1955 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1957 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1958 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1959 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1960 case Mode.U2_CH: /* nothing */ break;
1962 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1963 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1964 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1965 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1966 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1967 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1968 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1970 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1971 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1972 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1973 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1974 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1975 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1977 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1978 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1979 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1980 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1981 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1982 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1983 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1984 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1985 case Mode.I8_I: ig.Emit (OpCodes.Conv_Ovf_U); break;
1987 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1988 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1989 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1990 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1991 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1992 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1993 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1994 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1995 case Mode.U8_I: ig.Emit (OpCodes.Conv_Ovf_U_Un); break;
1997 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1998 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1999 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
2001 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
2002 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
2003 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
2004 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
2005 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
2006 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
2007 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
2008 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
2009 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
2011 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
2012 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
2013 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
2014 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
2015 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
2016 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
2017 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
2018 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
2019 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
2020 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
2022 case Mode.I_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
2026 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
2027 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
2028 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
2029 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
2030 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
2032 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
2033 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
2035 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
2036 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
2037 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
2038 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
2039 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
2040 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
2042 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
2043 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
2044 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
2045 case Mode.U2_CH: /* nothing */ break;
2047 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
2048 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
2049 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
2050 case Mode.I4_U4: /* nothing */ break;
2051 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
2052 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
2053 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
2055 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
2056 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
2057 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
2058 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
2059 case Mode.U4_I4: /* nothing */ break;
2060 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
2062 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
2063 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
2064 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
2065 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
2066 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
2067 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
2068 case Mode.I8_U8: /* nothing */ break;
2069 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
2070 case Mode.I8_I: ig.Emit (OpCodes.Conv_U); break;
2072 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
2073 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
2074 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
2075 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
2076 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
2077 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
2078 case Mode.U8_I8: /* nothing */ break;
2079 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
2080 case Mode.U8_I: ig.Emit (OpCodes.Conv_U); break;
2082 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
2083 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
2084 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
2086 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
2087 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
2088 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
2089 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
2090 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
2091 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
2092 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
2093 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
2094 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
2096 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
2097 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
2098 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
2099 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
2100 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
2101 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
2102 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
2103 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
2104 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
2105 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
2107 case Mode.I_I8: ig.Emit (OpCodes.Conv_U8); break;
2113 public class OpcodeCast : TypeCast {
2116 public OpcodeCast (Expression child, Type return_type, OpCode op)
2117 : base (child, return_type)
2122 public override Expression DoResolve (ResolveContext ec)
2124 // This should never be invoked, we are born in fully
2125 // initialized state.
2130 public override void Emit (EmitContext ec)
2136 public Type UnderlyingType {
2137 get { return child.Type; }
2142 /// This kind of cast is used to encapsulate a child and cast it
2143 /// to the class requested
2145 public sealed class ClassCast : TypeCast {
2146 readonly bool forced;
2148 public ClassCast (Expression child, Type return_type)
2149 : base (child, return_type)
2153 public ClassCast (Expression child, Type return_type, bool forced)
2154 : base (child, return_type)
2156 this.forced = forced;
2159 public override void Emit (EmitContext ec)
2163 bool gen = TypeManager.IsGenericParameter (child.Type);
2165 ec.ig.Emit (OpCodes.Box, child.Type);
2167 if (type.IsGenericParameter) {
2168 ec.ig.Emit (OpCodes.Unbox_Any, type);
2175 ec.ig.Emit (OpCodes.Castclass, type);
2180 // Created during resolving pahse when an expression is wrapped or constantified
2181 // and original expression can be used later (e.g. for expression trees)
2183 public class ReducedExpression : Expression
2185 sealed class ReducedConstantExpression : EmptyConstantCast
2187 readonly Expression orig_expr;
2189 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2190 : base (expr, expr.Type)
2192 this.orig_expr = orig_expr;
2195 public override Constant ConvertImplicitly (Type target_type)
2197 Constant c = base.ConvertImplicitly (target_type);
2199 c = new ReducedConstantExpression (c, orig_expr);
2203 public override Expression CreateExpressionTree (ResolveContext ec)
2205 return orig_expr.CreateExpressionTree (ec);
2208 public override bool GetAttributableValue (ResolveContext ec, Type value_type, out object value)
2211 // Even if resolved result is a constant original expression was not
2212 // and attribute accepts constants only
2214 Attribute.Error_AttributeArgumentNotValid (ec, orig_expr.Location);
2219 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
2221 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
2223 c = new ReducedConstantExpression (c, orig_expr);
2228 sealed class ReducedExpressionStatement : ExpressionStatement
2230 readonly Expression orig_expr;
2231 readonly ExpressionStatement stm;
2233 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
2235 this.orig_expr = orig;
2237 this.loc = orig.Location;
2240 public override Expression CreateExpressionTree (ResolveContext ec)
2242 return orig_expr.CreateExpressionTree (ec);
2245 public override Expression DoResolve (ResolveContext ec)
2247 eclass = stm.eclass;
2252 public override void Emit (EmitContext ec)
2257 public override void EmitStatement (EmitContext ec)
2259 stm.EmitStatement (ec);
2262 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2264 stm.MutateHoistedGenericType (storey);
2268 readonly Expression expr, orig_expr;
2270 private ReducedExpression (Expression expr, Expression orig_expr)
2273 this.orig_expr = orig_expr;
2274 this.loc = orig_expr.Location;
2277 public static Constant Create (Constant expr, Expression original_expr)
2279 return new ReducedConstantExpression (expr, original_expr);
2282 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
2284 return new ReducedExpressionStatement (s, orig);
2287 public static Expression Create (Expression expr, Expression original_expr)
2289 Constant c = expr as Constant;
2291 return Create (c, original_expr);
2293 ExpressionStatement s = expr as ExpressionStatement;
2295 return Create (s, original_expr);
2297 return new ReducedExpression (expr, original_expr);
2300 public override Expression CreateExpressionTree (ResolveContext ec)
2302 return orig_expr.CreateExpressionTree (ec);
2305 public override Expression DoResolve (ResolveContext ec)
2307 eclass = expr.eclass;
2312 public override void Emit (EmitContext ec)
2317 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2319 expr.EmitBranchable (ec, target, on_true);
2323 public override SLE.Expression MakeExpression (BuilderContext ctx)
2325 return orig_expr.MakeExpression (ctx);
2329 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2331 expr.MutateHoistedGenericType (storey);
2336 // Base of expressions used only to narrow resolve flow
2338 public abstract class ShimExpression : Expression
2340 protected Expression expr;
2342 protected ShimExpression (Expression expr)
2347 protected override void CloneTo (CloneContext clonectx, Expression t)
2352 ShimExpression target = (ShimExpression) t;
2353 target.expr = expr.Clone (clonectx);
2356 public override Expression CreateExpressionTree (ResolveContext ec)
2358 throw new NotSupportedException ("ET");
2361 public override void Emit (EmitContext ec)
2363 throw new InternalErrorException ("Missing Resolve call");
2366 public Expression Expr {
2367 get { return expr; }
2370 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2372 throw new InternalErrorException ("Missing Resolve call");
2377 // Unresolved type name expressions
2379 public abstract class ATypeNameExpression : FullNamedExpression
2382 protected TypeArguments targs;
2384 protected ATypeNameExpression (string name, Location l)
2390 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2397 public bool HasTypeArguments {
2399 return targs != null;
2403 public override bool Equals (object obj)
2405 ATypeNameExpression atne = obj as ATypeNameExpression;
2406 return atne != null && atne.Name == Name &&
2407 (targs == null || targs.Equals (atne.targs));
2410 public override int GetHashCode ()
2412 return Name.GetHashCode ();
2415 public override string GetSignatureForError ()
2417 if (targs != null) {
2418 return TypeManager.RemoveGenericArity (Name) + "<" +
2419 targs.GetSignatureForError () + ">";
2425 public string Name {
2434 public TypeArguments TypeArguments {
2442 /// SimpleName expressions are formed of a single word and only happen at the beginning
2443 /// of a dotted-name.
2445 public class SimpleName : ATypeNameExpression {
2448 public SimpleName (string name, Location l)
2453 public SimpleName (string name, TypeArguments args, Location l)
2454 : base (name, args, l)
2458 public SimpleName (string name, TypeParameter[] type_params, Location l)
2461 targs = new TypeArguments ();
2462 foreach (TypeParameter type_param in type_params)
2463 targs.Add (new TypeParameterExpr (type_param, l));
2466 public static string RemoveGenericArity (string name)
2469 StringBuilder sb = null;
2471 int pos = name.IndexOf ('`', start);
2476 sb.Append (name.Substring (start));
2481 sb = new StringBuilder ();
2482 sb.Append (name.Substring (start, pos-start));
2485 while ((pos < name.Length) && Char.IsNumber (name [pos]))
2489 } while (start < name.Length);
2491 return sb.ToString ();
2494 public SimpleName GetMethodGroup ()
2496 return new SimpleName (RemoveGenericArity (Name), targs, loc);
2499 public static void Error_ObjectRefRequired (ResolveContext ec, Location l, string name)
2501 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope))
2502 ec.Report.Error (236, l,
2503 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2506 ec.Report.Error (120, l,
2507 "An object reference is required to access non-static member `{0}'",
2511 public bool IdenticalNameAndTypeName (IMemberContext mc, Expression resolved_to, Location loc)
2513 return resolved_to != null && resolved_to.Type != null &&
2514 resolved_to.Type.Name == Name &&
2515 (mc.LookupNamespaceOrType (Name, loc, /* ignore_cs0104 = */ true) != null);
2518 public override Expression DoResolve (ResolveContext ec)
2520 return SimpleNameResolve (ec, null, false);
2523 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2525 return SimpleNameResolve (ec, right_side, false);
2529 public Expression DoResolve (ResolveContext ec, bool intermediate)
2531 return SimpleNameResolve (ec, null, intermediate);
2534 static bool IsNestedChild (Type t, Type parent)
2536 while (parent != null) {
2537 if (TypeManager.IsNestedChildOf (t, TypeManager.DropGenericTypeArguments (parent)))
2540 parent = parent.BaseType;
2546 FullNamedExpression ResolveNested (Type t)
2548 if (!TypeManager.IsGenericTypeDefinition (t) && !TypeManager.IsGenericType (t))
2552 while (ds != null && !IsNestedChild (t, ds))
2553 ds = ds.DeclaringType;
2558 Type[] gen_params = TypeManager.GetTypeArguments (t);
2560 int arg_count = targs != null ? targs.Count : 0;
2562 for (; (ds != null) && TypeManager.IsGenericType (ds); ds = ds.DeclaringType) {
2563 Type[] gargs = TypeManager.GetTypeArguments (ds);
2564 if (arg_count + gargs.Length == gen_params.Length) {
2565 TypeArguments new_args = new TypeArguments ();
2566 foreach (Type param in gargs)
2567 new_args.Add (new TypeExpression (param, loc));
2570 new_args.Add (targs);
2572 return new GenericTypeExpr (t, new_args, loc);
2579 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2581 int errors = ec.Compiler.Report.Errors;
2582 FullNamedExpression fne = ec.LookupNamespaceOrType (Name, loc, /*ignore_cs0104=*/ false);
2585 if (fne.Type == null)
2588 FullNamedExpression nested = ResolveNested (fne.Type);
2590 return nested.ResolveAsTypeStep (ec, false);
2592 if (targs != null) {
2593 if (TypeManager.IsGenericType (fne.Type)) {
2594 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2595 return ct.ResolveAsTypeStep (ec, false);
2598 fne.Error_TypeArgumentsCannotBeUsed (ec.Compiler.Report, loc);
2604 if (!HasTypeArguments && Name == "dynamic" && RootContext.Version > LanguageVersion.V_3)
2605 return new DynamicTypeExpr (loc);
2607 if (silent || errors != ec.Compiler.Report.Errors)
2610 Error_TypeOrNamespaceNotFound (ec);
2614 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ec)
2616 if (ec.CurrentType != null) {
2617 if (ec.CurrentTypeDefinition != null) {
2618 MemberCore mc = ec.CurrentTypeDefinition.GetDefinition (Name);
2620 Error_UnexpectedKind (ec.Compiler.Report, mc, "type", GetMemberType (mc), loc);
2625 string ns = ec.CurrentType.Namespace;
2626 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2627 foreach (Assembly a in GlobalRootNamespace.Instance.Assemblies) {
2628 Type type = a.GetType (fullname);
2630 ec.Compiler.Report.SymbolRelatedToPreviousError (type);
2631 Expression.ErrorIsInaccesible (loc, TypeManager.CSharpName (type), ec.Compiler.Report);
2636 if (ec.CurrentTypeDefinition != null) {
2637 Type t = ec.CurrentTypeDefinition.LookupAnyGeneric (Name);
2639 Namespace.Error_InvalidNumberOfTypeArguments (t, loc);
2645 if (targs != null) {
2646 FullNamedExpression retval = ec.LookupNamespaceOrType (SimpleName.RemoveGenericArity (Name), loc, true);
2647 if (retval != null) {
2648 retval.Error_TypeArgumentsCannotBeUsed (ec.Compiler.Report, loc);
2653 NamespaceEntry.Error_NamespaceNotFound (loc, Name, ec.Compiler.Report);
2656 // TODO: I am still not convinced about this. If someone else will need it
2657 // implement this as virtual property in MemberCore hierarchy
2658 public static string GetMemberType (MemberCore mc)
2664 if (mc is FieldBase)
2666 if (mc is MethodCore)
2668 if (mc is EnumMember)
2676 Expression SimpleNameResolve (ResolveContext ec, Expression right_side, bool intermediate)
2682 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2688 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2695 /// 7.5.2: Simple Names.
2697 /// Local Variables and Parameters are handled at
2698 /// parse time, so they never occur as SimpleNames.
2700 /// The `intermediate' flag is used by MemberAccess only
2701 /// and it is used to inform us that it is ok for us to
2702 /// avoid the static check, because MemberAccess might end
2703 /// up resolving the Name as a Type name and the access as
2704 /// a static type access.
2706 /// ie: Type Type; .... { Type.GetType (""); }
2708 /// Type is both an instance variable and a Type; Type.GetType
2709 /// is the static method not an instance method of type.
2711 Expression DoSimpleNameResolve (ResolveContext ec, Expression right_side, bool intermediate)
2713 Expression e = null;
2716 // Stage 1: Performed by the parser (binding to locals or parameters).
2718 Block current_block = ec.CurrentBlock;
2719 if (current_block != null){
2720 LocalInfo vi = current_block.GetLocalInfo (Name);
2722 e = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2724 if (right_side != null) {
2725 e = e.ResolveLValue (ec, right_side);
2727 ResolveFlags rf = ResolveFlags.VariableOrValue;
2729 rf |= ResolveFlags.DisableFlowAnalysis;
2731 e = e.Resolve (ec, rf);
2734 if (targs != null && e != null)
2735 e.Error_TypeArgumentsCannotBeUsed (ec.Report, loc);
2740 e = current_block.Toplevel.GetParameterReference (Name, loc);
2742 if (right_side != null)
2743 e = e.ResolveLValue (ec, right_side);
2747 if (targs != null && e != null)
2748 e.Error_TypeArgumentsCannotBeUsed (ec.Report, loc);
2755 // Stage 2: Lookup members
2758 Type almost_matched_type = null;
2759 ArrayList almost_matched = null;
2760 for (Type lookup_ds = ec.CurrentType; lookup_ds != null; lookup_ds = lookup_ds.DeclaringType) {
2761 e = MemberLookup (ec.Compiler, ec.CurrentType, lookup_ds, Name, loc);
2763 PropertyExpr pe = e as PropertyExpr;
2765 AParametersCollection param = TypeManager.GetParameterData (pe.PropertyInfo);
2767 // since TypeManager.MemberLookup doesn't know if we're doing a lvalue access or not,
2768 // it doesn't know which accessor to check permissions against
2769 if (param.IsEmpty && pe.IsAccessibleFrom (ec.CurrentType, right_side != null))
2771 } else if (e is EventExpr) {
2772 if (((EventExpr) e).IsAccessibleFrom (ec.CurrentType))
2774 } else if (targs != null && e is TypeExpression) {
2775 e = new GenericTypeExpr (e.Type, targs, loc).ResolveAsTypeStep (ec, false);
2783 if (almost_matched == null && almost_matched_members.Count > 0) {
2784 almost_matched_type = lookup_ds;
2785 almost_matched = (ArrayList) almost_matched_members.Clone ();
2790 if (almost_matched == null && almost_matched_members.Count > 0) {
2791 almost_matched_type = ec.CurrentType;
2792 almost_matched = (ArrayList) almost_matched_members.Clone ();
2794 e = ResolveAsTypeStep (ec, true);
2798 if (current_block != null) {
2799 IKnownVariable ikv = current_block.Explicit.GetKnownVariable (Name);
2801 LocalInfo li = ikv as LocalInfo;
2802 // Supress CS0219 warning
2806 Error_VariableIsUsedBeforeItIsDeclared (ec.Report, Name);
2811 if (RootContext.EvalMode){
2812 FieldInfo fi = Evaluator.LookupField (Name);
2814 return new FieldExpr (fi, loc).Resolve (ec);
2817 if (almost_matched != null)
2818 almost_matched_members = almost_matched;
2819 if (almost_matched_type == null)
2820 almost_matched_type = ec.CurrentType;
2822 string type_name = ec.MemberContext.CurrentType == null ? null : ec.MemberContext.CurrentType.Name;
2823 return Error_MemberLookupFailed (ec, ec.CurrentType, null, almost_matched_type, Name,
2824 type_name, AllMemberTypes, AllBindingFlags);
2827 if (e is MemberExpr) {
2828 MemberExpr me = (MemberExpr) e;
2831 if (me.IsInstance) {
2832 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope)) {
2834 // Note that an MemberExpr can be both IsInstance and IsStatic.
2835 // An unresolved MethodGroupExpr can contain both kinds of methods
2836 // and each predicate is true if the MethodGroupExpr contains
2837 // at least one of that kind of method.
2841 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2842 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2847 // Pass the buck to MemberAccess and Invocation.
2849 left = EmptyExpression.Null;
2851 left = ec.GetThis (loc);
2854 left = new TypeExpression (ec.CurrentType, loc);
2857 me = me.ResolveMemberAccess (ec, left, loc, null);
2861 if (targs != null) {
2862 if (!targs.Resolve (ec))
2865 me.SetTypeArguments (ec, targs);
2868 if (!me.IsStatic && (me.InstanceExpression != null && me.InstanceExpression != EmptyExpression.Null) &&
2869 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2870 me.InstanceExpression.Type != me.DeclaringType &&
2871 !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2872 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2873 ec.Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2874 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2878 return (right_side != null)
2879 ? me.DoResolveLValue (ec, right_side)
2880 : me.DoResolve (ec);
2888 /// Represents a namespace or a type. The name of the class was inspired by
2889 /// section 10.8.1 (Fully Qualified Names).
2891 public abstract class FullNamedExpression : Expression
2893 protected override void CloneTo (CloneContext clonectx, Expression target)
2895 // Do nothing, most unresolved type expressions cannot be
2896 // resolved to different type
2899 public override Expression CreateExpressionTree (ResolveContext ec)
2901 throw new NotSupportedException ("ET");
2904 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2906 throw new NotSupportedException ();
2909 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2914 public override void Emit (EmitContext ec)
2916 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2917 GetSignatureForError ());
2922 /// Expression that evaluates to a type
2924 public abstract class TypeExpr : FullNamedExpression {
2925 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2927 TypeExpr t = DoResolveAsTypeStep (ec);
2931 eclass = ExprClass.Type;
2935 override public Expression DoResolve (ResolveContext ec)
2937 return ResolveAsTypeTerminal (ec, false);
2940 public virtual bool CheckAccessLevel (IMemberContext mc)
2942 return mc.CurrentTypeDefinition.CheckAccessLevel (Type);
2945 public virtual bool IsClass {
2946 get { return Type.IsClass; }
2949 public virtual bool IsValueType {
2950 get { return TypeManager.IsStruct (Type); }
2953 public virtual bool IsInterface {
2954 get { return Type.IsInterface; }
2957 public virtual bool IsSealed {
2958 get { return Type.IsSealed; }
2961 public virtual bool CanInheritFrom ()
2963 if (Type == TypeManager.enum_type ||
2964 (Type == TypeManager.value_type && RootContext.StdLib) ||
2965 Type == TypeManager.multicast_delegate_type ||
2966 Type == TypeManager.delegate_type ||
2967 Type == TypeManager.array_type)
2973 protected abstract TypeExpr DoResolveAsTypeStep (IMemberContext ec);
2975 public override bool Equals (object obj)
2977 TypeExpr tobj = obj as TypeExpr;
2981 return Type == tobj.Type;
2984 public override int GetHashCode ()
2986 return Type.GetHashCode ();
2989 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2991 type = storey.MutateType (type);
2996 /// Fully resolved Expression that already evaluated to a type
2998 public class TypeExpression : TypeExpr {
2999 public TypeExpression (Type t, Location l)
3002 eclass = ExprClass.Type;
3006 protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec)
3011 public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
3018 // Used to create types from a fully qualified name. These are just used
3019 // by the parser to setup the core types.
3021 public sealed class TypeLookupExpression : TypeExpr {
3022 readonly string ns_name;
3023 readonly string name;
3025 public TypeLookupExpression (string ns, string name)
3029 eclass = ExprClass.Type;
3032 public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
3035 // It's null only during mscorlib bootstrap when DefineType
3036 // nees to resolve base type of same type
3038 // For instance struct Char : IComparable<char>
3040 // TODO: it could be removed when Resolve starts to use
3041 // DeclSpace instead of Type
3044 Namespace ns = GlobalRootNamespace.Instance.GetNamespace (ns_name, false);
3045 FullNamedExpression fne = ns.Lookup (ec.Compiler, name, loc);
3053 protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec)
3058 public override string GetSignatureForError ()
3061 return TypeManager.CSharpName (ns_name + "." + name, null);
3063 return base.GetSignatureForError ();
3068 /// This class denotes an expression which evaluates to a member
3069 /// of a struct or a class.
3071 public abstract class MemberExpr : Expression
3073 protected bool is_base;
3076 /// The name of this member.
3078 public abstract string Name {
3083 // When base.member is used
3085 public bool IsBase {
3086 get { return is_base; }
3087 set { is_base = value; }
3091 /// Whether this is an instance member.
3093 public abstract bool IsInstance {
3098 /// Whether this is a static member.
3100 public abstract bool IsStatic {
3105 /// The type which declares this member.
3107 public abstract Type DeclaringType {
3112 /// The instance expression associated with this member, if it's a
3113 /// non-static member.
3115 public Expression InstanceExpression;
3117 public static void error176 (ResolveContext ec, Location loc, string name)
3119 ec.Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
3120 "with an instance reference, qualify it with a type name instead", name);
3123 public static void Error_BaseAccessInExpressionTree (ResolveContext ec, Location loc)
3125 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
3128 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3130 if (InstanceExpression != null)
3131 InstanceExpression.MutateHoistedGenericType (storey);
3134 // TODO: possible optimalization
3135 // Cache resolved constant result in FieldBuilder <-> expression map
3136 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, Location loc,
3137 SimpleName original)
3141 // original == null || original.Resolve (...) ==> left
3144 if (left is TypeExpr) {
3145 left = left.ResolveAsBaseTerminal (ec, false);
3149 // TODO: Same problem as in class.cs, TypeTerminal does not
3150 // always do all necessary checks
3151 ObsoleteAttribute oa = AttributeTester.GetObsoleteAttribute (left.Type);
3152 if (oa != null && !ec.IsObsolete) {
3153 AttributeTester.Report_ObsoleteMessage (oa, left.GetSignatureForError (), loc, ec.Report);
3156 GenericTypeExpr ct = left as GenericTypeExpr;
3157 if (ct != null && !ct.CheckConstraints (ec))
3162 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3170 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3173 return ResolveExtensionMemberAccess (ec, left);
3176 InstanceExpression = left;
3180 protected virtual MemberExpr ResolveExtensionMemberAccess (ResolveContext ec, Expression left)
3182 error176 (ec, loc, GetSignatureForError ());
3186 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3191 if (InstanceExpression == EmptyExpression.Null) {
3192 // FIXME: This should not be here at all
3193 SimpleName.Error_ObjectRefRequired (new ResolveContext (ec.MemberContext), loc, GetSignatureForError ());
3197 if (TypeManager.IsValueType (InstanceExpression.Type)) {
3198 if (InstanceExpression is IMemoryLocation) {
3199 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
3201 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
3202 InstanceExpression.Emit (ec);
3204 t.AddressOf (ec, AddressOp.Store);
3207 InstanceExpression.Emit (ec);
3209 if (prepare_for_load)
3210 ec.ig.Emit (OpCodes.Dup);
3213 public virtual void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3215 // TODO: need to get correct member type
3216 ec.Report.Error (307, loc, "The property `{0}' cannot be used with type arguments",
3217 GetSignatureForError ());
3222 /// Represents group of extension methods
3224 public class ExtensionMethodGroupExpr : MethodGroupExpr
3226 readonly NamespaceEntry namespace_entry;
3227 public Expression ExtensionExpression;
3228 Argument extension_argument;
3230 public ExtensionMethodGroupExpr (ArrayList list, NamespaceEntry n, Type extensionType, Location l)
3231 : base (list, extensionType, l)
3233 this.namespace_entry = n;
3236 public override bool IsStatic {
3237 get { return true; }
3240 public bool IsTopLevel {
3241 get { return namespace_entry == null; }
3244 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3246 extension_argument.Expr.MutateHoistedGenericType (storey);
3247 base.MutateHoistedGenericType (storey);
3250 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, bool may_fail, Location loc)
3252 if (arguments == null)
3253 arguments = new Arguments (1);
3255 arguments.Insert (0, new Argument (ExtensionExpression));
3256 MethodGroupExpr mg = ResolveOverloadExtensions (ec, ref arguments, namespace_entry, loc);
3258 // Store resolved argument and restore original arguments
3260 ((ExtensionMethodGroupExpr)mg).extension_argument = arguments [0];
3262 arguments.RemoveAt (0); // Clean-up modified arguments for error reporting
3267 MethodGroupExpr ResolveOverloadExtensions (ResolveContext ec, ref Arguments arguments, NamespaceEntry ns, Location loc)
3269 // Use normal resolve rules
3270 MethodGroupExpr mg = base.OverloadResolve (ec, ref arguments, ns != null, loc);
3278 ExtensionMethodGroupExpr e = ns.LookupExtensionMethod (type, Name, loc);
3280 return base.OverloadResolve (ec, ref arguments, false, loc);
3282 e.ExtensionExpression = ExtensionExpression;
3283 e.SetTypeArguments (ec, type_arguments);
3284 return e.ResolveOverloadExtensions (ec, ref arguments, e.namespace_entry, loc);
3289 /// MethodGroupExpr represents a group of method candidates which
3290 /// can be resolved to the best method overload
3292 public class MethodGroupExpr : MemberExpr
3294 public interface IErrorHandler
3296 bool AmbiguousCall (ResolveContext ec, MethodBase ambiguous);
3297 bool NoExactMatch (ResolveContext ec, MethodBase method);
3300 public IErrorHandler CustomErrorHandler;
3301 public MethodBase [] Methods;
3302 MethodBase best_candidate;
3303 // TODO: make private
3304 public TypeArguments type_arguments;
3305 bool identical_type_name;
3306 bool has_inaccessible_candidates_only;
3310 public MethodGroupExpr (MemberInfo [] mi, Type type, Location l)
3313 Methods = new MethodBase [mi.Length];
3314 mi.CopyTo (Methods, 0);
3317 public MethodGroupExpr (MemberInfo[] mi, Type type, Location l, bool inacessibleCandidatesOnly)
3318 : this (mi, type, l)
3320 has_inaccessible_candidates_only = inacessibleCandidatesOnly;
3323 public MethodGroupExpr (ArrayList list, Type type, Location l)
3327 Methods = (MethodBase[])list.ToArray (typeof (MethodBase));
3329 foreach (MemberInfo m in list){
3330 if (!(m is MethodBase)){
3331 Console.WriteLine ("Name " + m.Name);
3332 Console.WriteLine ("Found a: " + m.GetType ().FullName);
3341 protected MethodGroupExpr (Type type, Location loc)
3344 eclass = ExprClass.MethodGroup;
3345 this.type = InternalType.MethodGroup;
3346 queried_type = type;
3349 public override Type DeclaringType {
3351 return queried_type;
3355 public Type DelegateType {
3357 delegate_type = value;
3361 public bool IdenticalTypeName {
3363 return identical_type_name;
3367 public override string GetSignatureForError ()
3369 if (best_candidate != null)
3370 return TypeManager.CSharpSignature (best_candidate);
3372 return TypeManager.CSharpSignature (Methods [0]);
3375 public override string Name {
3377 return Methods [0].Name;
3381 public override bool IsInstance {
3383 if (best_candidate != null)
3384 return !best_candidate.IsStatic;
3386 foreach (MethodBase mb in Methods)
3394 public override bool IsStatic {
3396 if (best_candidate != null)
3397 return best_candidate.IsStatic;
3399 foreach (MethodBase mb in Methods)
3407 public static explicit operator ConstructorInfo (MethodGroupExpr mg)
3409 return (ConstructorInfo)mg.best_candidate;
3412 public static explicit operator MethodInfo (MethodGroupExpr mg)
3414 return (MethodInfo)mg.best_candidate;
3418 // 7.4.3.3 Better conversion from expression
3419 // Returns : 1 if a->p is better,
3420 // 2 if a->q is better,
3421 // 0 if neither is better
3423 static int BetterExpressionConversion (ResolveContext ec, Argument a, Type p, Type q)
3425 Type argument_type = TypeManager.TypeToCoreType (a.Type);
3426 if (argument_type == InternalType.AnonymousMethod && RootContext.Version > LanguageVersion.ISO_2) {
3428 // Uwrap delegate from Expression<T>
3430 if (TypeManager.DropGenericTypeArguments (p) == TypeManager.expression_type) {
3431 p = TypeManager.GetTypeArguments (p) [0];
3433 if (TypeManager.DropGenericTypeArguments (q) == TypeManager.expression_type) {
3434 q = TypeManager.GetTypeArguments (q) [0];
3437 p = Delegate.GetInvokeMethod (ec.Compiler, null, p).ReturnType;
3438 q = Delegate.GetInvokeMethod (ec.Compiler, null, q).ReturnType;
3439 if (p == TypeManager.void_type && q != TypeManager.void_type)
3441 if (q == TypeManager.void_type && p != TypeManager.void_type)
3444 if (argument_type == p)
3447 if (argument_type == q)
3451 return BetterTypeConversion (ec, p, q);
3455 // 7.4.3.4 Better conversion from type
3457 public static int BetterTypeConversion (ResolveContext ec, Type p, Type q)
3459 if (p == null || q == null)
3460 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3462 if (p == TypeManager.int32_type) {
3463 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3465 } else if (p == TypeManager.int64_type) {
3466 if (q == TypeManager.uint64_type)
3468 } else if (p == TypeManager.sbyte_type) {
3469 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3470 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3472 } else if (p == TypeManager.short_type) {
3473 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3474 q == TypeManager.uint64_type)
3478 if (q == TypeManager.int32_type) {
3479 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3481 } if (q == TypeManager.int64_type) {
3482 if (p == TypeManager.uint64_type)
3484 } else if (q == TypeManager.sbyte_type) {
3485 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3486 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3488 } if (q == TypeManager.short_type) {
3489 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3490 p == TypeManager.uint64_type)
3494 // TODO: this is expensive
3495 Expression p_tmp = new EmptyExpression (p);
3496 Expression q_tmp = new EmptyExpression (q);
3498 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3499 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3501 if (p_to_q && !q_to_p)
3504 if (q_to_p && !p_to_q)
3511 /// Determines "Better function" between candidate
3512 /// and the current best match
3515 /// Returns a boolean indicating :
3516 /// false if candidate ain't better
3517 /// true if candidate is better than the current best match
3519 static bool BetterFunction (ResolveContext ec, Arguments args, int argument_count,
3520 MethodBase candidate, bool candidate_params,
3521 MethodBase best, bool best_params)
3523 AParametersCollection candidate_pd = TypeManager.GetParameterData (candidate);
3524 AParametersCollection best_pd = TypeManager.GetParameterData (best);
3526 bool better_at_least_one = false;
3528 for (int j = 0, c_idx = 0, b_idx = 0; j < argument_count; ++j, ++c_idx, ++b_idx)
3530 Argument a = args [j];
3532 // Provided default argument value is never better
3533 if (a.IsDefaultArgument && candidate_params == best_params)
3536 Type ct = candidate_pd.Types [c_idx];
3537 Type bt = best_pd.Types [b_idx];
3539 if (candidate_params && candidate_pd.FixedParameters [c_idx].ModFlags == Parameter.Modifier.PARAMS)
3541 ct = TypeManager.GetElementType (ct);
3545 if (best_params && best_pd.FixedParameters [b_idx].ModFlags == Parameter.Modifier.PARAMS)
3547 bt = TypeManager.GetElementType (bt);
3555 int result = BetterExpressionConversion (ec, a, ct, bt);
3557 // for each argument, the conversion to 'ct' should be no worse than
3558 // the conversion to 'bt'.
3562 // for at least one argument, the conversion to 'ct' should be better than
3563 // the conversion to 'bt'.
3565 better_at_least_one = true;
3568 if (better_at_least_one)
3572 // This handles the case
3574 // Add (float f1, float f2, float f3);
3575 // Add (params decimal [] foo);
3577 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3578 // first candidate would've chosen as better.
3584 // The two methods have equal parameter types. Now apply tie-breaking rules
3586 if (TypeManager.IsGenericMethod (best)) {
3587 if (!TypeManager.IsGenericMethod (candidate))
3589 } else if (TypeManager.IsGenericMethod (candidate)) {
3594 // This handles the following cases:
3596 // Trim () is better than Trim (params char[] chars)
3597 // Concat (string s1, string s2, string s3) is better than
3598 // Concat (string s1, params string [] srest)
3599 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3601 if (!candidate_params && best_params)
3603 if (candidate_params && !best_params)
3606 int candidate_param_count = candidate_pd.Count;
3607 int best_param_count = best_pd.Count;
3609 if (candidate_param_count != best_param_count)
3610 // can only happen if (candidate_params && best_params)
3611 return candidate_param_count > best_param_count && best_pd.HasParams;
3614 // now, both methods have the same number of parameters, and the parameters have the same types
3615 // Pick the "more specific" signature
3618 MethodBase orig_candidate = TypeManager.DropGenericMethodArguments (candidate);
3619 MethodBase orig_best = TypeManager.DropGenericMethodArguments (best);
3621 AParametersCollection orig_candidate_pd = TypeManager.GetParameterData (orig_candidate);
3622 AParametersCollection orig_best_pd = TypeManager.GetParameterData (orig_best);
3624 bool specific_at_least_once = false;
3625 for (int j = 0; j < candidate_param_count; ++j)
3627 Type ct = orig_candidate_pd.Types [j];
3628 Type bt = orig_best_pd.Types [j];
3631 Type specific = MoreSpecific (ct, bt);
3635 specific_at_least_once = true;
3638 if (specific_at_least_once)
3641 // FIXME: handle lifted operators
3647 protected override MemberExpr ResolveExtensionMemberAccess (ResolveContext ec, Expression left)
3650 return base.ResolveExtensionMemberAccess (ec, left);
3653 // When left side is an expression and at least one candidate method is
3654 // static, it can be extension method
3656 InstanceExpression = left;
3660 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, Location loc,
3661 SimpleName original)
3663 if (!(left is TypeExpr) &&
3664 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3665 identical_type_name = true;
3667 return base.ResolveMemberAccess (ec, left, loc, original);
3670 public override Expression CreateExpressionTree (ResolveContext ec)
3672 if (best_candidate == null) {
3673 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3677 IMethodData md = TypeManager.GetMethod (best_candidate);
3678 if (md != null && md.IsExcluded ())
3679 ec.Report.Error (765, loc,
3680 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3682 return new TypeOfMethod (best_candidate, loc);
3685 override public Expression DoResolve (ResolveContext ec)
3687 if (InstanceExpression != null) {
3688 InstanceExpression = InstanceExpression.DoResolve (ec);
3689 if (InstanceExpression == null)
3696 public void ReportUsageError (ResolveContext ec)
3698 ec.Report.Error (654, loc, "Method `" + DeclaringType + "." +
3699 Name + "()' is referenced without parentheses");
3702 override public void Emit (EmitContext ec)
3704 throw new NotSupportedException ();
3705 // ReportUsageError ();
3708 public void EmitCall (EmitContext ec, Arguments arguments)
3710 Invocation.EmitCall (ec, IsBase, InstanceExpression, best_candidate, arguments, loc);
3713 void Error_AmbiguousCall (ResolveContext ec, MethodBase ambiguous)
3715 if (CustomErrorHandler != null && CustomErrorHandler.AmbiguousCall (ec, ambiguous))
3718 ec.Report.SymbolRelatedToPreviousError (best_candidate);
3719 ec.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
3720 TypeManager.CSharpSignature (ambiguous), TypeManager.CSharpSignature (best_candidate));
3723 protected virtual void Error_InvalidArguments (ResolveContext ec, Location loc, int idx, MethodBase method,
3724 Argument a, AParametersCollection expected_par, Type paramType)
3726 ExtensionMethodGroupExpr emg = this as ExtensionMethodGroupExpr;
3728 if (a is CollectionElementInitializer.ElementInitializerArgument) {
3729 ec.Report.SymbolRelatedToPreviousError (method);
3730 if ((expected_par.FixedParameters [idx].ModFlags & Parameter.Modifier.ISBYREF) != 0) {
3731 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
3732 TypeManager.CSharpSignature (method));
3735 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
3736 TypeManager.CSharpSignature (method));
3737 } else if (TypeManager.IsDelegateType (method.DeclaringType)) {
3738 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
3739 TypeManager.CSharpName (method.DeclaringType));
3741 ec.Report.SymbolRelatedToPreviousError (method);
3743 ec.Report.Error (1928, loc,
3744 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3745 emg.ExtensionExpression.GetSignatureForError (),
3746 emg.Name, TypeManager.CSharpSignature (method));
3748 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
3749 TypeManager.CSharpSignature (method));
3753 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters [idx].ModFlags;
3755 string index = (idx + 1).ToString ();
3756 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
3757 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
3758 if ((mod & Parameter.Modifier.ISBYREF) == 0)
3759 ec.Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
3760 index, Parameter.GetModifierSignature (a.Modifier));
3762 ec.Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
3763 index, Parameter.GetModifierSignature (mod));
3765 string p1 = a.GetSignatureForError ();
3766 string p2 = TypeManager.CSharpName (paramType);
3769 ec.Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
3770 ec.Report.SymbolRelatedToPreviousError (a.Expr.Type);
3771 ec.Report.SymbolRelatedToPreviousError (paramType);
3774 if (idx == 0 && emg != null) {
3775 ec.Report.Error (1929, loc,
3776 "Extension method instance type `{0}' cannot be converted to `{1}'", p1, p2);
3778 ec.Report.Error (1503, loc,
3779 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
3784 public override void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, Type target, bool expl)
3786 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3787 Name, TypeManager.CSharpName (target));
3790 void Error_ArgumentCountWrong (ResolveContext ec, int arg_count)
3792 ec.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
3793 Name, arg_count.ToString ());
3796 protected virtual int GetApplicableParametersCount (MethodBase method, AParametersCollection parameters)
3798 return parameters.Count;
3801 public static bool IsAncestralType (Type first_type, Type second_type)
3803 return first_type != second_type &&
3804 (TypeManager.IsSubclassOf (second_type, first_type) ||
3805 TypeManager.ImplementsInterface (second_type, first_type));
3809 /// Determines if the candidate method is applicable (section 14.4.2.1)
3810 /// to the given set of arguments
3811 /// A return value rates candidate method compatibility,
3812 /// 0 = the best, int.MaxValue = the worst
3814 public int IsApplicable (ResolveContext ec,
3815 ref Arguments arguments, int arg_count, ref MethodBase method, ref bool params_expanded_form)
3817 MethodBase candidate = method;
3819 AParametersCollection pd = TypeManager.GetParameterData (candidate);
3820 int param_count = GetApplicableParametersCount (candidate, pd);
3821 int optional_count = 0;
3823 if (arg_count != param_count) {
3824 for (int i = 0; i < pd.Count; ++i) {
3825 if (pd.FixedParameters [i].HasDefaultValue) {
3826 optional_count = pd.Count - i;
3831 int args_gap = Math.Abs (arg_count - param_count);
3832 if (optional_count != 0) {
3833 if (args_gap > optional_count)
3834 return int.MaxValue - 10000 + args_gap - optional_count;
3836 // Readjust expected number when params used
3839 if (arg_count < param_count)
3841 } else if (arg_count > param_count) {
3842 return int.MaxValue - 10000 + args_gap;
3844 } else if (arg_count != param_count) {
3846 return int.MaxValue - 10000 + args_gap;
3847 if (arg_count < param_count - 1)
3848 return int.MaxValue - 10000 + args_gap;
3851 // Initialize expanded form of a method with 1 params parameter
3852 params_expanded_form = param_count == 1 && pd.HasParams;
3854 // Resize to fit optional arguments
3855 if (optional_count != 0) {
3857 if (arguments == null) {
3858 resized = new Arguments (optional_count);
3860 resized = new Arguments (param_count);
3861 resized.AddRange (arguments);
3864 for (int i = arg_count; i < param_count; ++i)
3866 arguments = resized;
3870 if (arg_count > 0) {
3872 // Shuffle named arguments to the right positions if there are any
3874 if (arguments [arg_count - 1] is NamedArgument) {
3875 arg_count = arguments.Count;
3877 for (int i = 0; i < arg_count; ++i) {
3878 bool arg_moved = false;
3880 NamedArgument na = arguments[i] as NamedArgument;
3884 int index = pd.GetParameterIndexByName (na.Name.Value);
3886 // Named parameter not found or already reordered
3890 // When using parameters which should not be available to the user
3891 if (index >= param_count)
3895 arguments.MarkReorderedArgument (na);
3899 Argument temp = arguments[index];
3900 arguments[index] = arguments[i];
3901 arguments[i] = temp;
3908 arg_count = arguments.Count;
3910 } else if (arguments != null) {
3911 arg_count = arguments.Count;
3915 // 1. Handle generic method using type arguments when specified or type inference
3917 if (TypeManager.IsGenericMethod (candidate)) {
3918 if (type_arguments != null) {
3919 Type [] g_args = candidate.GetGenericArguments ();
3920 if (g_args.Length != type_arguments.Count)
3921 return int.MaxValue - 20000 + Math.Abs (type_arguments.Count - g_args.Length);
3923 // TODO: Don't create new method, create Parameters only
3924 method = ((MethodInfo) candidate).MakeGenericMethod (type_arguments.Arguments);
3926 pd = TypeManager.GetParameterData (candidate);
3928 int score = TypeManager.InferTypeArguments (ec, arguments, ref candidate);
3930 return score - 20000;
3932 if (TypeManager.IsGenericMethodDefinition (candidate))
3933 throw new InternalErrorException ("A generic method `{0}' definition took part in overload resolution",
3934 TypeManager.CSharpSignature (candidate));
3936 pd = TypeManager.GetParameterData (candidate);
3939 if (type_arguments != null)
3940 return int.MaxValue - 15000;
3944 // 2. Each argument has to be implicitly convertible to method parameter
3947 Parameter.Modifier p_mod = 0;
3949 for (int i = 0; i < arg_count; i++) {
3950 Argument a = arguments [i];
3952 if (!pd.FixedParameters [i].HasDefaultValue)
3953 throw new InternalErrorException ();
3955 Expression e = pd.FixedParameters [i].DefaultValue as Constant;
3957 e = new DefaultValueExpression (new TypeExpression (pd.Types [i], loc), loc).Resolve (ec);
3959 arguments [i] = new Argument (e, Argument.AType.Default);
3963 if (p_mod != Parameter.Modifier.PARAMS) {
3964 p_mod = pd.FixedParameters [i].ModFlags & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3967 params_expanded_form = true;
3970 Parameter.Modifier a_mod = a.Modifier & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3972 if (!params_expanded_form)
3973 score = IsArgumentCompatible (ec, a_mod, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
3975 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && delegate_type == null) {
3976 // It can be applicable in expanded form
3977 score = IsArgumentCompatible (ec, a_mod, a, 0, TypeManager.GetElementType (pt));
3979 params_expanded_form = true;
3983 if (params_expanded_form)
3985 return (arg_count - i) * 2 + score;
3989 if (arg_count != param_count)
3990 params_expanded_form = true;
3995 int IsArgumentCompatible (ResolveContext ec, Parameter.Modifier arg_mod, Argument argument, Parameter.Modifier param_mod, Type parameter)
3998 // Types have to be identical when ref or out modifer is used
4000 if (arg_mod != 0 || param_mod != 0) {
4001 if (TypeManager.HasElementType (parameter))
4002 parameter = TypeManager.GetElementType (parameter);
4004 Type a_type = argument.Type;
4005 if (TypeManager.HasElementType (a_type))
4006 a_type = TypeManager.GetElementType (a_type);
4008 if (a_type != parameter)
4011 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter))
4015 if (arg_mod != param_mod)
4021 public static bool IsOverride (MethodBase cand_method, MethodBase base_method)
4023 if (!IsAncestralType (base_method.DeclaringType, cand_method.DeclaringType))
4026 AParametersCollection cand_pd = TypeManager.GetParameterData (cand_method);
4027 AParametersCollection base_pd = TypeManager.GetParameterData (base_method);
4029 if (cand_pd.Count != base_pd.Count)
4032 for (int j = 0; j < cand_pd.Count; ++j)
4034 Parameter.Modifier cm = cand_pd.FixedParameters [j].ModFlags;
4035 Parameter.Modifier bm = base_pd.FixedParameters [j].ModFlags;
4036 Type ct = cand_pd.Types [j];
4037 Type bt = base_pd.Types [j];
4039 if (cm != bm || ct != bt)
4046 public static MethodGroupExpr MakeUnionSet (MethodGroupExpr mg1, MethodGroupExpr mg2, Location loc)
4057 ArrayList all = new ArrayList (mg1.Methods);
4058 foreach (MethodBase m in mg2.Methods){
4059 if (!TypeManager.ArrayContainsMethod (mg1.Methods, m, false))
4063 return new MethodGroupExpr (all, null, loc);
4066 static Type MoreSpecific (Type p, Type q)
4068 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4070 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4073 if (TypeManager.HasElementType (p))
4075 Type pe = TypeManager.GetElementType (p);
4076 Type qe = TypeManager.GetElementType (q);
4077 Type specific = MoreSpecific (pe, qe);
4083 else if (TypeManager.IsGenericType (p))
4085 Type[] pargs = TypeManager.GetTypeArguments (p);
4086 Type[] qargs = TypeManager.GetTypeArguments (q);
4088 bool p_specific_at_least_once = false;
4089 bool q_specific_at_least_once = false;
4091 for (int i = 0; i < pargs.Length; i++)
4093 Type specific = MoreSpecific (TypeManager.TypeToCoreType (pargs [i]), TypeManager.TypeToCoreType (qargs [i]));
4094 if (specific == pargs [i])
4095 p_specific_at_least_once = true;
4096 if (specific == qargs [i])
4097 q_specific_at_least_once = true;
4100 if (p_specific_at_least_once && !q_specific_at_least_once)
4102 if (!p_specific_at_least_once && q_specific_at_least_once)
4109 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4111 base.MutateHoistedGenericType (storey);
4113 MethodInfo mi = best_candidate as MethodInfo;
4115 best_candidate = storey.MutateGenericMethod (mi);
4119 best_candidate = storey.MutateConstructor ((ConstructorInfo) this);
4123 /// Find the Applicable Function Members (7.4.2.1)
4125 /// me: Method Group expression with the members to select.
4126 /// it might contain constructors or methods (or anything
4127 /// that maps to a method).
4129 /// Arguments: ArrayList containing resolved Argument objects.
4131 /// loc: The location if we want an error to be reported, or a Null
4132 /// location for "probing" purposes.
4134 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4135 /// that is the best match of me on Arguments.
4138 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments Arguments,
4139 bool may_fail, Location loc)
4141 bool method_params = false;
4142 Type applicable_type = null;
4143 ArrayList candidates = new ArrayList (2);
4144 ArrayList candidate_overrides = null;
4147 // Used to keep a map between the candidate
4148 // and whether it is being considered in its
4149 // normal or expanded form
4151 // false is normal form, true is expanded form
4153 Hashtable candidate_to_form = null;
4154 Hashtable candidates_expanded = null;
4155 Arguments candidate_args = Arguments;
4157 int arg_count = Arguments != null ? Arguments.Count : 0;
4159 if (RootContext.Version == LanguageVersion.ISO_1 && Name == "Invoke" && TypeManager.IsDelegateType (DeclaringType)) {
4161 ec.Report.Error (1533, loc, "Invoke cannot be called directly on a delegate");
4165 int nmethods = Methods.Length;
4169 // Methods marked 'override' don't take part in 'applicable_type'
4170 // computation, nor in the actual overload resolution.
4171 // However, they still need to be emitted instead of a base virtual method.
4172 // So, we salt them away into the 'candidate_overrides' array.
4174 // In case of reflected methods, we replace each overriding method with
4175 // its corresponding base virtual method. This is to improve compatibility
4176 // with non-C# libraries which change the visibility of overrides (#75636)
4179 for (int i = 0; i < Methods.Length; ++i) {
4180 MethodBase m = Methods [i];
4181 if (TypeManager.IsOverride (m)) {
4182 if (candidate_overrides == null)
4183 candidate_overrides = new ArrayList ();
4184 candidate_overrides.Add (m);
4185 m = TypeManager.TryGetBaseDefinition (m);
4194 // Enable message recording, it's used mainly by lambda expressions
4196 SessionReportPrinter msg_recorder = new SessionReportPrinter ();
4197 ReportPrinter prev_recorder = ec.Report.SetPrinter (msg_recorder);
4200 // First we construct the set of applicable methods
4202 bool is_sorted = true;
4203 int best_candidate_rate = int.MaxValue;
4204 for (int i = 0; i < nmethods; i++) {
4205 Type decl_type = Methods [i].DeclaringType;
4208 // If we have already found an applicable method
4209 // we eliminate all base types (Section 14.5.5.1)
4211 if (applicable_type != null && IsAncestralType (decl_type, applicable_type))
4215 // Check if candidate is applicable (section 14.4.2.1)
4217 bool params_expanded_form = false;
4218 int candidate_rate = IsApplicable (ec, ref candidate_args, arg_count, ref Methods [i], ref params_expanded_form);
4220 if (candidate_rate < best_candidate_rate) {
4221 best_candidate_rate = candidate_rate;
4222 best_candidate = Methods [i];
4225 if (params_expanded_form) {
4226 if (candidate_to_form == null)
4227 candidate_to_form = new PtrHashtable ();
4228 MethodBase candidate = Methods [i];
4229 candidate_to_form [candidate] = candidate;
4232 if (candidate_args != Arguments) {
4233 if (candidates_expanded == null)
4234 candidates_expanded = new Hashtable (2);
4236 candidates_expanded.Add (Methods [i], candidate_args);
4237 candidate_args = Arguments;
4240 if (candidate_rate != 0 || has_inaccessible_candidates_only) {
4241 if (msg_recorder != null)
4242 msg_recorder.EndSession ();
4246 msg_recorder = null;
4247 candidates.Add (Methods [i]);
4249 if (applicable_type == null)
4250 applicable_type = decl_type;
4251 else if (applicable_type != decl_type) {
4253 if (IsAncestralType (applicable_type, decl_type))
4254 applicable_type = decl_type;
4258 ec.Report.SetPrinter (prev_recorder);
4259 if (msg_recorder != null && !msg_recorder.IsEmpty) {
4261 msg_recorder.Merge (prev_recorder);
4266 int candidate_top = candidates.Count;
4268 if (applicable_type == null) {
4270 // When we found a top level method which does not match and it's
4271 // not an extension method. We start extension methods lookup from here
4273 if (InstanceExpression != null) {
4274 ExtensionMethodGroupExpr ex_method_lookup = ec.LookupExtensionMethod (type, Name, loc);
4275 if (ex_method_lookup != null) {
4276 ex_method_lookup.ExtensionExpression = InstanceExpression;
4277 ex_method_lookup.SetTypeArguments (ec, type_arguments);
4278 return ex_method_lookup.OverloadResolve (ec, ref Arguments, may_fail, loc);
4286 // Okay so we have failed to find exact match so we
4287 // return error info about the closest match
4289 if (best_candidate != null) {
4290 if (CustomErrorHandler != null && !has_inaccessible_candidates_only && CustomErrorHandler.NoExactMatch (ec, best_candidate))
4293 AParametersCollection pd = TypeManager.GetParameterData (best_candidate);
4294 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4295 if (arg_count == pd.Count || pd.HasParams) {
4296 if (TypeManager.IsGenericMethodDefinition (best_candidate)) {
4297 if (type_arguments == null) {
4298 ec.Report.Error (411, loc,
4299 "The type arguments for method `{0}' cannot be inferred from " +
4300 "the usage. Try specifying the type arguments explicitly",
4301 TypeManager.CSharpSignature (best_candidate));
4305 Type[] g_args = TypeManager.GetGenericArguments (best_candidate);
4306 if (type_arguments.Count != g_args.Length) {
4307 ec.Report.SymbolRelatedToPreviousError (best_candidate);
4308 ec.Report.Error (305, loc, "Using the generic method `{0}' requires `{1}' type argument(s)",
4309 TypeManager.CSharpSignature (best_candidate),
4310 g_args.Length.ToString ());
4314 if (type_arguments != null && !TypeManager.IsGenericMethod (best_candidate)) {
4315 Error_TypeArgumentsCannotBeUsed (ec.Report, loc);
4320 if (has_inaccessible_candidates_only) {
4321 if (InstanceExpression != null && type != ec.CurrentType && TypeManager.IsNestedFamilyAccessible (ec.CurrentType, best_candidate.DeclaringType)) {
4322 // Although a derived class can access protected members of
4323 // its base class it cannot do so through an instance of the
4324 // base class (CS1540). If the qualifier_type is a base of the
4325 // ec.CurrentType and the lookup succeeds with the latter one,
4326 // then we are in this situation.
4327 Error_CannotAccessProtected (ec, loc, best_candidate, queried_type, ec.CurrentType);
4329 ec.Report.SymbolRelatedToPreviousError (best_candidate);
4330 ErrorIsInaccesible (loc, GetSignatureForError (), ec.Report);
4334 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate, cand_params, may_fail, loc))
4337 if (has_inaccessible_candidates_only)
4340 throw new InternalErrorException ("VerifyArgumentsCompat didn't find any problem with rejected candidate " + best_candidate);
4345 // We failed to find any method with correct argument count
4347 if (Name == ConstructorInfo.ConstructorName) {
4348 ec.Report.SymbolRelatedToPreviousError (queried_type);
4349 ec.Report.Error (1729, loc,
4350 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4351 TypeManager.CSharpName (queried_type), arg_count);
4353 Error_ArgumentCountWrong (ec, arg_count);
4361 // At this point, applicable_type is _one_ of the most derived types
4362 // in the set of types containing the methods in this MethodGroup.
4363 // Filter the candidates so that they only contain methods from the
4364 // most derived types.
4367 int finalized = 0; // Number of finalized candidates
4370 // Invariant: applicable_type is a most derived type
4372 // We'll try to complete Section 14.5.5.1 for 'applicable_type' by
4373 // eliminating all it's base types. At the same time, we'll also move
4374 // every unrelated type to the end of the array, and pick the next
4375 // 'applicable_type'.
4377 Type next_applicable_type = null;
4378 int j = finalized; // where to put the next finalized candidate
4379 int k = finalized; // where to put the next undiscarded candidate
4380 for (int i = finalized; i < candidate_top; ++i) {
4381 MethodBase candidate = (MethodBase) candidates [i];
4382 Type decl_type = candidate.DeclaringType;
4384 if (decl_type == applicable_type) {
4385 candidates [k++] = candidates [j];
4386 candidates [j++] = candidates [i];
4390 if (IsAncestralType (decl_type, applicable_type))
4393 if (next_applicable_type != null &&
4394 IsAncestralType (decl_type, next_applicable_type))
4397 candidates [k++] = candidates [i];
4399 if (next_applicable_type == null ||
4400 IsAncestralType (next_applicable_type, decl_type))
4401 next_applicable_type = decl_type;
4404 applicable_type = next_applicable_type;
4407 } while (applicable_type != null);
4411 // Now we actually find the best method
4414 best_candidate = (MethodBase) candidates [0];
4415 method_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4418 // TODO: Broken inverse order of candidates logic does not work with optional
4419 // parameters used for method overrides and I am not going to fix it for SRE
4421 if (candidates_expanded != null && candidates_expanded.Contains (best_candidate)) {
4422 candidate_args = (Arguments) candidates_expanded [best_candidate];
4423 arg_count = candidate_args.Count;
4426 for (int ix = 1; ix < candidate_top; ix++) {
4427 MethodBase candidate = (MethodBase) candidates [ix];
4429 if (candidate == best_candidate)
4432 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4434 if (BetterFunction (ec, candidate_args, arg_count,
4435 candidate, cand_params,
4436 best_candidate, method_params)) {
4437 best_candidate = candidate;
4438 method_params = cand_params;
4442 // Now check that there are no ambiguities i.e the selected method
4443 // should be better than all the others
4445 MethodBase ambiguous = null;
4446 for (int ix = 1; ix < candidate_top; ix++) {
4447 MethodBase candidate = (MethodBase) candidates [ix];
4449 if (candidate == best_candidate)
4452 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4453 if (!BetterFunction (ec, candidate_args, arg_count,
4454 best_candidate, method_params,
4455 candidate, cand_params))
4458 ec.Report.SymbolRelatedToPreviousError (candidate);
4459 ambiguous = candidate;
4463 if (ambiguous != null) {
4464 Error_AmbiguousCall (ec, ambiguous);
4469 // If the method is a virtual function, pick an override closer to the LHS type.
4471 if (!IsBase && best_candidate.IsVirtual) {
4472 if (TypeManager.IsOverride (best_candidate))
4473 throw new InternalErrorException (
4474 "Should not happen. An 'override' method took part in overload resolution: " + best_candidate);
4476 if (candidate_overrides != null) {
4477 Type[] gen_args = null;
4478 bool gen_override = false;
4479 if (TypeManager.IsGenericMethod (best_candidate))
4480 gen_args = TypeManager.GetGenericArguments (best_candidate);
4482 foreach (MethodBase candidate in candidate_overrides) {
4483 if (TypeManager.IsGenericMethod (candidate)) {
4484 if (gen_args == null)
4487 if (gen_args.Length != TypeManager.GetGenericArguments (candidate).Length)
4490 if (gen_args != null)
4494 if (IsOverride (candidate, best_candidate)) {
4495 gen_override = true;
4496 best_candidate = candidate;
4500 if (gen_override && gen_args != null) {
4501 best_candidate = ((MethodInfo) best_candidate).MakeGenericMethod (gen_args);
4507 // And now check if the arguments are all
4508 // compatible, perform conversions if
4509 // necessary etc. and return if everything is
4512 if (!VerifyArgumentsCompat (ec, ref candidate_args, arg_count, best_candidate,
4513 method_params, may_fail, loc))
4516 if (best_candidate == null)
4519 MethodBase the_method = TypeManager.DropGenericMethodArguments (best_candidate);
4520 if (TypeManager.IsGenericMethodDefinition (the_method) &&
4521 !ConstraintChecker.CheckConstraints (ec, the_method, best_candidate, loc))
4525 // Check ObsoleteAttribute on the best method
4527 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (the_method);
4528 if (oa != null && !ec.IsObsolete)
4529 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
4531 IMethodData data = TypeManager.GetMethod (the_method);
4533 data.SetMemberIsUsed ();
4535 Arguments = candidate_args;
4539 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4541 type_arguments = ta;
4544 public bool VerifyArgumentsCompat (ResolveContext ec, ref Arguments arguments,
4545 int arg_count, MethodBase method,
4546 bool chose_params_expanded,
4547 bool may_fail, Location loc)
4549 AParametersCollection pd = TypeManager.GetParameterData (method);
4550 int param_count = GetApplicableParametersCount (method, pd);
4552 int errors = ec.Report.Errors;
4553 Parameter.Modifier p_mod = 0;
4555 int a_idx = 0, a_pos = 0;
4557 ArrayList params_initializers = null;
4558 bool has_unsafe_arg = method is MethodInfo ? ((MethodInfo) method).ReturnType.IsPointer : false;
4560 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4561 a = arguments [a_idx];
4562 if (p_mod != Parameter.Modifier.PARAMS) {
4563 p_mod = pd.FixedParameters [a_idx].ModFlags;
4564 pt = pd.Types [a_idx];
4565 has_unsafe_arg |= pt.IsPointer;
4567 if (p_mod == Parameter.Modifier.PARAMS) {
4568 if (chose_params_expanded) {
4569 params_initializers = new ArrayList (arg_count - a_idx);
4570 pt = TypeManager.GetElementType (pt);
4576 // Types have to be identical when ref or out modifer is used
4578 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4579 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4582 if (!TypeManager.IsEqual (a.Expr.Type, pt))
4587 NamedArgument na = a as NamedArgument;
4589 int name_index = pd.GetParameterIndexByName (na.Name.Value);
4590 if (name_index < 0 || name_index >= param_count) {
4591 if (DeclaringType != null && TypeManager.IsDelegateType (DeclaringType)) {
4592 ec.Report.SymbolRelatedToPreviousError (DeclaringType);
4593 ec.Report.Error (1746, na.Name.Location,
4594 "The delegate `{0}' does not contain a parameter named `{1}'",
4595 TypeManager.CSharpName (DeclaringType), na.Name.Value);
4597 ec.Report.SymbolRelatedToPreviousError (best_candidate);
4598 ec.Report.Error (1739, na.Name.Location,
4599 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
4600 TypeManager.CSharpSignature (method), na.Name.Value);
4602 } else if (arguments[name_index] != a) {
4603 if (DeclaringType != null && TypeManager.IsDelegateType (DeclaringType))
4604 ec.Report.SymbolRelatedToPreviousError (DeclaringType);
4606 ec.Report.SymbolRelatedToPreviousError (best_candidate);
4608 ec.Report.Error (1744, na.Name.Location,
4609 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
4615 if (delegate_type != null && !Delegate.IsTypeCovariant (a.Expr, pt))
4618 Expression conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4623 // Convert params arguments to an array initializer
4625 if (params_initializers != null) {
4626 // we choose to use 'a.Expr' rather than 'conv' so that
4627 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
4628 params_initializers.Add (a.Expr);
4629 arguments.RemoveAt (a_idx--);
4634 // Update the argument with the implicit conversion
4638 if (a_idx != arg_count) {
4639 if (!may_fail && ec.Report.Errors == errors) {
4640 if (CustomErrorHandler != null)
4641 CustomErrorHandler.NoExactMatch (ec, best_candidate);
4643 Error_InvalidArguments (ec, loc, a_pos, method, a, pd, pt);
4649 // Fill not provided arguments required by params modifier
4651 if (params_initializers == null && pd.HasParams && arg_count + 1 == param_count) {
4652 if (arguments == null)
4653 arguments = new Arguments (1);
4655 pt = pd.Types [param_count - 1];
4656 pt = TypeManager.GetElementType (pt);
4657 has_unsafe_arg |= pt.IsPointer;
4658 params_initializers = new ArrayList (0);
4662 // Append an array argument with all params arguments
4664 if (params_initializers != null) {
4665 arguments.Add (new Argument (
4666 new ArrayCreation (new TypeExpression (pt, loc), "[]",
4667 params_initializers, loc).Resolve (ec)));
4671 if (arg_count < param_count) {
4673 Error_ArgumentCountWrong (ec, arg_count);
4677 if (has_unsafe_arg && !ec.IsUnsafe) {
4679 UnsafeError (ec, loc);
4687 public class ConstantExpr : MemberExpr
4691 public ConstantExpr (FieldInfo constant, Location loc)
4693 this.constant = constant;
4697 public override string Name {
4698 get { throw new NotImplementedException (); }
4701 public override bool IsInstance {
4702 get { return !IsStatic; }
4705 public override bool IsStatic {
4706 get { return constant.IsStatic; }
4709 public override Type DeclaringType {
4710 get { return constant.DeclaringType; }
4713 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, Location loc, SimpleName original)
4715 constant = TypeManager.GetGenericFieldDefinition (constant);
4717 IConstant ic = TypeManager.GetConstant (constant);
4719 if (constant.IsLiteral) {
4720 ic = new ExternalConstant (constant);
4722 ic = ExternalConstant.CreateDecimal (constant);
4723 // HACK: decimal field was not resolved as constant
4725 return new FieldExpr (constant, loc).ResolveMemberAccess (ec, left, loc, original);
4727 TypeManager.RegisterConstant (constant, ic);
4730 return base.ResolveMemberAccess (ec, left, loc, original);
4733 public override Expression CreateExpressionTree (ResolveContext ec)
4735 throw new NotSupportedException ("ET");
4738 public override Expression DoResolve (ResolveContext ec)
4740 IConstant ic = TypeManager.GetConstant (constant);
4741 if (ic.ResolveValue ()) {
4743 ic.CheckObsoleteness (loc);
4746 return ic.CreateConstantReference (loc);
4749 public override void Emit (EmitContext ec)
4751 throw new NotSupportedException ();
4754 public override string GetSignatureForError ()
4756 return TypeManager.GetFullNameSignature (constant);
4761 /// Fully resolved expression that evaluates to a Field
4763 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference {
4764 public FieldInfo FieldInfo;
4765 readonly Type constructed_generic_type;
4766 VariableInfo variable_info;
4768 LocalTemporary temp;
4771 protected FieldExpr (Location l)
4776 public FieldExpr (FieldInfo fi, Location l)
4779 type = TypeManager.TypeToCoreType (fi.FieldType);
4783 public FieldExpr (FieldInfo fi, Type genericType, Location l)
4786 if (TypeManager.IsGenericTypeDefinition (genericType))
4788 this.constructed_generic_type = genericType;
4791 public override string Name {
4793 return FieldInfo.Name;
4797 public override bool IsInstance {
4799 return !FieldInfo.IsStatic;
4803 public override bool IsStatic {
4805 return FieldInfo.IsStatic;
4809 public override Type DeclaringType {
4811 return FieldInfo.DeclaringType;
4815 public override string GetSignatureForError ()
4817 return TypeManager.GetFullNameSignature (FieldInfo);
4820 public VariableInfo VariableInfo {
4822 return variable_info;
4826 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, Location loc,
4827 SimpleName original)
4829 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
4830 Type t = fi.FieldType;
4832 if (t.IsPointer && !ec.IsUnsafe) {
4833 UnsafeError (ec, loc);
4836 return base.ResolveMemberAccess (ec, left, loc, original);
4839 public void SetHasAddressTaken ()
4841 IVariableReference vr = InstanceExpression as IVariableReference;
4843 vr.SetHasAddressTaken ();
4846 public override Expression CreateExpressionTree (ResolveContext ec)
4848 Expression instance;
4849 if (InstanceExpression == null) {
4850 instance = new NullLiteral (loc);
4852 instance = InstanceExpression.CreateExpressionTree (ec);
4855 Arguments args = Arguments.CreateForExpressionTree (ec, null,
4857 CreateTypeOfExpression ());
4859 return CreateExpressionFactoryCall (ec, "Field", args);
4862 public Expression CreateTypeOfExpression ()
4864 return new TypeOfField (GetConstructedFieldInfo (), loc);
4867 override public Expression DoResolve (ResolveContext ec)
4869 return DoResolve (ec, false, false);
4872 Expression DoResolve (ResolveContext ec, bool lvalue_instance, bool out_access)
4874 if (!FieldInfo.IsStatic){
4875 if (InstanceExpression == null){
4877 // This can happen when referencing an instance field using
4878 // a fully qualified type expression: TypeName.InstanceField = xxx
4880 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4884 // Resolve the field's instance expression while flow analysis is turned
4885 // off: when accessing a field "a.b", we must check whether the field
4886 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4888 if (lvalue_instance) {
4889 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
4890 Expression right_side =
4891 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4893 if (InstanceExpression != EmptyExpression.Null)
4894 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
4897 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
4899 if (InstanceExpression != EmptyExpression.Null)
4900 InstanceExpression = InstanceExpression.Resolve (ec, rf);
4903 if (InstanceExpression == null)
4906 using (ec.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
4907 InstanceExpression.CheckMarshalByRefAccess (ec);
4911 // TODO: the code above uses some non-standard multi-resolve rules
4912 if (eclass != ExprClass.Invalid)
4915 if (!ec.IsObsolete) {
4916 FieldBase f = TypeManager.GetField (FieldInfo);
4918 f.CheckObsoleteness (loc);
4920 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
4922 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc, ec.Report);
4926 IFixedBuffer fb = AttributeTester.GetFixedBuffer (FieldInfo);
4927 IVariableReference var = InstanceExpression as IVariableReference;
4930 IFixedExpression fe = InstanceExpression as IFixedExpression;
4931 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
4932 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4935 if (InstanceExpression.eclass != ExprClass.Variable) {
4936 ec.Report.SymbolRelatedToPreviousError (FieldInfo);
4937 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4938 TypeManager.GetFullNameSignature (FieldInfo));
4939 } else if (var != null && var.IsHoisted) {
4940 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
4943 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4946 eclass = ExprClass.Variable;
4948 // If the instance expression is a local variable or parameter.
4949 if (var == null || var.VariableInfo == null)
4952 VariableInfo vi = var.VariableInfo;
4953 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
4956 variable_info = vi.GetSubStruct (FieldInfo.Name);
4957 eclass = ExprClass.Variable;
4961 static readonly int [] codes = {
4962 191, // instance, write access
4963 192, // instance, out access
4964 198, // static, write access
4965 199, // static, out access
4966 1648, // member of value instance, write access
4967 1649, // member of value instance, out access
4968 1650, // member of value static, write access
4969 1651 // member of value static, out access
4972 static readonly string [] msgs = {
4973 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4974 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4975 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4976 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4977 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4978 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4979 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4980 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4983 // The return value is always null. Returning a value simplifies calling code.
4984 Expression Report_AssignToReadonly (ResolveContext ec, Expression right_side)
4987 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4991 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4993 ec.Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4998 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5000 IVariableReference var = InstanceExpression as IVariableReference;
5001 if (var != null && var.VariableInfo != null)
5002 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
5004 bool lvalue_instance = !FieldInfo.IsStatic && TypeManager.IsValueType (FieldInfo.DeclaringType);
5005 bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
5007 Expression e = DoResolve (ec, lvalue_instance, out_access);
5012 FieldBase fb = TypeManager.GetField (FieldInfo);
5016 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
5017 (fb.ModFlags & Modifiers.VOLATILE) != 0) {
5018 ec.Report.Warning (420, 1, loc,
5019 "`{0}': A volatile field references will not be treated as volatile",
5020 fb.GetSignatureForError ());
5024 if (FieldInfo.IsInitOnly) {
5025 // InitOnly fields can only be assigned in constructors or initializers
5026 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
5027 return Report_AssignToReadonly (ec, right_side);
5029 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
5030 Type ctype = ec.CurrentType;
5032 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
5033 if (!TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
5034 return Report_AssignToReadonly (ec, right_side);
5035 // static InitOnly fields cannot be assigned-to in an instance constructor
5036 if (IsStatic && !ec.IsStatic)
5037 return Report_AssignToReadonly (ec, right_side);
5038 // instance constructors can't modify InitOnly fields of other instances of the same type
5039 if (!IsStatic && !(InstanceExpression is This))
5040 return Report_AssignToReadonly (ec, right_side);
5044 if (right_side == EmptyExpression.OutAccess &&
5045 !IsStatic && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type)) {
5046 ec.Report.SymbolRelatedToPreviousError (DeclaringType);
5047 ec.Report.Warning (197, 1, loc,
5048 "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",
5049 GetSignatureForError ());
5052 eclass = ExprClass.Variable;
5056 bool is_marshal_by_ref ()
5058 return !IsStatic && TypeManager.IsStruct (Type) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type);
5061 public override void CheckMarshalByRefAccess (ResolveContext ec)
5063 if (is_marshal_by_ref () && !(InstanceExpression is This)) {
5064 ec.Report.SymbolRelatedToPreviousError (DeclaringType);
5065 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",
5066 GetSignatureForError ());
5070 public override int GetHashCode ()
5072 return FieldInfo.GetHashCode ();
5075 public bool IsFixed {
5078 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
5080 IVariableReference variable = InstanceExpression as IVariableReference;
5081 if (variable != null)
5082 return TypeManager.IsStruct (InstanceExpression.Type) && variable.IsFixed;
5084 IFixedExpression fe = InstanceExpression as IFixedExpression;
5085 return fe != null && fe.IsFixed;
5089 public bool IsHoisted {
5091 IVariableReference hv = InstanceExpression as IVariableReference;
5092 return hv != null && hv.IsHoisted;
5096 public override bool Equals (object obj)
5098 FieldExpr fe = obj as FieldExpr;
5102 if (FieldInfo != fe.FieldInfo)
5105 if (InstanceExpression == null || fe.InstanceExpression == null)
5108 return InstanceExpression.Equals (fe.InstanceExpression);
5111 public void Emit (EmitContext ec, bool leave_copy)
5113 ILGenerator ig = ec.ig;
5114 bool is_volatile = false;
5116 FieldBase f = TypeManager.GetField (FieldInfo);
5118 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
5121 f.SetMemberIsUsed ();
5124 if (FieldInfo.IsStatic){
5126 ig.Emit (OpCodes.Volatile);
5128 ig.Emit (OpCodes.Ldsfld, GetConstructedFieldInfo ());
5131 EmitInstance (ec, false);
5133 // Optimization for build-in types
5134 if (TypeManager.IsStruct (type) && TypeManager.IsEqual (type, ec.MemberContext.CurrentType)) {
5135 LoadFromPtr (ig, type);
5137 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
5139 ig.Emit (OpCodes.Ldflda, GetConstructedFieldInfo ());
5140 ig.Emit (OpCodes.Ldflda, ff.Element);
5143 ig.Emit (OpCodes.Volatile);
5145 ig.Emit (OpCodes.Ldfld, GetConstructedFieldInfo ());
5151 ec.ig.Emit (OpCodes.Dup);
5152 if (!FieldInfo.IsStatic) {
5153 temp = new LocalTemporary (this.Type);
5159 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5161 FieldAttributes fa = FieldInfo.Attributes;
5162 bool is_static = (fa & FieldAttributes.Static) != 0;
5163 ILGenerator ig = ec.ig;
5165 prepared = prepare_for_load;
5166 EmitInstance (ec, prepared);
5170 ec.ig.Emit (OpCodes.Dup);
5171 if (!FieldInfo.IsStatic) {
5172 temp = new LocalTemporary (this.Type);
5177 FieldBase f = TypeManager.GetField (FieldInfo);
5179 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
5180 ig.Emit (OpCodes.Volatile);
5186 ig.Emit (OpCodes.Stsfld, GetConstructedFieldInfo ());
5188 ig.Emit (OpCodes.Stfld, GetConstructedFieldInfo ());
5197 public override void Emit (EmitContext ec)
5202 public override void EmitSideEffect (EmitContext ec)
5204 FieldBase f = TypeManager.GetField (FieldInfo);
5205 bool is_volatile = f != null && (f.ModFlags & Modifiers.VOLATILE) != 0;
5207 if (is_volatile || is_marshal_by_ref ())
5208 base.EmitSideEffect (ec);
5211 public override void Error_VariableIsUsedBeforeItIsDeclared (Report r, string name)
5214 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the field `{1}'",
5215 name, GetSignatureForError ());
5218 public void AddressOf (EmitContext ec, AddressOp mode)
5220 ILGenerator ig = ec.ig;
5222 FieldBase f = TypeManager.GetField (FieldInfo);
5224 if ((mode & AddressOp.Store) != 0)
5226 if ((mode & AddressOp.Load) != 0)
5227 f.SetMemberIsUsed ();
5231 // Handle initonly fields specially: make a copy and then
5232 // get the address of the copy.
5235 if (FieldInfo.IsInitOnly){
5237 if (ec.HasSet (EmitContext.Options.ConstructorScope)){
5238 if (FieldInfo.IsStatic){
5250 local = ig.DeclareLocal (type);
5251 ig.Emit (OpCodes.Stloc, local);
5252 ig.Emit (OpCodes.Ldloca, local);
5257 if (FieldInfo.IsStatic){
5258 ig.Emit (OpCodes.Ldsflda, GetConstructedFieldInfo ());
5261 EmitInstance (ec, false);
5262 ig.Emit (OpCodes.Ldflda, GetConstructedFieldInfo ());
5266 FieldInfo GetConstructedFieldInfo ()
5268 if (constructed_generic_type == null)
5271 return TypeBuilder.GetField (constructed_generic_type, FieldInfo);
5275 public SLE.Expression MakeAssignExpression (BuilderContext ctx)
5277 return MakeExpression (ctx);
5280 public override SLE.Expression MakeExpression (BuilderContext ctx)
5282 return SLE.Expression.Field (InstanceExpression.MakeExpression (ctx), FieldInfo);
5286 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5288 FieldInfo = storey.MutateField (FieldInfo);
5289 base.MutateHoistedGenericType (storey);
5295 /// Expression that evaluates to a Property. The Assign class
5296 /// might set the `Value' expression if we are in an assignment.
5298 /// This is not an LValue because we need to re-write the expression, we
5299 /// can not take data from the stack and store it.
5301 public class PropertyExpr : MemberExpr, IDynamicAssign
5303 public readonly PropertyInfo PropertyInfo;
5304 MethodInfo getter, setter;
5308 TypeArguments targs;
5310 LocalTemporary temp;
5313 public PropertyExpr (Type container_type, PropertyInfo pi, Location l)
5316 eclass = ExprClass.PropertyAccess;
5320 type = TypeManager.TypeToCoreType (pi.PropertyType);
5322 ResolveAccessors (container_type);
5325 public override string Name {
5327 return PropertyInfo.Name;
5331 public override bool IsInstance {
5337 public override bool IsStatic {
5343 public override Expression CreateExpressionTree (ResolveContext ec)
5346 if (IsSingleDimensionalArrayLength ()) {
5347 args = new Arguments (1);
5348 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5349 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
5353 Error_BaseAccessInExpressionTree (ec, loc);
5357 args = new Arguments (2);
5358 if (InstanceExpression == null)
5359 args.Add (new Argument (new NullLiteral (loc)));
5361 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5362 args.Add (new Argument (new TypeOfMethod (getter, loc)));
5363 return CreateExpressionFactoryCall (ec, "Property", args);
5366 public Expression CreateSetterTypeOfExpression ()
5368 return new TypeOfMethod (setter, loc);
5371 public override Type DeclaringType {
5373 return PropertyInfo.DeclaringType;
5377 public override string GetSignatureForError ()
5379 return TypeManager.GetFullNameSignature (PropertyInfo);
5382 void FindAccessors (Type invocation_type)
5384 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
5385 BindingFlags.Static | BindingFlags.Instance |
5386 BindingFlags.DeclaredOnly;
5388 Type current = PropertyInfo.DeclaringType;
5389 for (; current != null; current = current.BaseType) {
5390 MemberInfo[] group = TypeManager.MemberLookup (
5391 invocation_type, invocation_type, current,
5392 MemberTypes.Property, flags, PropertyInfo.Name, null);
5397 if (group.Length != 1)
5398 // Oooops, can this ever happen ?
5401 PropertyInfo pi = (PropertyInfo) group [0];
5404 getter = pi.GetGetMethod (true);
5407 setter = pi.GetSetMethod (true);
5409 MethodInfo accessor = getter != null ? getter : setter;
5411 if (!accessor.IsVirtual)
5417 // We also perform the permission checking here, as the PropertyInfo does not
5418 // hold the information for the accessibility of its setter/getter
5420 // TODO: Refactor to use some kind of cache together with GetPropertyFromAccessor
5421 void ResolveAccessors (Type container_type)
5423 FindAccessors (container_type);
5425 if (getter != null) {
5426 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
5427 IMethodData md = TypeManager.GetMethod (the_getter);
5429 md.SetMemberIsUsed ();
5431 is_static = getter.IsStatic;
5434 if (setter != null) {
5435 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
5436 IMethodData md = TypeManager.GetMethod (the_setter);
5438 md.SetMemberIsUsed ();
5440 is_static = setter.IsStatic;
5445 public SLE.Expression MakeAssignExpression (BuilderContext ctx)
5447 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), setter);
5450 public override SLE.Expression MakeExpression (BuilderContext ctx)
5452 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), getter);
5456 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5458 if (InstanceExpression != null)
5459 InstanceExpression.MutateHoistedGenericType (storey);
5461 type = storey.MutateType (type);
5463 getter = storey.MutateGenericMethod (getter);
5465 setter = storey.MutateGenericMethod (setter);
5468 bool InstanceResolve (ResolveContext ec, bool lvalue_instance, bool must_do_cs1540_check)
5471 InstanceExpression = null;
5475 if (InstanceExpression == null) {
5476 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5480 InstanceExpression = InstanceExpression.DoResolve (ec);
5481 if (lvalue_instance && InstanceExpression != null)
5482 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess);
5484 if (InstanceExpression == null)
5487 InstanceExpression.CheckMarshalByRefAccess (ec);
5489 if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) &&
5490 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.CurrentType) &&
5491 !TypeManager.IsNestedChildOf (ec.CurrentType, InstanceExpression.Type) &&
5492 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.CurrentType)) {
5493 ec.Report.SymbolRelatedToPreviousError (PropertyInfo);
5494 Error_CannotAccessProtected (ec, loc, PropertyInfo, InstanceExpression.Type, ec.CurrentType);
5501 void Error_PropertyNotFound (ResolveContext ec, MethodInfo mi, bool getter)
5503 // TODO: correctly we should compare arguments but it will lead to bigger changes
5504 if (mi is MethodBuilder) {
5505 Error_TypeDoesNotContainDefinition (ec, loc, PropertyInfo.DeclaringType, Name);
5509 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
5511 AParametersCollection iparams = TypeManager.GetParameterData (mi);
5512 sig.Append (getter ? "get_" : "set_");
5514 sig.Append (iparams.GetSignatureForError ());
5516 ec.Report.SymbolRelatedToPreviousError (mi);
5517 ec.Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
5518 Name, sig.ToString ());
5521 public bool IsAccessibleFrom (Type invocation_type, bool lvalue)
5524 MethodInfo accessor = lvalue ? setter : getter;
5525 if (accessor == null && lvalue)
5527 return accessor != null && IsAccessorAccessible (invocation_type, accessor, out dummy);
5530 bool IsSingleDimensionalArrayLength ()
5532 if (DeclaringType != TypeManager.array_type || getter == null || Name != "Length")
5535 string t_name = InstanceExpression.Type.Name;
5536 int t_name_len = t_name.Length;
5537 return t_name_len > 2 && t_name [t_name_len - 2] == '[';
5540 public override Expression DoResolve (ResolveContext ec)
5545 bool must_do_cs1540_check = false;
5546 ec.Report.DisableReporting ();
5547 bool res = ResolveGetter (ec, ref must_do_cs1540_check);
5548 ec.Report.EnableReporting ();
5551 if (InstanceExpression != null) {
5552 Type expr_type = InstanceExpression.Type;
5553 ExtensionMethodGroupExpr ex_method_lookup = ec.LookupExtensionMethod (expr_type, Name, loc);
5554 if (ex_method_lookup != null) {
5555 ex_method_lookup.ExtensionExpression = InstanceExpression;
5556 ex_method_lookup.SetTypeArguments (ec, targs);
5557 return ex_method_lookup.DoResolve (ec);
5561 ResolveGetter (ec, ref must_do_cs1540_check);
5565 if (!InstanceResolve (ec, false, must_do_cs1540_check))
5569 // Only base will allow this invocation to happen.
5571 if (IsBase && getter.IsAbstract) {
5572 Error_CannotCallAbstractBase (ec, TypeManager.GetFullNameSignature (PropertyInfo));
5575 if (PropertyInfo.PropertyType.IsPointer && !ec.IsUnsafe){
5576 UnsafeError (ec, loc);
5579 if (!ec.IsObsolete) {
5580 PropertyBase pb = TypeManager.GetProperty (PropertyInfo);
5582 pb.CheckObsoleteness (loc);
5584 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (PropertyInfo);
5586 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
5595 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5597 if (right_side == EmptyExpression.OutAccess) {
5598 if (ec.CurrentBlock.Toplevel.GetParameterReference (PropertyInfo.Name, loc) is MemberAccess) {
5599 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5602 ec.Report.Error (206, loc, "A property or indexer `{0}' may not be passed as `ref' or `out' parameter",
5603 GetSignatureForError ());
5608 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5609 Error_CannotModifyIntermediateExpressionValue (ec);
5612 if (setter == null){
5614 // The following condition happens if the PropertyExpr was
5615 // created, but is invalid (ie, the property is inaccessible),
5616 // and we did not want to embed the knowledge about this in
5617 // the caller routine. This only avoids double error reporting.
5622 if (ec.CurrentBlock.Toplevel.GetParameterReference (PropertyInfo.Name, loc) is MemberAccess) {
5623 ec.Report.Error (1947, loc, "A range variable `{0}' cannot be assigned to. Consider using `let' clause to store the value",
5626 ec.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
5627 GetSignatureForError ());
5632 if (targs != null) {
5633 base.SetTypeArguments (ec, targs);
5637 if (TypeManager.GetParameterData (setter).Count != 1){
5638 Error_PropertyNotFound (ec, setter, false);
5642 bool must_do_cs1540_check;
5643 if (!IsAccessorAccessible (ec.CurrentType, setter, out must_do_cs1540_check)) {
5644 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
5645 if (pm != null && pm.HasCustomAccessModifier) {
5646 ec.Report.SymbolRelatedToPreviousError (pm);
5647 ec.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5648 TypeManager.CSharpSignature (setter));
5651 ec.Report.SymbolRelatedToPreviousError (setter);
5652 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter), ec.Report);
5657 if (!InstanceResolve (ec, TypeManager.IsStruct (PropertyInfo.DeclaringType), must_do_cs1540_check))
5661 // Only base will allow this invocation to happen.
5663 if (IsBase && setter.IsAbstract){
5664 Error_CannotCallAbstractBase (ec, TypeManager.GetFullNameSignature (PropertyInfo));
5667 if (PropertyInfo.PropertyType.IsPointer && !ec.IsUnsafe) {
5668 UnsafeError (ec, loc);
5671 if (!ec.IsObsolete) {
5672 PropertyBase pb = TypeManager.GetProperty (PropertyInfo);
5674 pb.CheckObsoleteness (loc);
5676 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (PropertyInfo);
5678 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
5685 public override void Emit (EmitContext ec)
5690 public void Emit (EmitContext ec, bool leave_copy)
5693 // Special case: length of single dimension array property is turned into ldlen
5695 if (IsSingleDimensionalArrayLength ()) {
5697 EmitInstance (ec, false);
5698 ec.ig.Emit (OpCodes.Ldlen);
5699 ec.ig.Emit (OpCodes.Conv_I4);
5703 Invocation.EmitCall (ec, IsBase, InstanceExpression, getter, null, loc, prepared, false);
5706 ec.ig.Emit (OpCodes.Dup);
5708 temp = new LocalTemporary (this.Type);
5715 // Implements the IAssignMethod interface for assignments
5717 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5719 Expression my_source = source;
5721 if (prepare_for_load) {
5726 ec.ig.Emit (OpCodes.Dup);
5728 temp = new LocalTemporary (this.Type);
5732 } else if (leave_copy) {
5734 temp = new LocalTemporary (this.Type);
5739 Arguments args = new Arguments (1);
5740 args.Add (new Argument (my_source));
5742 Invocation.EmitCall (ec, IsBase, InstanceExpression, setter, args, loc, false, prepared);
5750 bool ResolveGetter (ResolveContext ec, ref bool must_do_cs1540_check)
5752 if (targs != null) {
5753 base.SetTypeArguments (ec, targs);
5757 if (getter != null) {
5758 if (TypeManager.GetParameterData (getter).Count != 0) {
5759 Error_PropertyNotFound (ec, getter, true);
5764 if (getter == null) {
5766 // The following condition happens if the PropertyExpr was
5767 // created, but is invalid (ie, the property is inaccessible),
5768 // and we did not want to embed the knowledge about this in
5769 // the caller routine. This only avoids double error reporting.
5774 if (InstanceExpression != EmptyExpression.Null) {
5775 ec.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5776 TypeManager.GetFullNameSignature (PropertyInfo));
5781 if (getter != null &&
5782 !IsAccessorAccessible (ec.CurrentType, getter, out must_do_cs1540_check)) {
5783 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
5784 if (pm != null && pm.HasCustomAccessModifier) {
5785 ec.Report.SymbolRelatedToPreviousError (pm);
5786 ec.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5787 TypeManager.CSharpSignature (getter));
5789 ec.Report.SymbolRelatedToPreviousError (getter);
5790 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter), ec.Report);
5799 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5806 /// Fully resolved expression that evaluates to an Event
5808 public class EventExpr : MemberExpr {
5809 public readonly EventInfo EventInfo;
5812 MethodInfo add_accessor, remove_accessor;
5814 public EventExpr (EventInfo ei, Location loc)
5818 eclass = ExprClass.EventAccess;
5820 add_accessor = TypeManager.GetAddMethod (ei);
5821 remove_accessor = TypeManager.GetRemoveMethod (ei);
5822 if (add_accessor.IsStatic || remove_accessor.IsStatic)
5825 if (EventInfo is MyEventBuilder){
5826 MyEventBuilder eb = (MyEventBuilder) EventInfo;
5827 type = eb.EventType;
5830 type = EventInfo.EventHandlerType;
5833 public override string Name {
5835 return EventInfo.Name;
5839 public override bool IsInstance {
5845 public override bool IsStatic {
5851 public override Type DeclaringType {
5853 return EventInfo.DeclaringType;
5857 public void Error_AssignmentEventOnly (ResolveContext ec)
5859 ec.Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5860 GetSignatureForError ());
5863 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, Location loc,
5864 SimpleName original)
5867 // If the event is local to this class, we transform ourselves into a FieldExpr
5870 if (EventInfo.DeclaringType == ec.CurrentType ||
5871 TypeManager.IsNestedChildOf(ec.CurrentType, EventInfo.DeclaringType)) {
5872 EventField mi = TypeManager.GetEventField (EventInfo);
5876 mi.CheckObsoleteness (loc);
5878 if ((mi.ModFlags & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0 && !ec.HasSet (ResolveContext.Options.CompoundAssignmentScope))
5879 Error_AssignmentEventOnly (ec);
5881 FieldExpr ml = new FieldExpr (mi.BackingField.FieldBuilder, loc);
5883 InstanceExpression = null;
5885 return ml.ResolveMemberAccess (ec, left, loc, original);
5889 if (left is This && !ec.HasSet (ResolveContext.Options.CompoundAssignmentScope))
5890 Error_AssignmentEventOnly (ec);
5892 return base.ResolveMemberAccess (ec, left, loc, original);
5895 bool InstanceResolve (ResolveContext ec, bool must_do_cs1540_check)
5898 InstanceExpression = null;
5902 if (InstanceExpression == null) {
5903 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5907 InstanceExpression = InstanceExpression.DoResolve (ec);
5908 if (InstanceExpression == null)
5911 if (IsBase && add_accessor.IsAbstract) {
5912 Error_CannotCallAbstractBase (ec, TypeManager.CSharpSignature(add_accessor));
5917 // This is using the same mechanism as the CS1540 check in PropertyExpr.
5918 // However, in the Event case, we reported a CS0122 instead.
5920 // TODO: Exact copy from PropertyExpr
5922 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
5923 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.CurrentType) &&
5924 !TypeManager.IsNestedChildOf (ec.CurrentType, InstanceExpression.Type) &&
5925 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.CurrentType)) {
5926 ec.Report.SymbolRelatedToPreviousError (EventInfo);
5927 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo), ec.Report);
5934 public bool IsAccessibleFrom (Type invocation_type)
5937 return IsAccessorAccessible (invocation_type, add_accessor, out dummy) &&
5938 IsAccessorAccessible (invocation_type, remove_accessor, out dummy);
5941 public override Expression CreateExpressionTree (ResolveContext ec)
5943 throw new NotSupportedException ("ET");
5946 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5948 // contexts where an LValue is valid have already devolved to FieldExprs
5949 Error_CannotAssign (ec);
5953 public override Expression DoResolve (ResolveContext ec)
5955 bool must_do_cs1540_check;
5956 if (!(IsAccessorAccessible (ec.CurrentType, add_accessor, out must_do_cs1540_check) &&
5957 IsAccessorAccessible (ec.CurrentType, remove_accessor, out must_do_cs1540_check))) {
5958 ec.Report.SymbolRelatedToPreviousError (EventInfo);
5959 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo), ec.Report);
5963 if (!InstanceResolve (ec, must_do_cs1540_check))
5966 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
5967 Error_CannotAssign (ec);
5971 if (!ec.IsObsolete) {
5972 EventField ev = TypeManager.GetEventField (EventInfo);
5974 ev.CheckObsoleteness (loc);
5976 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (EventInfo);
5978 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
5985 public override void Emit (EmitContext ec)
5987 throw new NotSupportedException ();
5988 //Error_CannotAssign ();
5991 public void Error_CannotAssign (ResolveContext ec)
5993 ec.Report.Error (70, loc,
5994 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
5995 GetSignatureForError (), TypeManager.CSharpName (EventInfo.DeclaringType));
5998 public override string GetSignatureForError ()
6000 return TypeManager.CSharpSignature (EventInfo);
6003 public void EmitAddOrRemove (EmitContext ec, bool is_add, Expression source)
6005 Arguments args = new Arguments (1);
6006 args.Add (new Argument (source));
6007 Invocation.EmitCall (ec, IsBase, InstanceExpression, is_add ? add_accessor : remove_accessor, args, loc);
6011 public class TemporaryVariable : VariableReference
6015 public TemporaryVariable (Type type, Location loc)
6019 eclass = ExprClass.Variable;
6022 public override Expression CreateExpressionTree (ResolveContext ec)
6024 throw new NotSupportedException ("ET");
6027 public override Expression DoResolve (ResolveContext ec)
6032 TypeExpr te = new TypeExpression (type, loc);
6033 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
6034 if (!li.Resolve (ec))
6038 // Don't capture temporary variables except when using
6039 // iterator redirection
6041 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.IsIterator && ec.IsVariableCapturingRequired) {
6042 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
6043 storey.CaptureLocalVariable (ec, li);
6049 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6051 return DoResolve (ec);
6054 public override void Emit (EmitContext ec)
6059 public void EmitAssign (EmitContext ec, Expression source)
6061 EmitAssign (ec, source, false, false);
6064 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6066 return li.HoistedVariableReference;
6069 public override bool IsFixed {
6070 get { return true; }
6073 public override bool IsRef {
6074 get { return false; }
6077 public override string Name {
6078 get { throw new NotImplementedException (); }
6081 public override void SetHasAddressTaken ()
6083 throw new NotImplementedException ();
6086 protected override ILocalVariable Variable {
6090 public override VariableInfo VariableInfo {
6091 get { throw new NotImplementedException (); }
6096 /// Handles `var' contextual keyword; var becomes a keyword only
6097 /// if no type called var exists in a variable scope
6099 class VarExpr : SimpleName
6101 // Used for error reporting only
6102 ArrayList initializer;
6104 public VarExpr (Location loc)
6109 public ArrayList VariableInitializer {
6111 this.initializer = value;
6115 public bool InferType (ResolveContext ec, Expression right_side)
6118 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
6120 type = right_side.Type;
6121 if (type == TypeManager.null_type || type == TypeManager.void_type || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
6122 ec.Report.Error (815, loc, "An implicitly typed local variable declaration cannot be initialized with `{0}'",
6123 right_side.GetSignatureForError ());
6127 eclass = ExprClass.Variable;
6131 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
6133 if (RootContext.Version < LanguageVersion.V_3)
6134 base.Error_TypeOrNamespaceNotFound (ec);
6136 ec.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");
6139 public override TypeExpr ResolveAsContextualType (IMemberContext rc, bool silent)
6141 TypeExpr te = base.ResolveAsContextualType (rc, true);
6145 if (RootContext.Version < LanguageVersion.V_3)
6146 rc.Compiler.Report.FeatureIsNotAvailable (loc, "implicitly typed local variable");
6148 if (initializer == null)
6151 if (initializer.Count > 1) {
6152 Location loc_init = ((CSharpParser.VariableDeclaration) initializer[1]).Location;
6153 rc.Compiler.Report.Error (819, loc_init, "An implicitly typed local variable declaration cannot include multiple declarators");
6158 Expression variable_initializer = ((CSharpParser.VariableDeclaration) initializer[0]).expression_or_array_initializer;
6159 if (variable_initializer == null) {
6160 rc.Compiler.Report.Error (818, loc, "An implicitly typed local variable declarator must include an initializer");