2 // ecore.cs: Core of the Expression representation for the intermediate tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@seznam.cz)
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
14 using System.Collections.Generic;
15 using System.Diagnostics;
16 using System.Reflection;
17 using System.Reflection.Emit;
19 using SLE = System.Linq.Expressions;
22 namespace Mono.CSharp {
25 /// The ExprClass class contains the is used to pass the
26 /// classification of an expression (value, variable, namespace,
27 /// type, method group, property access, event access, indexer access,
30 public enum ExprClass : byte {
46 /// This is used to tell Resolve in which types of expressions we're
50 public enum ResolveFlags {
51 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
54 // Returns a type expression.
57 // Returns a method group.
60 TypeParameter = 1 << 3,
62 // Mask of all the expression class flags.
63 MaskExprClass = VariableOrValue | Type | MethodGroup | TypeParameter,
65 // Set if this is resolving the first part of a MemberAccess.
66 Intermediate = 1 << 11,
70 // This is just as a hint to AddressOf of what will be done with the
73 public enum AddressOp {
80 /// This interface is implemented by variables
82 public interface IMemoryLocation {
84 /// The AddressOf method should generate code that loads
85 /// the address of the object and leaves it on the stack.
87 /// The `mode' argument is used to notify the expression
88 /// of whether this will be used to read from the address or
89 /// write to the address.
91 /// This is just a hint that can be used to provide good error
92 /// reporting, and should have no other side effects.
94 void AddressOf (EmitContext ec, AddressOp mode);
98 // An expressions resolved as a direct variable reference
100 public interface IVariableReference : IFixedExpression
102 bool IsHoisted { get; }
104 VariableInfo VariableInfo { get; }
106 void SetHasAddressTaken ();
110 // Implemented by an expression which could be or is always
113 public interface IFixedExpression
115 bool IsFixed { get; }
119 /// Base class for expressions
121 public abstract class Expression {
122 public ExprClass eclass;
124 protected Location loc;
128 set { type = value; }
131 public virtual Location Location {
135 // Not nice but we have broken hierarchy.
136 public virtual void CheckMarshalByRefAccess (ResolveContext ec)
140 public virtual string GetSignatureForError ()
142 return TypeManager.CSharpName (type);
145 public static bool IsAccessorAccessible (Type invocation_type, MethodSpec mi, out bool must_do_cs1540_check)
147 var ma = mi.Modifiers & Modifiers.AccessibilityMask;
149 must_do_cs1540_check = false; // by default we do not check for this
151 if (ma == Modifiers.PUBLIC)
155 // If only accessible to the current class or children
157 if (ma == Modifiers.PRIVATE)
158 return TypeManager.IsPrivateAccessible (invocation_type, mi.DeclaringType) ||
159 TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType);
161 if ((ma & Modifiers.INTERNAL) != 0) {
162 var b = TypeManager.IsThisOrFriendAssembly (invocation_type.Assembly, mi.DeclaringType.Assembly);
163 if (b || ma == Modifiers.INTERNAL)
167 // Family and FamANDAssem require that we derive.
168 // FamORAssem requires that we derive if in different assemblies.
169 if (!TypeManager.IsNestedFamilyAccessible (invocation_type, mi.DeclaringType))
172 if (!TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType))
173 must_do_cs1540_check = true;
178 public virtual bool IsNull {
185 /// Performs semantic analysis on the Expression
189 /// The Resolve method is invoked to perform the semantic analysis
192 /// The return value is an expression (it can be the
193 /// same expression in some cases) or a new
194 /// expression that better represents this node.
196 /// For example, optimizations of Unary (LiteralInt)
197 /// would return a new LiteralInt with a negated
200 /// If there is an error during semantic analysis,
201 /// then an error should be reported (using Report)
202 /// and a null value should be returned.
204 /// There are two side effects expected from calling
205 /// Resolve(): the the field variable "eclass" should
206 /// be set to any value of the enumeration
207 /// `ExprClass' and the type variable should be set
208 /// to a valid type (this is the type of the
211 protected abstract Expression DoResolve (ResolveContext rc);
213 public virtual Expression DoResolveLValue (ResolveContext rc, Expression right_side)
219 // This is used if the expression should be resolved as a type or namespace name.
220 // the default implementation fails.
222 public virtual FullNamedExpression ResolveAsTypeStep (IMemberContext rc, bool silent)
225 ResolveContext ec = new ResolveContext (rc);
226 Expression e = Resolve (ec);
228 e.Error_UnexpectedKind (ec, ResolveFlags.Type, loc);
235 // C# 3.0 introduced contextual keywords (var) which behaves like a type if type with
236 // same name exists or as a keyword when no type was found
238 public virtual TypeExpr ResolveAsContextualType (IMemberContext rc, bool silent)
240 return ResolveAsTypeTerminal (rc, silent);
244 // This is used to resolve the expression as a type, a null
245 // value will be returned if the expression is not a type
248 public virtual TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
250 TypeExpr te = ResolveAsBaseTerminal (ec, silent);
254 if (!silent) { // && !(te is TypeParameterExpr)) {
255 ObsoleteAttribute obsolete_attr = AttributeTester.GetObsoleteAttribute (te.Type);
256 if (obsolete_attr != null && !ec.IsObsolete) {
257 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, ec.Compiler.Report);
261 GenericTypeExpr ct = te as GenericTypeExpr;
264 // TODO: Constrained type parameters check for parameters of generic method overrides is broken
265 // There are 2 solutions.
266 // 1, Skip this check completely when we are in override/explicit impl scope
267 // 2, Copy type parameters constraints from base implementation and pass (they have to be emitted anyway)
269 MemberCore gm = ec as GenericMethod;
272 if (gm != null && ((gm.ModFlags & Modifiers.OVERRIDE) != 0 || gm.MemberName.Left != null)) {
277 // TODO: silent flag is ignored
278 ct.CheckConstraints (ec);
284 public TypeExpr ResolveAsBaseTerminal (IMemberContext ec, bool silent)
286 int errors = ec.Compiler.Report.Errors;
288 FullNamedExpression fne = ResolveAsTypeStep (ec, silent);
293 TypeExpr te = fne as TypeExpr;
295 if (!silent && errors == ec.Compiler.Report.Errors)
296 fne.Error_UnexpectedKind (ec.Compiler.Report, null, "type", loc);
300 if (!te.CheckAccessLevel (ec)) {
301 ec.Compiler.Report.SymbolRelatedToPreviousError (te.Type);
302 ErrorIsInaccesible (loc, TypeManager.CSharpName (te.Type), ec.Compiler.Report);
310 public static void ErrorIsInaccesible (Location loc, string name, Report Report)
312 Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", name);
315 protected static void Error_CannotAccessProtected (ResolveContext ec, Location loc, MemberInfo m, Type qualifier, Type container)
317 ec.Report.Error (1540, loc, "Cannot access protected member `{0}' via a qualifier of type `{1}'."
318 + " The qualifier must be of type `{2}' or derived from it",
319 TypeManager.GetFullNameSignature (m),
320 TypeManager.CSharpName (qualifier),
321 TypeManager.CSharpName (container));
325 public void Error_ExpressionMustBeConstant (ResolveContext rc, Location loc, string e_name)
327 rc.Report.Error (133, loc, "The expression being assigned to `{0}' must be constant", e_name);
330 public void Error_ConstantCanBeInitializedWithNullOnly (ResolveContext rc, Type type, Location loc, string name)
332 rc.Report.Error (134, loc, "A constant `{0}' of reference type `{1}' can only be initialized with null",
333 name, TypeManager.CSharpName (type));
336 public static void Error_InvalidExpressionStatement (Report Report, Location loc)
338 Report.Error (201, loc, "Only assignment, call, increment, decrement, and new object " +
339 "expressions can be used as a statement");
342 public void Error_InvalidExpressionStatement (BlockContext ec)
344 Error_InvalidExpressionStatement (ec.Report, loc);
347 public static void Error_VoidInvalidInTheContext (Location loc, Report Report)
349 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
352 public virtual void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, Type target, bool expl)
354 Error_ValueCannotBeConvertedCore (ec, loc, target, expl);
357 protected void Error_ValueCannotBeConvertedCore (ResolveContext ec, Location loc, Type target, bool expl)
359 // The error was already reported as CS1660
360 if (type == InternalType.AnonymousMethod)
363 if (TypeManager.IsGenericParameter (Type) && TypeManager.IsGenericParameter (target) && type.Name == target.Name) {
364 string sig1 = type.DeclaringMethod == null ?
365 TypeManager.CSharpName (type.DeclaringType) :
366 TypeManager.CSharpSignature (type.DeclaringMethod);
367 string sig2 = target.DeclaringMethod == null ?
368 TypeManager.CSharpName (target.DeclaringType) :
369 TypeManager.CSharpSignature (target.DeclaringMethod);
370 ec.Report.ExtraInformation (loc,
372 "The generic parameter `{0}' of `{1}' cannot be converted to the generic parameter `{0}' of `{2}' (in the previous ",
373 Type.Name, sig1, sig2));
374 } else if (Type.FullName == target.FullName){
375 ec.Report.ExtraInformation (loc,
377 "The type `{0}' has two conflicting definitions, one comes from `{1}' and the other from `{2}' (in the previous ",
378 Type.FullName, Type.Assembly.FullName, target.Assembly.FullName));
382 ec.Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
383 TypeManager.CSharpName (type), TypeManager.CSharpName (target));
387 ec.Report.DisableReporting ();
388 bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null;
389 ec.Report.EnableReporting ();
392 ec.Report.Error (266, loc, "Cannot implicitly convert type `{0}' to `{1}'. " +
393 "An explicit conversion exists (are you missing a cast?)",
394 TypeManager.CSharpName (Type), TypeManager.CSharpName (target));
398 ec.Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
399 TypeManager.CSharpName (type),
400 TypeManager.CSharpName (target));
403 public virtual void Error_VariableIsUsedBeforeItIsDeclared (Report Report, string name)
405 Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", name);
408 public void Error_TypeArgumentsCannotBeUsed (Report report, Location loc)
410 // Better message for possible generic expressions
411 if (eclass == ExprClass.MethodGroup || eclass == ExprClass.Type) {
412 if (this is TypeExpr)
413 report.SymbolRelatedToPreviousError (type);
415 string name = eclass == ExprClass.Type ? ExprClassName : "method";
416 report.Error (308, loc, "The non-generic {0} `{1}' cannot be used with the type arguments",
417 name, GetSignatureForError ());
419 report.Error (307, loc, "The {0} `{1}' cannot be used with type arguments",
420 ExprClassName, GetSignatureForError ());
424 protected virtual void Error_TypeDoesNotContainDefinition (ResolveContext ec, Type type, string name)
426 Error_TypeDoesNotContainDefinition (ec, loc, type, name);
429 public static void Error_TypeDoesNotContainDefinition (ResolveContext ec, Location loc, Type type, string name)
431 ec.Report.SymbolRelatedToPreviousError (type);
432 ec.Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
433 TypeManager.CSharpName (type), name);
436 protected static void Error_ValueAssignment (ResolveContext ec, Location loc)
438 ec.Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
441 ResolveFlags ExprClassToResolveFlags {
445 case ExprClass.Namespace:
446 return ResolveFlags.Type;
448 case ExprClass.MethodGroup:
449 return ResolveFlags.MethodGroup;
451 case ExprClass.TypeParameter:
452 return ResolveFlags.TypeParameter;
454 case ExprClass.Value:
455 case ExprClass.Variable:
456 case ExprClass.PropertyAccess:
457 case ExprClass.EventAccess:
458 case ExprClass.IndexerAccess:
459 return ResolveFlags.VariableOrValue;
462 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
468 /// Resolves an expression and performs semantic analysis on it.
472 /// Currently Resolve wraps DoResolve to perform sanity
473 /// checking and assertion checking on what we expect from Resolve.
475 public Expression Resolve (ResolveContext ec, ResolveFlags flags)
477 if (eclass != ExprClass.Unresolved)
481 if (this is SimpleName) {
482 e = ((SimpleName) this).DoResolve (ec, (flags & ResolveFlags.Intermediate) != 0);
490 if ((flags & e.ExprClassToResolveFlags) == 0) {
491 e.Error_UnexpectedKind (ec, flags, loc);
496 throw new InternalErrorException ("Expression `{0}' didn't set its type in DoResolve", e.GetType ());
502 /// Resolves an expression and performs semantic analysis on it.
504 public Expression Resolve (ResolveContext rc)
506 return Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
510 /// Resolves an expression for LValue assignment
514 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
515 /// checking and assertion checking on what we expect from Resolve
517 public Expression ResolveLValue (ResolveContext ec, Expression right_side)
519 int errors = ec.Report.Errors;
520 bool out_access = right_side == EmptyExpression.OutAccess.Instance;
522 Expression e = DoResolveLValue (ec, right_side);
524 if (e != null && out_access && !(e is IMemoryLocation)) {
525 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
526 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
528 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
529 // e.GetType () + " " + e.GetSignatureForError ());
534 if (errors == ec.Report.Errors) {
536 ec.Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
538 Error_ValueAssignment (ec, loc);
543 if (e.eclass == ExprClass.Unresolved)
544 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
546 if ((e.type == null) && !(e is GenericTypeExpr))
547 throw new Exception ("Expression " + e + " did not set its type after Resolve");
552 public virtual void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, Type targetType)
554 Attribute.Error_AttributeArgumentNotValid (rc, loc);
558 /// Emits the code for the expression
562 /// The Emit method is invoked to generate the code
563 /// for the expression.
565 public abstract void Emit (EmitContext ec);
568 // Emit code to branch to @target if this expression is equivalent to @on_true.
569 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
570 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
571 // including the use of conditional branches. Note also that a branch MUST be emitted
572 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
575 ec.ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
578 // Emit this expression for its side effects, not for its value.
579 // The default implementation is to emit the value, and then throw it away.
580 // Subclasses can provide more efficient implementations, but those MUST be equivalent
581 public virtual void EmitSideEffect (EmitContext ec)
584 ec.ig.Emit (OpCodes.Pop);
588 /// Protected constructor. Only derivate types should
589 /// be able to be created
592 protected Expression ()
597 /// Returns a fully formed expression after a MemberLookup
600 public static Expression ExprClassFromMemberInfo (Type container_type, MemberInfo mi, Location loc)
603 return new EventExpr (Import.CreateEvent ((EventInfo) mi), loc);
604 else if (mi is FieldInfo) {
605 FieldInfo fi = (FieldInfo) mi;
606 var spec = Import.CreateField (fi);
607 if (spec is ConstSpec)
608 return new ConstantExpr ((ConstSpec) spec, loc);
609 return new FieldExpr (spec, loc);
610 } else if (mi is PropertyInfo)
611 return new PropertyExpr (container_type, Import.CreateProperty ((PropertyInfo) mi), loc);
612 else if (mi is Type) {
613 return new TypeExpression ((System.Type) mi, loc);
619 // TODO: [Obsolete ("Can be removed")]
620 protected static IList<MemberInfo> almost_matched_members = new List<MemberInfo> (4);
623 // FIXME: Probably implement a cache for (t,name,current_access_set)?
625 // This code could use some optimizations, but we need to do some
626 // measurements. For example, we could use a delegate to `flag' when
627 // something can not any longer be a method-group (because it is something
631 // If the return value is an Array, then it is an array of
634 // If the return value is an MemberInfo, it is anything, but a Method
638 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
639 // the arguments here and have MemberLookup return only the methods that
640 // match the argument count/type, unlike we are doing now (we delay this
643 // This is so we can catch correctly attempts to invoke instance methods
644 // from a static body (scan for error 120 in ResolveSimpleName).
647 // FIXME: Potential optimization, have a static ArrayList
650 public static Expression MemberLookup (CompilerContext ctx, Type container_type, Type queried_type, string name,
651 MemberTypes mt, BindingFlags bf, Location loc)
653 return MemberLookup (ctx, container_type, null, queried_type, name, mt, bf, loc);
657 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
658 // `qualifier_type' or null to lookup members in the current class.
661 public static Expression MemberLookup (CompilerContext ctx, Type container_type,
662 Type qualifier_type, Type queried_type,
663 string name, MemberTypes mt,
664 BindingFlags bf, Location loc)
666 almost_matched_members.Clear ();
668 MemberInfo [] mi = TypeManager.MemberLookup (container_type, qualifier_type,
669 queried_type, mt, bf, name, almost_matched_members);
675 bool is_interface = qualifier_type != null && qualifier_type.IsInterface;
676 var methods = new List<MethodSpec> (2);
677 List<MemberInfo> non_methods = null;
679 foreach (var m in mi) {
680 if (m is MethodBase) {
681 methods.Add (Import.CreateMethod ((MethodBase) m));
685 if (non_methods == null)
686 non_methods = new List<MemberInfo> (2);
688 bool is_candidate = true;
689 for (int i = 0; i < non_methods.Count; ++i) {
690 MemberInfo n_m = non_methods [i];
691 if (n_m.DeclaringType.IsInterface && TypeManager.ImplementsInterface (m.DeclaringType, n_m.DeclaringType)) {
692 non_methods.Remove (n_m);
694 } else if (m.DeclaringType.IsInterface && TypeManager.ImplementsInterface (n_m.DeclaringType, m.DeclaringType)) {
695 is_candidate = false;
705 if (methods.Count == 0 && non_methods != null && non_methods.Count > 1) {
706 ctx.Report.SymbolRelatedToPreviousError (non_methods [1]);
707 ctx.Report.SymbolRelatedToPreviousError (non_methods [0]);
708 ctx.Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
709 TypeManager.GetFullNameSignature (non_methods [1]),
710 TypeManager.GetFullNameSignature (non_methods [0]));
714 if (methods.Count == 0)
715 return ExprClassFromMemberInfo (container_type, (MemberInfo)non_methods [0], loc);
717 if (non_methods != null && non_methods.Count > 0) {
718 var method = methods [0];
719 MemberInfo non_method = (MemberInfo) non_methods [0];
720 if (method.DeclaringType == non_method.DeclaringType) {
721 // Cannot happen with C# code, but is valid in IL
722 ctx.Report.SymbolRelatedToPreviousError (method.MetaInfo);
723 ctx.Report.SymbolRelatedToPreviousError (non_method);
724 ctx.Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
725 TypeManager.GetFullNameSignature (non_method),
726 TypeManager.CSharpSignature (method.MetaInfo));
731 ctx.Report.SymbolRelatedToPreviousError (method.MetaInfo);
732 ctx.Report.SymbolRelatedToPreviousError (non_method);
733 ctx.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and non-method `{1}'. Using method `{0}'",
734 TypeManager.CSharpSignature (method.MetaInfo), TypeManager.GetFullNameSignature (non_method));
738 return new MethodGroupExpr (methods, queried_type, loc);
741 if (mi [0] is MethodBase)
742 return new MethodGroupExpr (mi.Select (l => Import.CreateMethod ((MethodBase) l)).ToArray (), queried_type, loc);
744 return ExprClassFromMemberInfo (container_type, mi [0], loc);
747 public const MemberTypes AllMemberTypes =
748 MemberTypes.Constructor |
752 MemberTypes.NestedType |
753 MemberTypes.Property;
755 public const BindingFlags AllBindingFlags =
756 BindingFlags.Public |
757 BindingFlags.Static |
758 BindingFlags.Instance;
760 public static Expression MemberLookup (CompilerContext ctx, Type container_type, Type queried_type,
761 string name, Location loc)
763 return MemberLookup (ctx, container_type, null, queried_type, name,
764 AllMemberTypes, AllBindingFlags, loc);
767 public static Expression MemberLookup (CompilerContext ctx, Type container_type, Type qualifier_type,
768 Type queried_type, string name, Location loc)
770 return MemberLookup (ctx, container_type, qualifier_type, queried_type,
771 name, AllMemberTypes, AllBindingFlags, loc);
774 public static MethodGroupExpr MethodLookup (CompilerContext ctx, Type container_type, Type queried_type,
775 string name, Location loc)
777 return (MethodGroupExpr)MemberLookup (ctx, container_type, null, queried_type, name,
778 MemberTypes.Method, AllBindingFlags, loc);
782 /// This is a wrapper for MemberLookup that is not used to "probe", but
783 /// to find a final definition. If the final definition is not found, we
784 /// look for private members and display a useful debugging message if we
787 protected Expression MemberLookupFinal (ResolveContext ec, Type qualifier_type,
788 Type queried_type, string name,
789 MemberTypes mt, BindingFlags bf,
794 int errors = ec.Report.Errors;
795 e = MemberLookup (ec.Compiler, ec.CurrentType, qualifier_type, queried_type, name, mt, bf, loc);
797 if (e != null || errors != ec.Report.Errors)
800 // No errors were reported by MemberLookup, but there was an error.
801 return Error_MemberLookupFailed (ec, ec.CurrentType, qualifier_type, queried_type,
805 protected virtual Expression Error_MemberLookupFailed (ResolveContext ec, Type container_type, Type qualifier_type,
806 Type queried_type, string name, string class_name,
807 MemberTypes mt, BindingFlags bf)
809 MemberInfo[] lookup = null;
810 if (queried_type == null) {
811 class_name = "global::";
813 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
814 mt, (bf & ~BindingFlags.Public) | BindingFlags.NonPublic,
817 if (lookup != null) {
818 Expression e = Error_MemberLookupFailed (ec, queried_type, lookup);
821 // FIXME: This is still very wrong, it should be done inside
822 // OverloadResolve to do correct arguments matching.
823 // Requires MemberLookup accessiblity check removal
825 if (e == null || (mt & (MemberTypes.Method | MemberTypes.Constructor)) == 0) {
826 MemberInfo mi = lookup[0];
827 ec.Report.SymbolRelatedToPreviousError (mi);
828 if (qualifier_type != null && container_type != null && qualifier_type != container_type &&
829 TypeManager.IsNestedFamilyAccessible (container_type, mi.DeclaringType)) {
830 // Although a derived class can access protected members of
831 // its base class it cannot do so through an instance of the
832 // base class (CS1540). If the qualifier_type is a base of the
833 // ec.CurrentType and the lookup succeeds with the latter one,
834 // then we are in this situation.
835 Error_CannotAccessProtected (ec, loc, mi, qualifier_type, container_type);
837 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (mi), ec.Report);
844 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
845 AllMemberTypes, AllBindingFlags | BindingFlags.NonPublic,
849 if (lookup == null) {
850 if (class_name != null) {
851 ec.Report.Error (103, loc, "The name `{0}' does not exist in the current context",
854 Error_TypeDoesNotContainDefinition (ec, queried_type, name);
859 if (TypeManager.MemberLookup (queried_type, null, queried_type,
860 AllMemberTypes, AllBindingFlags |
861 BindingFlags.NonPublic, name, null) == null) {
862 if ((lookup.Length == 1) && (lookup [0] is Type)) {
863 Type t = (Type) lookup [0];
865 ec.Report.Error (305, loc,
866 "Using the generic type `{0}' " +
867 "requires {1} type arguments",
868 TypeManager.CSharpName (t),
869 TypeManager.GetNumberOfTypeArguments (t).ToString ());
874 return Error_MemberLookupFailed (ec, queried_type, lookup);
877 protected virtual Expression Error_MemberLookupFailed (ResolveContext ec, Type type, MemberInfo[] members)
879 List<MethodSpec> methods = new List<MethodSpec> ();
880 for (int i = 0; i < members.Length; ++i) {
881 if (!(members [i] is MethodBase))
884 methods.Add (Import.CreateMethod (members[i] as MethodBase));
887 // By default propagate the closest candidates upwards
888 return new MethodGroupExpr (methods.ToArray (), type, loc, true);
891 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
893 throw new NotImplementedException ();
896 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
898 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
902 /// Returns an expression that can be used to invoke operator true
903 /// on the expression if it exists.
905 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
907 return GetOperatorTrueOrFalse (ec, e, true, loc);
911 /// Returns an expression that can be used to invoke operator false
912 /// on the expression if it exists.
914 static public Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
916 return GetOperatorTrueOrFalse (ec, e, false, loc);
919 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
921 MethodGroupExpr operator_group;
922 string mname = Operator.GetMetadataName (is_true ? Operator.OpType.True : Operator.OpType.False);
923 operator_group = MethodLookup (ec.Compiler, ec.CurrentType, e.Type, mname, loc) as MethodGroupExpr;
924 if (operator_group == null)
927 Arguments arguments = new Arguments (1);
928 arguments.Add (new Argument (e));
929 operator_group = operator_group.OverloadResolve (
930 ec, ref arguments, false, loc);
932 if (operator_group == null)
935 return new UserOperatorCall (operator_group, arguments, null, loc);
938 public virtual string ExprClassName
942 case ExprClass.Unresolved:
944 case ExprClass.Value:
946 case ExprClass.Variable:
948 case ExprClass.Namespace:
952 case ExprClass.MethodGroup:
953 return "method group";
954 case ExprClass.PropertyAccess:
955 return "property access";
956 case ExprClass.EventAccess:
957 return "event access";
958 case ExprClass.IndexerAccess:
959 return "indexer access";
960 case ExprClass.Nothing:
962 case ExprClass.TypeParameter:
963 return "type parameter";
965 throw new Exception ("Should not happen");
970 /// Reports that we were expecting `expr' to be of class `expected'
972 public void Error_UnexpectedKind (Report r, MemberCore mc, string expected, Location loc)
974 Error_UnexpectedKind (r, mc, expected, ExprClassName, loc);
977 public void Error_UnexpectedKind (Report r, MemberCore mc, string expected, string was, Location loc)
981 name = mc.GetSignatureForError ();
983 name = GetSignatureForError ();
985 r.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
986 name, was, expected);
989 public void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
991 string [] valid = new string [4];
994 if ((flags & ResolveFlags.VariableOrValue) != 0) {
995 valid [count++] = "variable";
996 valid [count++] = "value";
999 if ((flags & ResolveFlags.Type) != 0)
1000 valid [count++] = "type";
1002 if ((flags & ResolveFlags.MethodGroup) != 0)
1003 valid [count++] = "method group";
1006 valid [count++] = "unknown";
1008 StringBuilder sb = new StringBuilder (valid [0]);
1009 for (int i = 1; i < count - 1; i++) {
1011 sb.Append (valid [i]);
1014 sb.Append ("' or `");
1015 sb.Append (valid [count - 1]);
1018 ec.Report.Error (119, loc,
1019 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1022 public static void UnsafeError (ResolveContext ec, Location loc)
1024 UnsafeError (ec.Report, loc);
1027 public static void UnsafeError (Report Report, Location loc)
1029 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1033 // Load the object from the pointer.
1035 public static void LoadFromPtr (ILGenerator ig, Type t)
1037 if (t == TypeManager.int32_type)
1038 ig.Emit (OpCodes.Ldind_I4);
1039 else if (t == TypeManager.uint32_type)
1040 ig.Emit (OpCodes.Ldind_U4);
1041 else if (t == TypeManager.short_type)
1042 ig.Emit (OpCodes.Ldind_I2);
1043 else if (t == TypeManager.ushort_type)
1044 ig.Emit (OpCodes.Ldind_U2);
1045 else if (t == TypeManager.char_type)
1046 ig.Emit (OpCodes.Ldind_U2);
1047 else if (t == TypeManager.byte_type)
1048 ig.Emit (OpCodes.Ldind_U1);
1049 else if (t == TypeManager.sbyte_type)
1050 ig.Emit (OpCodes.Ldind_I1);
1051 else if (t == TypeManager.uint64_type)
1052 ig.Emit (OpCodes.Ldind_I8);
1053 else if (t == TypeManager.int64_type)
1054 ig.Emit (OpCodes.Ldind_I8);
1055 else if (t == TypeManager.float_type)
1056 ig.Emit (OpCodes.Ldind_R4);
1057 else if (t == TypeManager.double_type)
1058 ig.Emit (OpCodes.Ldind_R8);
1059 else if (t == TypeManager.bool_type)
1060 ig.Emit (OpCodes.Ldind_I1);
1061 else if (t == TypeManager.intptr_type)
1062 ig.Emit (OpCodes.Ldind_I);
1063 else if (TypeManager.IsEnumType (t)) {
1064 if (t == TypeManager.enum_type)
1065 ig.Emit (OpCodes.Ldind_Ref);
1067 LoadFromPtr (ig, TypeManager.GetEnumUnderlyingType (t));
1068 } else if (TypeManager.IsStruct (t) || TypeManager.IsGenericParameter (t))
1069 ig.Emit (OpCodes.Ldobj, t);
1070 else if (t.IsPointer)
1071 ig.Emit (OpCodes.Ldind_I);
1073 ig.Emit (OpCodes.Ldind_Ref);
1077 // The stack contains the pointer and the value of type `type'
1079 public static void StoreFromPtr (ILGenerator ig, Type type)
1081 if (TypeManager.IsEnumType (type))
1082 type = TypeManager.GetEnumUnderlyingType (type);
1083 if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
1084 ig.Emit (OpCodes.Stind_I4);
1085 else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
1086 ig.Emit (OpCodes.Stind_I8);
1087 else if (type == TypeManager.char_type || type == TypeManager.short_type ||
1088 type == TypeManager.ushort_type)
1089 ig.Emit (OpCodes.Stind_I2);
1090 else if (type == TypeManager.float_type)
1091 ig.Emit (OpCodes.Stind_R4);
1092 else if (type == TypeManager.double_type)
1093 ig.Emit (OpCodes.Stind_R8);
1094 else if (type == TypeManager.byte_type || type == TypeManager.sbyte_type ||
1095 type == TypeManager.bool_type)
1096 ig.Emit (OpCodes.Stind_I1);
1097 else if (type == TypeManager.intptr_type)
1098 ig.Emit (OpCodes.Stind_I);
1099 else if (TypeManager.IsStruct (type) || TypeManager.IsGenericParameter (type))
1100 ig.Emit (OpCodes.Stobj, type);
1102 ig.Emit (OpCodes.Stind_Ref);
1106 // Returns the size of type `t' if known, otherwise, 0
1108 public static int GetTypeSize (Type t)
1110 t = TypeManager.TypeToCoreType (t);
1111 if (t == TypeManager.int32_type ||
1112 t == TypeManager.uint32_type ||
1113 t == TypeManager.float_type)
1115 else if (t == TypeManager.int64_type ||
1116 t == TypeManager.uint64_type ||
1117 t == TypeManager.double_type)
1119 else if (t == TypeManager.byte_type ||
1120 t == TypeManager.sbyte_type ||
1121 t == TypeManager.bool_type)
1123 else if (t == TypeManager.short_type ||
1124 t == TypeManager.char_type ||
1125 t == TypeManager.ushort_type)
1127 else if (t == TypeManager.decimal_type)
1133 protected void Error_CannotCallAbstractBase (ResolveContext ec, string name)
1135 ec.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
1138 protected void Error_CannotModifyIntermediateExpressionValue (ResolveContext ec)
1140 ec.Report.SymbolRelatedToPreviousError (type);
1141 if (ec.CurrentInitializerVariable != null) {
1142 ec.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
1143 TypeManager.CSharpName (type), GetSignatureForError ());
1145 ec.Report.Error (1612, loc, "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
1146 GetSignatureForError ());
1151 // Converts `source' to an int, uint, long or ulong.
1153 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source)
1155 if (TypeManager.IsDynamicType (source.type)) {
1156 Arguments args = new Arguments (1);
1157 args.Add (new Argument (source));
1158 return new DynamicConversion (TypeManager.int32_type, CSharpBinderFlags.ConvertArrayIndex, args, loc).Resolve (ec);
1161 Expression converted;
1163 using (ec.Set (ResolveContext.Options.CheckedScope)) {
1164 converted = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, source.loc);
1165 if (converted == null)
1166 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, source.loc);
1167 if (converted == null)
1168 converted = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, source.loc);
1169 if (converted == null)
1170 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, source.loc);
1172 if (converted == null) {
1173 source.Error_ValueCannotBeConverted (ec, source.loc, TypeManager.int32_type, false);
1179 // Only positive constants are allowed at compile time
1181 Constant c = converted as Constant;
1182 if (c != null && c.IsNegative)
1183 Error_NegativeArrayIndex (ec, source.loc);
1185 // No conversion needed to array index
1186 if (converted.Type == TypeManager.int32_type)
1189 return new ArrayIndexCast (converted).Resolve (ec);
1193 // Derived classes implement this method by cloning the fields that
1194 // could become altered during the Resolve stage
1196 // Only expressions that are created for the parser need to implement
1199 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1201 throw new NotImplementedException (
1203 "CloneTo not implemented for expression {0}", this.GetType ()));
1207 // Clones an expression created by the parser.
1209 // We only support expressions created by the parser so far, not
1210 // expressions that have been resolved (many more classes would need
1211 // to implement CloneTo).
1213 // This infrastructure is here merely for Lambda expressions which
1214 // compile the same code using different type values for the same
1215 // arguments to find the correct overload
1217 public Expression Clone (CloneContext clonectx)
1219 Expression cloned = (Expression) MemberwiseClone ();
1220 CloneTo (clonectx, cloned);
1226 // Implementation of expression to expression tree conversion
1228 public abstract Expression CreateExpressionTree (ResolveContext ec);
1230 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
1232 return CreateExpressionFactoryCall (ec, name, null, args, loc);
1235 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
1237 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
1240 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
1242 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
1245 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
1247 TypeExpr texpr = TypeManager.expression_type_expr;
1248 if (texpr == null) {
1249 Type t = TypeManager.CoreLookupType (ec.Compiler, "System.Linq.Expressions", "Expression", MemberKind.Class, true);
1253 TypeManager.expression_type_expr = texpr = new TypeExpression (t, Location.Null);
1260 // Implemented by all expressions which support conversion from
1261 // compiler expression to invokable runtime expression. Used by
1262 // dynamic C# binder.
1264 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
1266 throw new NotImplementedException ("MakeExpression for " + GetType ());
1269 public virtual void MutateHoistedGenericType (AnonymousMethodStorey storey)
1271 // TODO: It should probably be type = storey.MutateType (type);
1276 /// This is just a base class for expressions that can
1277 /// appear on statements (invocations, object creation,
1278 /// assignments, post/pre increment and decrement). The idea
1279 /// being that they would support an extra Emition interface that
1280 /// does not leave a result on the stack.
1282 public abstract class ExpressionStatement : Expression {
1284 public virtual ExpressionStatement ResolveStatement (BlockContext ec)
1286 Expression e = Resolve (ec);
1290 ExpressionStatement es = e as ExpressionStatement;
1292 Error_InvalidExpressionStatement (ec);
1298 /// Requests the expression to be emitted in a `statement'
1299 /// context. This means that no new value is left on the
1300 /// stack after invoking this method (constrasted with
1301 /// Emit that will always leave a value on the stack).
1303 public abstract void EmitStatement (EmitContext ec);
1305 public override void EmitSideEffect (EmitContext ec)
1312 /// This kind of cast is used to encapsulate the child
1313 /// whose type is child.Type into an expression that is
1314 /// reported to return "return_type". This is used to encapsulate
1315 /// expressions which have compatible types, but need to be dealt
1316 /// at higher levels with.
1318 /// For example, a "byte" expression could be encapsulated in one
1319 /// of these as an "unsigned int". The type for the expression
1320 /// would be "unsigned int".
1323 public abstract class TypeCast : Expression
1325 protected readonly Expression child;
1327 protected TypeCast (Expression child, Type return_type)
1329 eclass = child.eclass;
1330 loc = child.Location;
1335 public Expression Child {
1341 public override Expression CreateExpressionTree (ResolveContext ec)
1343 Arguments args = new Arguments (2);
1344 args.Add (new Argument (child.CreateExpressionTree (ec)));
1345 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1347 if (type.IsPointer || child.Type.IsPointer)
1348 Error_PointerInsideExpressionTree (ec);
1350 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1353 protected override Expression DoResolve (ResolveContext ec)
1355 // This should never be invoked, we are born in fully
1356 // initialized state.
1361 public override void Emit (EmitContext ec)
1366 public override SLE.Expression MakeExpression (BuilderContext ctx)
1368 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1369 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type) :
1370 SLE.Expression.Convert (child.MakeExpression (ctx), type);
1373 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1375 type = storey.MutateType (type);
1376 child.MutateHoistedGenericType (storey);
1379 protected override void CloneTo (CloneContext clonectx, Expression t)
1384 public override bool IsNull {
1385 get { return child.IsNull; }
1389 public class EmptyCast : TypeCast {
1390 EmptyCast (Expression child, Type target_type)
1391 : base (child, target_type)
1395 public static Expression Create (Expression child, Type type)
1397 Constant c = child as Constant;
1399 return new EmptyConstantCast (c, type);
1401 EmptyCast e = child as EmptyCast;
1403 return new EmptyCast (e.child, type);
1405 return new EmptyCast (child, type);
1408 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1410 child.EmitBranchable (ec, label, on_true);
1413 public override void EmitSideEffect (EmitContext ec)
1415 child.EmitSideEffect (ec);
1420 // Used for predefined class library user casts (no obsolete check, etc.)
1422 public class OperatorCast : TypeCast {
1423 MethodInfo conversion_operator;
1425 public OperatorCast (Expression child, Type target_type)
1426 : this (child, target_type, false)
1430 public OperatorCast (Expression child, Type target_type, bool find_explicit)
1431 : base (child, target_type)
1433 conversion_operator = GetConversionOperator (find_explicit);
1434 if (conversion_operator == null)
1435 throw new InternalErrorException ("Outer conversion routine is out of sync");
1438 // Returns the implicit operator that converts from
1439 // 'child.Type' to our target type (type)
1440 MethodInfo GetConversionOperator (bool find_explicit)
1442 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1446 mi = TypeManager.MemberLookup (child.Type, child.Type, child.Type, MemberTypes.Method,
1447 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1450 mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1451 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1454 foreach (MethodInfo oper in mi) {
1455 AParametersCollection pd = TypeManager.GetParameterData (oper);
1457 if (pd.Types [0] == child.Type && TypeManager.TypeToCoreType (oper.ReturnType) == type)
1464 public override void Emit (EmitContext ec)
1467 ec.ig.Emit (OpCodes.Call, conversion_operator);
1472 /// This is a numeric cast to a Decimal
1474 public class CastToDecimal : OperatorCast {
1475 public CastToDecimal (Expression child)
1476 : this (child, false)
1480 public CastToDecimal (Expression child, bool find_explicit)
1481 : base (child, TypeManager.decimal_type, find_explicit)
1487 /// This is an explicit numeric cast from a Decimal
1489 public class CastFromDecimal : TypeCast
1491 static Dictionary<Type, MethodInfo> operators;
1493 public CastFromDecimal (Expression child, Type return_type)
1494 : base (child, return_type)
1496 if (child.Type != TypeManager.decimal_type)
1497 throw new InternalErrorException (
1498 "The expected type is Decimal, instead it is " + child.Type.FullName);
1501 // Returns the explicit operator that converts from an
1502 // express of type System.Decimal to 'type'.
1503 public Expression Resolve ()
1505 if (operators == null) {
1506 MemberInfo[] all_oper = TypeManager.MemberLookup (TypeManager.decimal_type,
1507 TypeManager.decimal_type, TypeManager.decimal_type, MemberTypes.Method,
1508 BindingFlags.Static | BindingFlags.Public, "op_Explicit", null);
1510 operators = new Dictionary<Type, MethodInfo> (ReferenceEquality<Type>.Default);
1511 foreach (MethodInfo oper in all_oper) {
1512 AParametersCollection pd = TypeManager.GetParameterData (oper);
1513 if (pd.Types [0] == TypeManager.decimal_type)
1514 operators.Add (TypeManager.TypeToCoreType (oper.ReturnType), oper);
1518 return operators.ContainsKey (type) ? this : null;
1521 public override void Emit (EmitContext ec)
1523 ILGenerator ig = ec.ig;
1526 ig.Emit (OpCodes.Call, operators [type]);
1532 // Constant specialization of EmptyCast.
1533 // We need to special case this since an empty cast of
1534 // a constant is still a constant.
1536 public class EmptyConstantCast : Constant
1538 public Constant child;
1540 public EmptyConstantCast (Constant child, Type type)
1541 : base (child.Location)
1544 throw new ArgumentNullException ("child");
1547 this.eclass = child.eclass;
1551 public override string AsString ()
1553 return child.AsString ();
1556 public override object GetValue ()
1558 return child.GetValue ();
1561 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
1563 if (child.Type == target_type)
1566 // FIXME: check that 'type' can be converted to 'target_type' first
1567 return child.ConvertExplicitly (in_checked_context, target_type);
1570 public override Expression CreateExpressionTree (ResolveContext ec)
1572 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1573 child.CreateExpressionTree (ec),
1574 new TypeOf (new TypeExpression (type, loc), loc));
1577 Error_PointerInsideExpressionTree (ec);
1579 return CreateExpressionFactoryCall (ec, "Convert", args);
1582 public override bool IsDefaultValue {
1583 get { return child.IsDefaultValue; }
1586 public override bool IsNegative {
1587 get { return child.IsNegative; }
1590 public override bool IsNull {
1591 get { return child.IsNull; }
1594 public override bool IsOneInteger {
1595 get { return child.IsOneInteger; }
1598 public override bool IsZeroInteger {
1599 get { return child.IsZeroInteger; }
1602 protected override Expression DoResolve (ResolveContext rc)
1607 public override void Emit (EmitContext ec)
1612 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1614 child.EmitBranchable (ec, label, on_true);
1616 // Only to make verifier happy
1617 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1618 ec.ig.Emit (OpCodes.Unbox_Any, type);
1621 public override void EmitSideEffect (EmitContext ec)
1623 child.EmitSideEffect (ec);
1626 public override Constant ConvertImplicitly (ResolveContext rc, Type target_type)
1628 // FIXME: Do we need to check user conversions?
1629 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1631 return child.ConvertImplicitly (rc, target_type);
1634 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1636 child.MutateHoistedGenericType (storey);
1641 /// This class is used to wrap literals which belong inside Enums
1643 public class EnumConstant : Constant
1645 public Constant Child;
1647 public EnumConstant (Constant child, Type enum_type)
1648 : base (child.Location)
1651 this.type = enum_type;
1654 protected EnumConstant (Location loc)
1659 protected override Expression DoResolve (ResolveContext rc)
1661 Child = Child.Resolve (rc);
1662 this.eclass = ExprClass.Value;
1666 public override void Emit (EmitContext ec)
1671 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, Type targetType)
1673 Child.EncodeAttributeValue (rc, enc, Child.Type);
1676 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1678 Child.EmitBranchable (ec, label, on_true);
1681 public override void EmitSideEffect (EmitContext ec)
1683 Child.EmitSideEffect (ec);
1686 public override string GetSignatureForError()
1688 return TypeManager.CSharpName (Type);
1691 public override object GetValue ()
1693 return Child.GetValue ();
1696 public override object GetTypedValue ()
1698 // FIXME: runtime is not ready to work with just emited enums
1699 if (!RootContext.StdLib) {
1700 return Child.GetValue ();
1704 // Small workaround for big problem
1705 // System.Enum.ToObject cannot be called on dynamic types
1706 // EnumBuilder has to be used, but we cannot use EnumBuilder
1707 // because it does not properly support generics
1709 // This works only sometimes
1711 if (TypeManager.IsBeingCompiled (type))
1712 return Child.GetValue ();
1715 return System.Enum.ToObject (type, Child.GetValue ());
1718 public override string AsString ()
1720 return Child.AsString ();
1723 public EnumConstant Increment()
1725 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1728 public override bool IsDefaultValue {
1730 return Child.IsDefaultValue;
1734 public override bool IsZeroInteger {
1735 get { return Child.IsZeroInteger; }
1738 public override bool IsNegative {
1740 return Child.IsNegative;
1744 public override Constant ConvertExplicitly(bool in_checked_context, Type target_type)
1746 if (Child.Type == target_type)
1749 return Child.ConvertExplicitly (in_checked_context, target_type);
1752 public override Constant ConvertImplicitly (ResolveContext rc, Type type)
1754 Type this_type = TypeManager.DropGenericTypeArguments (Type);
1755 type = TypeManager.DropGenericTypeArguments (type);
1757 if (this_type == type) {
1758 // This is workaround of mono bug. It can be removed when the latest corlib spreads enough
1759 if (TypeManager.IsEnumType (type.UnderlyingSystemType))
1762 Type child_type = TypeManager.DropGenericTypeArguments (Child.Type);
1763 if (type.UnderlyingSystemType != child_type)
1764 Child = Child.ConvertImplicitly (rc, type.UnderlyingSystemType);
1768 if (!Convert.ImplicitStandardConversionExists (this, type)){
1772 return Child.ConvertImplicitly (rc, type);
1777 /// This kind of cast is used to encapsulate Value Types in objects.
1779 /// The effect of it is to box the value type emitted by the previous
1782 public class BoxedCast : TypeCast {
1784 public BoxedCast (Expression expr, Type target_type)
1785 : base (expr, target_type)
1787 eclass = ExprClass.Value;
1790 protected override Expression DoResolve (ResolveContext ec)
1792 // This should never be invoked, we are born in fully
1793 // initialized state.
1798 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, Type targetType)
1800 enc.Encode (child.Type);
1801 child.EncodeAttributeValue (rc, enc, child.Type);
1804 public override void Emit (EmitContext ec)
1808 ec.ig.Emit (OpCodes.Box, child.Type);
1811 public override void EmitSideEffect (EmitContext ec)
1813 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1814 // so, we need to emit the box+pop instructions in most cases
1815 if (TypeManager.IsStruct (child.Type) &&
1816 (type == TypeManager.object_type || type == TypeManager.value_type))
1817 child.EmitSideEffect (ec);
1819 base.EmitSideEffect (ec);
1823 public class UnboxCast : TypeCast {
1824 public UnboxCast (Expression expr, Type return_type)
1825 : base (expr, return_type)
1829 protected override Expression DoResolve (ResolveContext ec)
1831 // This should never be invoked, we are born in fully
1832 // initialized state.
1837 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
1839 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
1840 ec.Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
1841 return base.DoResolveLValue (ec, right_side);
1844 public override void Emit (EmitContext ec)
1848 ILGenerator ig = ec.ig;
1849 ig.Emit (OpCodes.Unbox_Any, type);
1852 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1854 type = storey.MutateType (type);
1855 base.MutateHoistedGenericType (storey);
1860 /// This is used to perform explicit numeric conversions.
1862 /// Explicit numeric conversions might trigger exceptions in a checked
1863 /// context, so they should generate the conv.ovf opcodes instead of
1866 public class ConvCast : TypeCast {
1867 public enum Mode : byte {
1868 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1870 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1871 U2_I1, U2_U1, U2_I2, U2_CH,
1872 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1873 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1874 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1875 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1876 CH_I1, CH_U1, CH_I2,
1877 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1878 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1884 public ConvCast (Expression child, Type return_type, Mode m)
1885 : base (child, return_type)
1890 protected override Expression DoResolve (ResolveContext ec)
1892 // This should never be invoked, we are born in fully
1893 // initialized state.
1898 public override string ToString ()
1900 return String.Format ("ConvCast ({0}, {1})", mode, child);
1903 public override void Emit (EmitContext ec)
1905 ILGenerator ig = ec.ig;
1909 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1911 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1912 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1913 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1914 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1915 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1917 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1918 case Mode.U1_CH: /* nothing */ break;
1920 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1921 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1922 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1923 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1924 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1925 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1927 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1928 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1929 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1930 case Mode.U2_CH: /* nothing */ break;
1932 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1933 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1934 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1935 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1936 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1937 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1938 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1940 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1941 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1942 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1943 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1944 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1945 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1947 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1948 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1949 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1950 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1951 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1952 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1953 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1954 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1955 case Mode.I8_I: ig.Emit (OpCodes.Conv_Ovf_U); break;
1957 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1958 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1959 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1960 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1961 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1962 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1963 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1964 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1965 case Mode.U8_I: ig.Emit (OpCodes.Conv_Ovf_U_Un); break;
1967 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1968 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1969 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1971 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1972 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1973 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1974 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1975 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1976 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1977 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1978 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1979 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1981 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1982 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1983 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1984 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1985 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1986 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1987 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1988 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1989 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1990 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1992 case Mode.I_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1996 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
1997 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
1998 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
1999 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
2000 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
2002 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
2003 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
2005 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
2006 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
2007 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
2008 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
2009 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
2010 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
2012 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
2013 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
2014 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
2015 case Mode.U2_CH: /* nothing */ break;
2017 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
2018 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
2019 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
2020 case Mode.I4_U4: /* nothing */ break;
2021 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
2022 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
2023 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
2025 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
2026 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
2027 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
2028 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
2029 case Mode.U4_I4: /* nothing */ break;
2030 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
2032 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
2033 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
2034 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
2035 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
2036 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
2037 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
2038 case Mode.I8_U8: /* nothing */ break;
2039 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
2040 case Mode.I8_I: ig.Emit (OpCodes.Conv_U); break;
2042 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
2043 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
2044 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
2045 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
2046 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
2047 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
2048 case Mode.U8_I8: /* nothing */ break;
2049 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
2050 case Mode.U8_I: ig.Emit (OpCodes.Conv_U); break;
2052 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
2053 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
2054 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
2056 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
2057 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
2058 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
2059 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
2060 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
2061 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
2062 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
2063 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
2064 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
2066 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
2067 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
2068 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
2069 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
2070 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
2071 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
2072 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
2073 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
2074 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
2075 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
2077 case Mode.I_I8: ig.Emit (OpCodes.Conv_U8); break;
2083 public class OpcodeCast : TypeCast {
2086 public OpcodeCast (Expression child, Type return_type, OpCode op)
2087 : base (child, return_type)
2092 protected override Expression DoResolve (ResolveContext ec)
2094 // This should never be invoked, we are born in fully
2095 // initialized state.
2100 public override void Emit (EmitContext ec)
2106 public Type UnderlyingType {
2107 get { return child.Type; }
2112 /// This kind of cast is used to encapsulate a child and cast it
2113 /// to the class requested
2115 public sealed class ClassCast : TypeCast {
2116 readonly bool forced;
2118 public ClassCast (Expression child, Type return_type)
2119 : base (child, return_type)
2123 public ClassCast (Expression child, Type return_type, bool forced)
2124 : base (child, return_type)
2126 this.forced = forced;
2129 public override void Emit (EmitContext ec)
2133 bool gen = TypeManager.IsGenericParameter (child.Type);
2135 ec.ig.Emit (OpCodes.Box, child.Type);
2137 if (type.IsGenericParameter) {
2138 ec.ig.Emit (OpCodes.Unbox_Any, type);
2145 ec.ig.Emit (OpCodes.Castclass, type);
2150 // Created during resolving pahse when an expression is wrapped or constantified
2151 // and original expression can be used later (e.g. for expression trees)
2153 public class ReducedExpression : Expression
2155 sealed class ReducedConstantExpression : EmptyConstantCast
2157 readonly Expression orig_expr;
2159 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2160 : base (expr, expr.Type)
2162 this.orig_expr = orig_expr;
2165 public override Constant ConvertImplicitly (ResolveContext rc, Type target_type)
2167 Constant c = base.ConvertImplicitly (rc, target_type);
2169 c = new ReducedConstantExpression (c, orig_expr);
2174 public override Expression CreateExpressionTree (ResolveContext ec)
2176 return orig_expr.CreateExpressionTree (ec);
2179 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
2181 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
2183 c = new ReducedConstantExpression (c, orig_expr);
2188 sealed class ReducedExpressionStatement : ExpressionStatement
2190 readonly Expression orig_expr;
2191 readonly ExpressionStatement stm;
2193 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
2195 this.orig_expr = orig;
2197 this.loc = orig.Location;
2200 public override Expression CreateExpressionTree (ResolveContext ec)
2202 return orig_expr.CreateExpressionTree (ec);
2205 protected override Expression DoResolve (ResolveContext ec)
2207 eclass = stm.eclass;
2212 public override void Emit (EmitContext ec)
2217 public override void EmitStatement (EmitContext ec)
2219 stm.EmitStatement (ec);
2222 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2224 stm.MutateHoistedGenericType (storey);
2228 readonly Expression expr, orig_expr;
2230 private ReducedExpression (Expression expr, Expression orig_expr)
2233 this.eclass = expr.eclass;
2234 this.type = expr.Type;
2235 this.orig_expr = orig_expr;
2236 this.loc = orig_expr.Location;
2240 // Creates fully resolved expression switcher
2242 public static Constant Create (Constant expr, Expression original_expr)
2244 if (expr.eclass == ExprClass.Unresolved)
2245 throw new ArgumentException ("Unresolved expression");
2247 return new ReducedConstantExpression (expr, original_expr);
2250 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
2252 return new ReducedExpressionStatement (s, orig);
2256 // Creates unresolved reduce expression. The original expression has to be
2259 public static Expression Create (Expression expr, Expression original_expr)
2261 Constant c = expr as Constant;
2263 return Create (c, original_expr);
2265 ExpressionStatement s = expr as ExpressionStatement;
2267 return Create (s, original_expr);
2269 if (expr.eclass == ExprClass.Unresolved)
2270 throw new ArgumentException ("Unresolved expression");
2272 return new ReducedExpression (expr, original_expr);
2275 public override Expression CreateExpressionTree (ResolveContext ec)
2277 return orig_expr.CreateExpressionTree (ec);
2280 protected override Expression DoResolve (ResolveContext ec)
2285 public override void Emit (EmitContext ec)
2290 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2292 expr.EmitBranchable (ec, target, on_true);
2295 public override SLE.Expression MakeExpression (BuilderContext ctx)
2297 return orig_expr.MakeExpression (ctx);
2300 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2302 expr.MutateHoistedGenericType (storey);
2307 // Standard composite pattern
2309 public abstract class CompositeExpression : Expression
2313 protected CompositeExpression (Expression expr)
2316 this.loc = expr.Location;
2319 public override Expression CreateExpressionTree (ResolveContext ec)
2321 return expr.CreateExpressionTree (ec);
2324 public Expression Child {
2325 get { return expr; }
2328 protected override Expression DoResolve (ResolveContext ec)
2330 expr = expr.Resolve (ec);
2333 eclass = expr.eclass;
2339 public override void Emit (EmitContext ec)
2344 public override bool IsNull {
2345 get { return expr.IsNull; }
2350 // Base of expressions used only to narrow resolve flow
2352 public abstract class ShimExpression : Expression
2354 protected Expression expr;
2356 protected ShimExpression (Expression expr)
2361 protected override void CloneTo (CloneContext clonectx, Expression t)
2366 ShimExpression target = (ShimExpression) t;
2367 target.expr = expr.Clone (clonectx);
2370 public override Expression CreateExpressionTree (ResolveContext ec)
2372 throw new NotSupportedException ("ET");
2375 public override void Emit (EmitContext ec)
2377 throw new InternalErrorException ("Missing Resolve call");
2380 public Expression Expr {
2381 get { return expr; }
2384 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2386 throw new InternalErrorException ("Missing Resolve call");
2391 // Unresolved type name expressions
2393 public abstract class ATypeNameExpression : FullNamedExpression
2396 protected TypeArguments targs;
2398 protected ATypeNameExpression (string name, Location l)
2404 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2411 public bool HasTypeArguments {
2413 return targs != null;
2417 public override bool Equals (object obj)
2419 ATypeNameExpression atne = obj as ATypeNameExpression;
2420 return atne != null && atne.Name == Name &&
2421 (targs == null || targs.Equals (atne.targs));
2424 public override int GetHashCode ()
2426 return Name.GetHashCode ();
2429 public override string GetSignatureForError ()
2431 if (targs != null) {
2432 return TypeManager.RemoveGenericArity (Name) + "<" +
2433 targs.GetSignatureForError () + ">";
2439 public string Name {
2448 public TypeArguments TypeArguments {
2456 /// SimpleName expressions are formed of a single word and only happen at the beginning
2457 /// of a dotted-name.
2459 public class SimpleName : ATypeNameExpression
2461 public SimpleName (string name, Location l)
2466 public SimpleName (string name, TypeArguments args, Location l)
2467 : base (name, args, l)
2471 public SimpleName (string name, TypeParameter[] type_params, Location l)
2474 targs = new TypeArguments ();
2475 foreach (TypeParameter type_param in type_params)
2476 targs.Add (new TypeParameterExpr (type_param, l));
2479 public static string RemoveGenericArity (string name)
2482 StringBuilder sb = null;
2484 int pos = name.IndexOf ('`', start);
2489 sb.Append (name.Substring (start));
2494 sb = new StringBuilder ();
2495 sb.Append (name.Substring (start, pos-start));
2498 while ((pos < name.Length) && Char.IsNumber (name [pos]))
2502 } while (start < name.Length);
2504 return sb.ToString ();
2507 public SimpleName GetMethodGroup ()
2509 return new SimpleName (RemoveGenericArity (Name), targs, loc);
2512 public static void Error_ObjectRefRequired (ResolveContext ec, Location l, string name)
2514 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope))
2515 ec.Report.Error (236, l,
2516 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2519 ec.Report.Error (120, l,
2520 "An object reference is required to access non-static member `{0}'",
2524 public bool IdenticalNameAndTypeName (IMemberContext mc, Expression resolved_to, Location loc)
2526 return resolved_to != null && resolved_to.Type != null &&
2527 resolved_to.Type.Name == Name &&
2528 (mc.LookupNamespaceOrType (Name, loc, /* ignore_cs0104 = */ true) != null);
2531 protected override Expression DoResolve (ResolveContext ec)
2533 return SimpleNameResolve (ec, null, false);
2536 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2538 return SimpleNameResolve (ec, right_side, false);
2541 public Expression DoResolve (ResolveContext ec, bool intermediate)
2543 return SimpleNameResolve (ec, null, intermediate);
2546 static bool IsNestedChild (Type t, Type parent)
2548 while (parent != null) {
2549 if (TypeManager.IsNestedChildOf (t, TypeManager.DropGenericTypeArguments (parent)))
2552 parent = parent.BaseType;
2558 FullNamedExpression ResolveNested (Type t)
2560 if (!TypeManager.IsGenericTypeDefinition (t) && !TypeManager.IsGenericType (t))
2564 while (ds != null && !IsNestedChild (t, ds))
2565 ds = ds.DeclaringType;
2570 Type[] gen_params = TypeManager.GetTypeArguments (t);
2572 int arg_count = targs != null ? targs.Count : 0;
2574 for (; (ds != null) && TypeManager.IsGenericType (ds); ds = ds.DeclaringType) {
2575 Type[] gargs = TypeManager.GetTypeArguments (ds);
2576 if (arg_count + gargs.Length == gen_params.Length) {
2577 TypeArguments new_args = new TypeArguments ();
2578 foreach (Type param in gargs)
2579 new_args.Add (new TypeExpression (param, loc));
2582 new_args.Add (targs);
2584 return new GenericTypeExpr (t, new_args, loc);
2591 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2593 int errors = ec.Compiler.Report.Errors;
2594 FullNamedExpression fne = ec.LookupNamespaceOrType (Name, loc, /*ignore_cs0104=*/ false);
2597 if (fne.Type == null)
2600 FullNamedExpression nested = ResolveNested (fne.Type);
2602 return nested.ResolveAsTypeStep (ec, false);
2604 if (targs != null) {
2605 if (TypeManager.IsGenericType (fne.Type)) {
2606 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2607 return ct.ResolveAsTypeStep (ec, false);
2610 fne.Error_TypeArgumentsCannotBeUsed (ec.Compiler.Report, loc);
2616 if (!HasTypeArguments && Name == "dynamic" &&
2617 RootContext.Version > LanguageVersion.V_3 &&
2618 RootContext.MetadataCompatibilityVersion > MetadataVersion.v2) {
2620 if (!PredefinedAttributes.Get.Dynamic.IsDefined) {
2621 ec.Compiler.Report.Error (1980, Location,
2622 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2623 PredefinedAttributes.Get.Dynamic.GetSignatureForError ());
2626 return new DynamicTypeExpr (loc);
2629 if (silent || errors != ec.Compiler.Report.Errors)
2632 Error_TypeOrNamespaceNotFound (ec);
2636 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ec)
2638 if (ec.CurrentType != null) {
2639 if (ec.CurrentTypeDefinition != null) {
2640 MemberCore mc = ec.CurrentTypeDefinition.GetDefinition (Name);
2642 Error_UnexpectedKind (ec.Compiler.Report, mc, "type", GetMemberType (mc), loc);
2647 string ns = ec.CurrentType.Namespace;
2648 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2649 foreach (Assembly a in GlobalRootNamespace.Instance.Assemblies) {
2650 Type type = a.GetType (fullname);
2652 ec.Compiler.Report.SymbolRelatedToPreviousError (type);
2653 Expression.ErrorIsInaccesible (loc, TypeManager.CSharpName (type), ec.Compiler.Report);
2658 if (ec.CurrentTypeDefinition != null) {
2659 Type t = ec.CurrentTypeDefinition.LookupAnyGeneric (Name);
2661 Namespace.Error_InvalidNumberOfTypeArguments (ec.Compiler.Report, t, loc);
2667 if (targs != null) {
2668 FullNamedExpression retval = ec.LookupNamespaceOrType (SimpleName.RemoveGenericArity (Name), loc, true);
2669 if (retval != null) {
2670 retval.Error_TypeArgumentsCannotBeUsed (ec.Compiler.Report, loc);
2675 NamespaceEntry.Error_NamespaceNotFound (loc, Name, ec.Compiler.Report);
2678 // TODO: I am still not convinced about this. If someone else will need it
2679 // implement this as virtual property in MemberCore hierarchy
2680 public static string GetMemberType (MemberCore mc)
2686 if (mc is FieldBase)
2688 if (mc is MethodCore)
2690 if (mc is EnumMember)
2698 Expression SimpleNameResolve (ResolveContext ec, Expression right_side, bool intermediate)
2700 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2705 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2712 /// 7.5.2: Simple Names.
2714 /// Local Variables and Parameters are handled at
2715 /// parse time, so they never occur as SimpleNames.
2717 /// The `intermediate' flag is used by MemberAccess only
2718 /// and it is used to inform us that it is ok for us to
2719 /// avoid the static check, because MemberAccess might end
2720 /// up resolving the Name as a Type name and the access as
2721 /// a static type access.
2723 /// ie: Type Type; .... { Type.GetType (""); }
2725 /// Type is both an instance variable and a Type; Type.GetType
2726 /// is the static method not an instance method of type.
2728 Expression DoSimpleNameResolve (ResolveContext ec, Expression right_side, bool intermediate)
2730 Expression e = null;
2733 // Stage 1: Performed by the parser (binding to locals or parameters).
2735 Block current_block = ec.CurrentBlock;
2736 if (current_block != null){
2737 LocalInfo vi = current_block.GetLocalInfo (Name);
2739 e = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2741 if (right_side != null) {
2742 e = e.ResolveLValue (ec, right_side);
2745 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
2746 e = e.Resolve (ec, ResolveFlags.VariableOrValue);
2749 e = e.Resolve (ec, ResolveFlags.VariableOrValue);
2753 if (targs != null && e != null)
2754 e.Error_TypeArgumentsCannotBeUsed (ec.Report, loc);
2759 e = current_block.Toplevel.GetParameterReference (Name, loc);
2761 if (right_side != null)
2762 e = e.ResolveLValue (ec, right_side);
2766 if (targs != null && e != null)
2767 e.Error_TypeArgumentsCannotBeUsed (ec.Report, loc);
2774 // Stage 2: Lookup members
2777 Type almost_matched_type = null;
2778 IList<MemberInfo> almost_matched = null;
2779 for (Type lookup_ds = ec.CurrentType; lookup_ds != null; lookup_ds = lookup_ds.DeclaringType) {
2780 e = MemberLookup (ec.Compiler, ec.CurrentType, lookup_ds, Name, loc);
2782 PropertyExpr pe = e as PropertyExpr;
2784 AParametersCollection param = TypeManager.GetParameterData (pe.PropertyInfo);
2786 // since TypeManager.MemberLookup doesn't know if we're doing a lvalue access or not,
2787 // it doesn't know which accessor to check permissions against
2788 if (param.IsEmpty && pe.IsAccessibleFrom (ec.CurrentType, right_side != null))
2790 } else if (e is EventExpr) {
2791 if (((EventExpr) e).IsAccessibleFrom (ec.CurrentType))
2793 } else if (targs != null && e is TypeExpression) {
2794 e = new GenericTypeExpr (e.Type, targs, loc).ResolveAsTypeStep (ec, false);
2802 if (almost_matched == null && almost_matched_members.Count > 0) {
2803 almost_matched_type = lookup_ds;
2804 almost_matched = new List<MemberInfo>(almost_matched_members);
2809 if (almost_matched == null && almost_matched_members.Count > 0) {
2810 almost_matched_type = ec.CurrentType;
2811 almost_matched = new List<MemberInfo> (almost_matched_members);
2813 e = ResolveAsTypeStep (ec, true);
2817 if (current_block != null) {
2818 IKnownVariable ikv = current_block.Explicit.GetKnownVariable (Name);
2820 LocalInfo li = ikv as LocalInfo;
2821 // Supress CS0219 warning
2825 Error_VariableIsUsedBeforeItIsDeclared (ec.Report, Name);
2830 if (RootContext.EvalMode){
2831 FieldInfo fi = Evaluator.LookupField (Name);
2833 return new FieldExpr (Import.CreateField (fi), loc).Resolve (ec);
2836 if (almost_matched != null)
2837 almost_matched_members = almost_matched;
2838 if (almost_matched_type == null)
2839 almost_matched_type = ec.CurrentType;
2841 string type_name = ec.MemberContext.CurrentType == null ? null : ec.MemberContext.CurrentType.Name;
2842 return Error_MemberLookupFailed (ec, ec.CurrentType, null, almost_matched_type, Name,
2843 type_name, AllMemberTypes, AllBindingFlags);
2846 if (e is MemberExpr) {
2847 MemberExpr me = (MemberExpr) e;
2850 if (me.IsInstance) {
2851 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope)) {
2853 // Note that an MemberExpr can be both IsInstance and IsStatic.
2854 // An unresolved MethodGroupExpr can contain both kinds of methods
2855 // and each predicate is true if the MethodGroupExpr contains
2856 // at least one of that kind of method.
2860 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2861 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2866 // Pass the buck to MemberAccess and Invocation.
2868 left = EmptyExpression.Null;
2870 left = ec.GetThis (loc);
2873 left = new TypeExpression (ec.CurrentType, loc);
2876 me = me.ResolveMemberAccess (ec, left, loc, null);
2880 if (targs != null) {
2881 if (!targs.Resolve (ec))
2884 me.SetTypeArguments (ec, targs);
2887 if (!me.IsStatic && (me.InstanceExpression != null && me.InstanceExpression != EmptyExpression.Null) &&
2888 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2889 me.InstanceExpression.Type != me.DeclaringType &&
2890 !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2891 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2892 ec.Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2893 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2897 return (right_side != null)
2898 ? me.DoResolveLValue (ec, right_side)
2907 /// Represents a namespace or a type. The name of the class was inspired by
2908 /// section 10.8.1 (Fully Qualified Names).
2910 public abstract class FullNamedExpression : Expression
2912 protected override void CloneTo (CloneContext clonectx, Expression target)
2914 // Do nothing, most unresolved type expressions cannot be
2915 // resolved to different type
2918 public override Expression CreateExpressionTree (ResolveContext ec)
2920 throw new NotSupportedException ("ET");
2923 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2925 throw new NotSupportedException ();
2928 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2933 public override void Emit (EmitContext ec)
2935 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2936 GetSignatureForError ());
2941 /// Expression that evaluates to a type
2943 public abstract class TypeExpr : FullNamedExpression {
2944 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2946 TypeExpr t = DoResolveAsTypeStep (ec);
2950 eclass = ExprClass.Type;
2954 protected override Expression DoResolve (ResolveContext ec)
2956 return ResolveAsTypeTerminal (ec, false);
2959 public virtual bool CheckAccessLevel (IMemberContext mc)
2961 return mc.CurrentTypeDefinition.CheckAccessLevel (Type);
2964 public virtual bool IsClass {
2965 get { return Type.IsClass; }
2968 public virtual bool IsValueType {
2969 get { return TypeManager.IsStruct (Type); }
2972 public virtual bool IsInterface {
2973 get { return Type.IsInterface; }
2976 public virtual bool IsSealed {
2977 get { return Type.IsSealed; }
2980 public virtual bool CanInheritFrom ()
2982 if (Type == TypeManager.enum_type ||
2983 (Type == TypeManager.value_type && RootContext.StdLib) ||
2984 Type == TypeManager.multicast_delegate_type ||
2985 Type == TypeManager.delegate_type ||
2986 Type == TypeManager.array_type)
2992 protected abstract TypeExpr DoResolveAsTypeStep (IMemberContext ec);
2994 public override bool Equals (object obj)
2996 TypeExpr tobj = obj as TypeExpr;
3000 return Type == tobj.Type;
3003 public override int GetHashCode ()
3005 return Type.GetHashCode ();
3008 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3010 type = storey.MutateType (type);
3015 /// Fully resolved Expression that already evaluated to a type
3017 public class TypeExpression : TypeExpr {
3018 public TypeExpression (Type t, Location l)
3021 eclass = ExprClass.Type;
3025 protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec)
3030 public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
3037 // Used to create types from a fully qualified name. These are just used
3038 // by the parser to setup the core types.
3040 public sealed class TypeLookupExpression : TypeExpr {
3041 readonly string ns_name;
3042 readonly string name;
3044 public TypeLookupExpression (string ns, string name)
3048 eclass = ExprClass.Type;
3051 public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
3054 // It's null only during mscorlib bootstrap when DefineType
3055 // nees to resolve base type of same type
3057 // For instance struct Char : IComparable<char>
3059 // TODO: it could be removed when Resolve starts to use
3060 // DeclSpace instead of Type
3063 Namespace ns = GlobalRootNamespace.Instance.GetNamespace (ns_name, false);
3064 FullNamedExpression fne = ns.Lookup (ec.Compiler, name, loc);
3072 protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec)
3077 public override string GetSignatureForError ()
3080 return TypeManager.CSharpName (ns_name + "." + name, null);
3082 return base.GetSignatureForError ();
3087 /// This class denotes an expression which evaluates to a member
3088 /// of a struct or a class.
3090 public abstract class MemberExpr : Expression
3092 protected bool is_base;
3095 /// The name of this member.
3097 public abstract string Name {
3102 // When base.member is used
3104 public bool IsBase {
3105 get { return is_base; }
3106 set { is_base = value; }
3110 /// Whether this is an instance member.
3112 public abstract bool IsInstance {
3117 /// Whether this is a static member.
3119 public abstract bool IsStatic {
3124 /// The type which declares this member.
3126 public abstract Type DeclaringType {
3131 /// The instance expression associated with this member, if it's a
3132 /// non-static member.
3134 public Expression InstanceExpression;
3136 public static void error176 (ResolveContext ec, Location loc, string name)
3138 ec.Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
3139 "with an instance reference, qualify it with a type name instead", name);
3142 public static void Error_BaseAccessInExpressionTree (ResolveContext ec, Location loc)
3144 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
3147 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3149 if (InstanceExpression != null)
3150 InstanceExpression.MutateHoistedGenericType (storey);
3153 // TODO: possible optimalization
3154 // Cache resolved constant result in FieldBuilder <-> expression map
3155 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, Location loc,
3156 SimpleName original)
3160 // original == null || original.Resolve (...) ==> left
3163 if (left is TypeExpr) {
3164 left = left.ResolveAsBaseTerminal (ec, false);
3168 // TODO: Same problem as in class.cs, TypeTerminal does not
3169 // always do all necessary checks
3170 ObsoleteAttribute oa = AttributeTester.GetObsoleteAttribute (left.Type);
3171 if (oa != null && !ec.IsObsolete) {
3172 AttributeTester.Report_ObsoleteMessage (oa, left.GetSignatureForError (), loc, ec.Report);
3175 GenericTypeExpr ct = left as GenericTypeExpr;
3176 if (ct != null && !ct.CheckConstraints (ec))
3181 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3189 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3192 return ResolveExtensionMemberAccess (ec, left);
3195 InstanceExpression = left;
3199 protected virtual MemberExpr ResolveExtensionMemberAccess (ResolveContext ec, Expression left)
3201 error176 (ec, loc, GetSignatureForError ());
3205 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3210 if (InstanceExpression == EmptyExpression.Null) {
3211 // FIXME: This should not be here at all
3212 SimpleName.Error_ObjectRefRequired (new ResolveContext (ec.MemberContext), loc, GetSignatureForError ());
3216 if (TypeManager.IsValueType (InstanceExpression.Type)) {
3217 if (InstanceExpression is IMemoryLocation) {
3218 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
3220 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
3221 InstanceExpression.Emit (ec);
3223 t.AddressOf (ec, AddressOp.Store);
3226 InstanceExpression.Emit (ec);
3228 if (prepare_for_load)
3229 ec.ig.Emit (OpCodes.Dup);
3232 public virtual void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3234 // TODO: need to get correct member type
3235 ec.Report.Error (307, loc, "The property `{0}' cannot be used with type arguments",
3236 GetSignatureForError ());
3241 /// Represents group of extension methods
3243 public class ExtensionMethodGroupExpr : MethodGroupExpr
3245 readonly NamespaceEntry namespace_entry;
3246 public Expression ExtensionExpression;
3247 Argument extension_argument;
3249 public ExtensionMethodGroupExpr (List<MethodSpec> list, NamespaceEntry n, Type extensionType, Location l)
3250 : base (list, extensionType, l)
3252 this.namespace_entry = n;
3255 public override bool IsStatic {
3256 get { return true; }
3259 public bool IsTopLevel {
3260 get { return namespace_entry == null; }
3263 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3265 extension_argument.Expr.MutateHoistedGenericType (storey);
3266 base.MutateHoistedGenericType (storey);
3269 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, bool may_fail, Location loc)
3271 if (arguments == null)
3272 arguments = new Arguments (1);
3274 arguments.Insert (0, new Argument (ExtensionExpression));
3275 MethodGroupExpr mg = ResolveOverloadExtensions (ec, ref arguments, namespace_entry, loc);
3277 // Store resolved argument and restore original arguments
3279 ((ExtensionMethodGroupExpr)mg).extension_argument = arguments [0];
3281 arguments.RemoveAt (0); // Clean-up modified arguments for error reporting
3286 MethodGroupExpr ResolveOverloadExtensions (ResolveContext ec, ref Arguments arguments, NamespaceEntry ns, Location loc)
3288 // Use normal resolve rules
3289 MethodGroupExpr mg = base.OverloadResolve (ec, ref arguments, ns != null, loc);
3297 ExtensionMethodGroupExpr e = ns.LookupExtensionMethod (type, Name, loc);
3299 return base.OverloadResolve (ec, ref arguments, false, loc);
3301 e.ExtensionExpression = ExtensionExpression;
3302 e.SetTypeArguments (ec, type_arguments);
3303 return e.ResolveOverloadExtensions (ec, ref arguments, e.namespace_entry, loc);
3308 /// MethodGroupExpr represents a group of method candidates which
3309 /// can be resolved to the best method overload
3311 public class MethodGroupExpr : MemberExpr
3313 public interface IErrorHandler
3315 bool AmbiguousCall (ResolveContext ec, MethodSpec ambiguous);
3316 bool NoExactMatch (ResolveContext ec, MethodSpec method);
3319 public IErrorHandler CustomErrorHandler;
3320 public MethodSpec [] Methods;
3321 MethodSpec best_candidate;
3322 // TODO: make private
3323 public TypeArguments type_arguments;
3324 bool identical_type_name;
3325 bool has_inaccessible_candidates_only;
3329 public MethodGroupExpr (MethodSpec [] mi, Type type, Location l)
3332 Methods = new MethodSpec[mi.Length];
3333 mi.CopyTo (Methods, 0);
3336 public MethodGroupExpr (MethodSpec[] mi, Type type, Location l, bool inacessibleCandidatesOnly)
3337 : this (mi, type, l)
3339 has_inaccessible_candidates_only = inacessibleCandidatesOnly;
3342 public MethodGroupExpr (List<MethodSpec> list, Type type, Location l)
3346 Methods = list.ToArray ();
3348 //foreach (MemberInfo m in list){
3349 // if (!(m is MethodBase)){
3350 // Console.WriteLine ("Name " + m.Name);
3351 // Console.WriteLine ("Found a: " + m.GetType ().FullName);
3360 protected MethodGroupExpr (Type type, Location loc)
3363 eclass = ExprClass.MethodGroup;
3364 this.type = InternalType.MethodGroup;
3365 queried_type = type;
3368 public override Type DeclaringType {
3370 return queried_type;
3374 public MethodSpec BestCandidate {
3376 return best_candidate;
3380 public Type DelegateType {
3382 delegate_type = value;
3386 public bool IdenticalTypeName {
3388 return identical_type_name;
3392 public override string GetSignatureForError ()
3394 if (best_candidate != null)
3395 return TypeManager.CSharpSignature (best_candidate.MetaInfo);
3397 return TypeManager.CSharpSignature (Methods [0].MetaInfo);
3400 public override string Name {
3402 return Methods [0].Name;
3406 public override bool IsInstance {
3408 if (best_candidate != null)
3409 return !best_candidate.IsStatic;
3411 foreach (var mb in Methods)
3419 public override bool IsStatic {
3421 if (best_candidate != null)
3422 return best_candidate.IsStatic;
3424 foreach (var mb in Methods)
3432 public static explicit operator MethodSpec (MethodGroupExpr mg)
3434 return mg.best_candidate;
3438 // 7.4.3.3 Better conversion from expression
3439 // Returns : 1 if a->p is better,
3440 // 2 if a->q is better,
3441 // 0 if neither is better
3443 static int BetterExpressionConversion (ResolveContext ec, Argument a, Type p, Type q)
3445 Type argument_type = TypeManager.TypeToCoreType (a.Type);
3446 if (argument_type == InternalType.AnonymousMethod && RootContext.Version > LanguageVersion.ISO_2) {
3448 // Uwrap delegate from Expression<T>
3450 if (TypeManager.DropGenericTypeArguments (p) == TypeManager.expression_type) {
3451 p = TypeManager.GetTypeArguments (p) [0];
3453 if (TypeManager.DropGenericTypeArguments (q) == TypeManager.expression_type) {
3454 q = TypeManager.GetTypeArguments (q) [0];
3457 p = Delegate.GetInvokeMethod (ec.Compiler, null, p).ReturnType;
3458 q = Delegate.GetInvokeMethod (ec.Compiler, null, q).ReturnType;
3459 if (p == TypeManager.void_type && q != TypeManager.void_type)
3461 if (q == TypeManager.void_type && p != TypeManager.void_type)
3464 if (argument_type == p)
3467 if (argument_type == q)
3471 return BetterTypeConversion (ec, p, q);
3475 // 7.4.3.4 Better conversion from type
3477 public static int BetterTypeConversion (ResolveContext ec, Type p, Type q)
3479 if (p == null || q == null)
3480 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3482 if (p == TypeManager.int32_type) {
3483 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3485 } else if (p == TypeManager.int64_type) {
3486 if (q == TypeManager.uint64_type)
3488 } else if (p == TypeManager.sbyte_type) {
3489 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3490 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3492 } else if (p == TypeManager.short_type) {
3493 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3494 q == TypeManager.uint64_type)
3496 } else if (p == InternalType.Dynamic) {
3497 if (q == TypeManager.object_type)
3501 if (q == TypeManager.int32_type) {
3502 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3504 } if (q == TypeManager.int64_type) {
3505 if (p == TypeManager.uint64_type)
3507 } else if (q == TypeManager.sbyte_type) {
3508 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3509 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3511 } if (q == TypeManager.short_type) {
3512 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3513 p == TypeManager.uint64_type)
3515 } else if (q == InternalType.Dynamic) {
3516 if (p == TypeManager.object_type)
3520 // TODO: this is expensive
3521 Expression p_tmp = new EmptyExpression (p);
3522 Expression q_tmp = new EmptyExpression (q);
3524 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3525 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3527 if (p_to_q && !q_to_p)
3530 if (q_to_p && !p_to_q)
3537 /// Determines "Better function" between candidate
3538 /// and the current best match
3541 /// Returns a boolean indicating :
3542 /// false if candidate ain't better
3543 /// true if candidate is better than the current best match
3545 static bool BetterFunction (ResolveContext ec, Arguments args, int argument_count,
3546 MethodSpec candidate, bool candidate_params,
3547 MethodSpec best, bool best_params)
3549 AParametersCollection candidate_pd = candidate.Parameters;
3550 AParametersCollection best_pd = best.Parameters;
3552 bool better_at_least_one = false;
3554 for (int j = 0, c_idx = 0, b_idx = 0; j < argument_count; ++j, ++c_idx, ++b_idx)
3556 Argument a = args [j];
3558 // Provided default argument value is never better
3559 if (a.IsDefaultArgument && candidate_params == best_params)
3562 Type ct = candidate_pd.Types [c_idx];
3563 Type bt = best_pd.Types [b_idx];
3565 if (candidate_params && candidate_pd.FixedParameters [c_idx].ModFlags == Parameter.Modifier.PARAMS)
3567 ct = TypeManager.GetElementType (ct);
3571 if (best_params && best_pd.FixedParameters [b_idx].ModFlags == Parameter.Modifier.PARAMS)
3573 bt = TypeManager.GetElementType (bt);
3577 if (TypeManager.IsEqual (ct, bt))
3581 int result = BetterExpressionConversion (ec, a, ct, bt);
3583 // for each argument, the conversion to 'ct' should be no worse than
3584 // the conversion to 'bt'.
3588 // for at least one argument, the conversion to 'ct' should be better than
3589 // the conversion to 'bt'.
3591 better_at_least_one = true;
3594 if (better_at_least_one)
3598 // This handles the case
3600 // Add (float f1, float f2, float f3);
3601 // Add (params decimal [] foo);
3603 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3604 // first candidate would've chosen as better.
3610 // The two methods have equal parameter types. Now apply tie-breaking rules
3612 if (best.IsGenericMethod) {
3613 if (!candidate.IsGenericMethod)
3615 } else if (candidate.IsGenericMethod) {
3620 // This handles the following cases:
3622 // Trim () is better than Trim (params char[] chars)
3623 // Concat (string s1, string s2, string s3) is better than
3624 // Concat (string s1, params string [] srest)
3625 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3627 if (!candidate_params && best_params)
3629 if (candidate_params && !best_params)
3632 int candidate_param_count = candidate_pd.Count;
3633 int best_param_count = best_pd.Count;
3635 if (candidate_param_count != best_param_count)
3636 // can only happen if (candidate_params && best_params)
3637 return candidate_param_count > best_param_count && best_pd.HasParams;
3640 // now, both methods have the same number of parameters, and the parameters have the same types
3641 // Pick the "more specific" signature
3644 MethodBase orig_candidate = TypeManager.DropGenericMethodArguments (candidate);
3645 MethodBase orig_best = TypeManager.DropGenericMethodArguments (best);
3647 AParametersCollection orig_candidate_pd = TypeManager.GetParameterData (orig_candidate);
3648 AParametersCollection orig_best_pd = TypeManager.GetParameterData (orig_best);
3650 bool specific_at_least_once = false;
3651 for (int j = 0; j < candidate_param_count; ++j)
3653 Type ct = orig_candidate_pd.Types [j];
3654 Type bt = orig_best_pd.Types [j];
3657 Type specific = MoreSpecific (ct, bt);
3661 specific_at_least_once = true;
3664 if (specific_at_least_once)
3667 // FIXME: handle lifted operators
3673 protected override MemberExpr ResolveExtensionMemberAccess (ResolveContext ec, Expression left)
3676 return base.ResolveExtensionMemberAccess (ec, left);
3679 // When left side is an expression and at least one candidate method is
3680 // static, it can be extension method
3682 InstanceExpression = left;
3686 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, Location loc,
3687 SimpleName original)
3689 if (!(left is TypeExpr) &&
3690 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3691 identical_type_name = true;
3693 return base.ResolveMemberAccess (ec, left, loc, original);
3696 public override Expression CreateExpressionTree (ResolveContext ec)
3698 if (best_candidate == null) {
3699 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3703 IMethodData md = TypeManager.GetMethod (best_candidate.MetaInfo);
3704 if (md != null && md.IsExcluded ())
3705 ec.Report.Error (765, loc,
3706 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3708 return new TypeOfMethod (best_candidate, loc);
3711 protected override Expression DoResolve (ResolveContext ec)
3713 this.eclass = ExprClass.MethodGroup;
3715 if (InstanceExpression != null) {
3716 InstanceExpression = InstanceExpression.Resolve (ec);
3717 if (InstanceExpression == null)
3724 public void ReportUsageError (ResolveContext ec)
3726 ec.Report.Error (654, loc, "Method `" + DeclaringType + "." +
3727 Name + "()' is referenced without parentheses");
3730 override public void Emit (EmitContext ec)
3732 throw new NotSupportedException ();
3733 // ReportUsageError ();
3736 public void EmitCall (EmitContext ec, Arguments arguments)
3738 Invocation.EmitCall (ec, IsBase, InstanceExpression, best_candidate, arguments, loc);
3741 void Error_AmbiguousCall (ResolveContext ec, MethodSpec ambiguous)
3743 if (CustomErrorHandler != null && CustomErrorHandler.AmbiguousCall (ec, ambiguous))
3746 ec.Report.SymbolRelatedToPreviousError (best_candidate.MetaInfo);
3747 ec.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
3748 TypeManager.CSharpSignature (ambiguous), TypeManager.CSharpSignature (best_candidate.MetaInfo));
3751 protected virtual void Error_InvalidArguments (ResolveContext ec, Location loc, int idx, MethodSpec method,
3752 Argument a, AParametersCollection expected_par, Type paramType)
3754 ExtensionMethodGroupExpr emg = this as ExtensionMethodGroupExpr;
3756 if (a is CollectionElementInitializer.ElementInitializerArgument) {
3757 ec.Report.SymbolRelatedToPreviousError (method.MetaInfo);
3758 if ((expected_par.FixedParameters [idx].ModFlags & Parameter.Modifier.ISBYREF) != 0) {
3759 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
3760 TypeManager.CSharpSignature (method));
3763 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
3764 TypeManager.CSharpSignature (method));
3765 } else if (TypeManager.IsDelegateType (method.DeclaringType)) {
3766 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
3767 TypeManager.CSharpName (method.DeclaringType));
3769 ec.Report.SymbolRelatedToPreviousError (method.MetaInfo);
3771 ec.Report.Error (1928, loc,
3772 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3773 emg.ExtensionExpression.GetSignatureForError (),
3774 emg.Name, TypeManager.CSharpSignature (method));
3776 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
3777 TypeManager.CSharpSignature (method));
3781 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters [idx].ModFlags;
3783 string index = (idx + 1).ToString ();
3784 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
3785 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
3786 if ((mod & Parameter.Modifier.ISBYREF) == 0)
3787 ec.Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
3788 index, Parameter.GetModifierSignature (a.Modifier));
3790 ec.Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
3791 index, Parameter.GetModifierSignature (mod));
3793 string p1 = a.GetSignatureForError ();
3794 string p2 = TypeManager.CSharpName (paramType);
3797 ec.Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
3798 ec.Report.SymbolRelatedToPreviousError (a.Expr.Type);
3799 ec.Report.SymbolRelatedToPreviousError (paramType);
3802 if (idx == 0 && emg != null) {
3803 ec.Report.Error (1929, loc,
3804 "Extension method instance type `{0}' cannot be converted to `{1}'", p1, p2);
3806 ec.Report.Error (1503, loc,
3807 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
3812 public override void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, Type target, bool expl)
3814 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3815 Name, TypeManager.CSharpName (target));
3818 void Error_ArgumentCountWrong (ResolveContext ec, int arg_count)
3820 ec.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
3821 Name, arg_count.ToString ());
3824 protected virtual int GetApplicableParametersCount (MethodSpec method, AParametersCollection parameters)
3826 return parameters.Count;
3829 public static bool IsAncestralType (Type first_type, Type second_type)
3831 return first_type != second_type &&
3832 (TypeManager.IsSubclassOf (second_type, first_type) ||
3833 TypeManager.ImplementsInterface (second_type, first_type));
3837 /// Determines if the candidate method is applicable (section 14.4.2.1)
3838 /// to the given set of arguments
3839 /// A return value rates candidate method compatibility,
3840 /// 0 = the best, int.MaxValue = the worst
3842 public int IsApplicable (ResolveContext ec,
3843 ref Arguments arguments, int arg_count, ref MethodSpec method, ref bool params_expanded_form)
3845 var candidate = method;
3847 AParametersCollection pd = candidate.Parameters;
3848 int param_count = GetApplicableParametersCount (candidate, pd);
3849 int optional_count = 0;
3851 if (arg_count != param_count) {
3852 for (int i = 0; i < pd.Count; ++i) {
3853 if (pd.FixedParameters [i].HasDefaultValue) {
3854 optional_count = pd.Count - i;
3859 int args_gap = System.Math.Abs (arg_count - param_count);
3860 if (optional_count != 0) {
3861 if (args_gap > optional_count)
3862 return int.MaxValue - 10000 + args_gap - optional_count;
3864 // Readjust expected number when params used
3867 if (arg_count < param_count)
3869 } else if (arg_count > param_count) {
3870 return int.MaxValue - 10000 + args_gap;
3872 } else if (arg_count != param_count) {
3874 return int.MaxValue - 10000 + args_gap;
3875 if (arg_count < param_count - 1)
3876 return int.MaxValue - 10000 + args_gap;
3879 // Initialize expanded form of a method with 1 params parameter
3880 params_expanded_form = param_count == 1 && pd.HasParams;
3882 // Resize to fit optional arguments
3883 if (optional_count != 0) {
3885 if (arguments == null) {
3886 resized = new Arguments (optional_count);
3888 resized = new Arguments (param_count);
3889 resized.AddRange (arguments);
3892 for (int i = arg_count; i < param_count; ++i)
3894 arguments = resized;
3898 if (arg_count > 0) {
3900 // Shuffle named arguments to the right positions if there are any
3902 if (arguments [arg_count - 1] is NamedArgument) {
3903 arg_count = arguments.Count;
3905 for (int i = 0; i < arg_count; ++i) {
3906 bool arg_moved = false;
3908 NamedArgument na = arguments[i] as NamedArgument;
3912 int index = pd.GetParameterIndexByName (na.Name);
3914 // Named parameter not found or already reordered
3918 // When using parameters which should not be available to the user
3919 if (index >= param_count)
3923 arguments.MarkReorderedArgument (na);
3927 Argument temp = arguments[index];
3928 arguments[index] = arguments[i];
3929 arguments[i] = temp;
3936 arg_count = arguments.Count;
3938 } else if (arguments != null) {
3939 arg_count = arguments.Count;
3943 // 1. Handle generic method using type arguments when specified or type inference
3945 if (candidate.IsGenericMethod) {
3946 if (type_arguments != null) {
3947 Type [] g_args = candidate.GetGenericArguments ();
3948 if (g_args.Length != type_arguments.Count)
3949 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args.Length);
3951 method = candidate.Inflate (type_arguments.Arguments);
3953 pd = candidate.Parameters;
3955 int score = TypeManager.InferTypeArguments (ec, arguments, ref candidate);
3957 return score - 20000;
3959 if (TypeManager.IsGenericMethodDefinition (candidate.MetaInfo))
3960 throw new InternalErrorException ("A generic method `{0}' definition took part in overload resolution",
3961 TypeManager.CSharpSignature (candidate.MetaInfo));
3963 pd = candidate.Parameters;
3966 if (type_arguments != null)
3967 return int.MaxValue - 15000;
3971 // 2. Each argument has to be implicitly convertible to method parameter
3974 Parameter.Modifier p_mod = 0;
3976 for (int i = 0; i < arg_count; i++) {
3977 Argument a = arguments [i];
3979 if (!pd.FixedParameters [i].HasDefaultValue)
3980 throw new InternalErrorException ();
3982 Expression e = pd.FixedParameters [i].DefaultValue as Constant;
3984 e = new DefaultValueExpression (new TypeExpression (pd.Types [i], loc), loc).Resolve (ec);
3986 arguments [i] = new Argument (e, Argument.AType.Default);
3990 if (p_mod != Parameter.Modifier.PARAMS) {
3991 p_mod = pd.FixedParameters [i].ModFlags & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3994 params_expanded_form = true;
3997 Parameter.Modifier a_mod = a.Modifier & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3999 if (!params_expanded_form)
4000 score = IsArgumentCompatible (ec, a_mod, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
4002 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && delegate_type == null) {
4003 // It can be applicable in expanded form
4004 score = IsArgumentCompatible (ec, a_mod, a, 0, TypeManager.GetElementType (pt));
4006 params_expanded_form = true;
4010 if (params_expanded_form)
4012 return (arg_count - i) * 2 + score;
4016 if (arg_count != param_count)
4017 params_expanded_form = true;
4022 int IsArgumentCompatible (ResolveContext ec, Parameter.Modifier arg_mod, Argument argument, Parameter.Modifier param_mod, Type parameter)
4025 // Types have to be identical when ref or out modifer is used
4027 if (arg_mod != 0 || param_mod != 0) {
4028 if (TypeManager.HasElementType (parameter))
4029 parameter = TypeManager.GetElementType (parameter);
4031 Type a_type = argument.Type;
4032 if (TypeManager.HasElementType (a_type))
4033 a_type = TypeManager.GetElementType (a_type);
4035 if (a_type != parameter) {
4036 if (TypeManager.IsDynamicType (a_type))
4042 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
4043 if (TypeManager.IsDynamicType (argument.Type))
4050 if (arg_mod != param_mod)
4056 public static bool IsOverride (MethodBase cand_method, MethodBase base_method)
4058 if (!IsAncestralType (base_method.DeclaringType, cand_method.DeclaringType))
4061 AParametersCollection cand_pd = TypeManager.GetParameterData (cand_method);
4062 AParametersCollection base_pd = TypeManager.GetParameterData (base_method);
4064 if (cand_pd.Count != base_pd.Count)
4067 for (int j = 0; j < cand_pd.Count; ++j)
4069 Parameter.Modifier cm = cand_pd.FixedParameters [j].ModFlags;
4070 Parameter.Modifier bm = base_pd.FixedParameters [j].ModFlags;
4071 Type ct = cand_pd.Types [j];
4072 Type bt = base_pd.Types [j];
4074 if (cm != bm || ct != bt)
4081 public static MethodGroupExpr MakeUnionSet (MethodGroupExpr mg1, MethodGroupExpr mg2, Location loc)
4092 var all = new List<MethodSpec> (mg1.Methods);
4093 foreach (var m in mg2.Methods){
4094 if (!TypeManager.ArrayContainsMethod (mg1.Methods.Select (l => l.MetaInfo).ToArray (), m.MetaInfo, false))
4098 return new MethodGroupExpr (all, null, loc);
4101 static Type MoreSpecific (Type p, Type q)
4103 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4105 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4108 if (TypeManager.HasElementType (p))
4110 Type pe = TypeManager.GetElementType (p);
4111 Type qe = TypeManager.GetElementType (q);
4112 Type specific = MoreSpecific (pe, qe);
4118 else if (TypeManager.IsGenericType (p))
4120 Type[] pargs = TypeManager.GetTypeArguments (p);
4121 Type[] qargs = TypeManager.GetTypeArguments (q);
4123 bool p_specific_at_least_once = false;
4124 bool q_specific_at_least_once = false;
4126 for (int i = 0; i < pargs.Length; i++)
4128 Type specific = MoreSpecific (TypeManager.TypeToCoreType (pargs [i]), TypeManager.TypeToCoreType (qargs [i]));
4129 if (specific == pargs [i])
4130 p_specific_at_least_once = true;
4131 if (specific == qargs [i])
4132 q_specific_at_least_once = true;
4135 if (p_specific_at_least_once && !q_specific_at_least_once)
4137 if (!p_specific_at_least_once && q_specific_at_least_once)
4144 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4146 base.MutateHoistedGenericType (storey);
4148 if (best_candidate.IsConstructor) {
4149 storey.MutateConstructor (best_candidate);
4151 storey.MutateGenericMethod (best_candidate);
4156 /// Find the Applicable Function Members (7.4.2.1)
4158 /// me: Method Group expression with the members to select.
4159 /// it might contain constructors or methods (or anything
4160 /// that maps to a method).
4162 /// Arguments: ArrayList containing resolved Argument objects.
4164 /// loc: The location if we want an error to be reported, or a Null
4165 /// location for "probing" purposes.
4167 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4168 /// that is the best match of me on Arguments.
4171 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments Arguments,
4172 bool may_fail, Location loc)
4174 bool method_params = false;
4175 Type applicable_type = null;
4176 var candidates = new List<MethodSpec> (2);
4177 List<MethodSpec> candidate_overrides = null;
4180 // Used to keep a map between the candidate
4181 // and whether it is being considered in its
4182 // normal or expanded form
4184 // false is normal form, true is expanded form
4186 Dictionary<MethodSpec, MethodSpec> candidate_to_form = null;
4187 Dictionary<MethodSpec, Arguments> candidates_expanded = null;
4188 Arguments candidate_args = Arguments;
4190 int arg_count = Arguments != null ? Arguments.Count : 0;
4192 if (RootContext.Version == LanguageVersion.ISO_1 && Name == "Invoke" && TypeManager.IsDelegateType (DeclaringType)) {
4194 ec.Report.Error (1533, loc, "Invoke cannot be called directly on a delegate");
4198 int nmethods = Methods.Length;
4202 // Methods marked 'override' don't take part in 'applicable_type'
4203 // computation, nor in the actual overload resolution.
4204 // However, they still need to be emitted instead of a base virtual method.
4205 // So, we salt them away into the 'candidate_overrides' array.
4207 // In case of reflected methods, we replace each overriding method with
4208 // its corresponding base virtual method. This is to improve compatibility
4209 // with non-C# libraries which change the visibility of overrides (#75636)
4212 MethodBase mb = null;
4213 for (int i = 0; i < Methods.Length; ++i) {
4214 var m = Methods [i];
4216 if (TypeManager.IsOverride (m)) {
4217 if (candidate_overrides == null)
4218 candidate_overrides = new List<MethodSpec> ();
4219 candidate_overrides.Add (m);
4220 mb = TypeManager.TryGetBaseDefinition (mb);
4221 if (mb != null && Array.Exists (Methods, l => l.MetaInfo == mb))
4225 Methods [j++] = Import.CreateMethod (mb);
4231 // Enable message recording, it's used mainly by lambda expressions
4233 SessionReportPrinter msg_recorder = new SessionReportPrinter ();
4234 ReportPrinter prev_recorder = ec.Report.SetPrinter (msg_recorder);
4237 // First we construct the set of applicable methods
4239 bool is_sorted = true;
4240 int best_candidate_rate = int.MaxValue;
4241 for (int i = 0; i < nmethods; i++) {
4242 Type decl_type = Methods [i].DeclaringType;
4245 // If we have already found an applicable method
4246 // we eliminate all base types (Section 14.5.5.1)
4248 if (applicable_type != null && IsAncestralType (decl_type, applicable_type))
4252 // Check if candidate is applicable (section 14.4.2.1)
4254 bool params_expanded_form = false;
4255 int candidate_rate = IsApplicable (ec, ref candidate_args, arg_count, ref Methods [i], ref params_expanded_form);
4257 if (candidate_rate < best_candidate_rate) {
4258 best_candidate_rate = candidate_rate;
4259 best_candidate = Methods [i];
4262 if (params_expanded_form) {
4263 if (candidate_to_form == null)
4264 candidate_to_form = new Dictionary<MethodSpec, MethodSpec> (4, ReferenceEquality<MethodSpec>.Default);
4265 var candidate = Methods [i];
4266 candidate_to_form [candidate] = candidate;
4269 if (candidate_args != Arguments) {
4270 if (candidates_expanded == null)
4271 candidates_expanded = new Dictionary<MethodSpec, Arguments> (4, ReferenceEquality<MethodSpec>.Default);
4273 candidates_expanded.Add (Methods [i], candidate_args);
4274 candidate_args = Arguments;
4277 if (candidate_rate != 0 || has_inaccessible_candidates_only) {
4278 if (msg_recorder != null)
4279 msg_recorder.EndSession ();
4283 msg_recorder = null;
4284 candidates.Add (Methods [i]);
4286 if (applicable_type == null)
4287 applicable_type = decl_type;
4288 else if (applicable_type != decl_type) {
4290 if (IsAncestralType (applicable_type, decl_type))
4291 applicable_type = decl_type;
4295 ec.Report.SetPrinter (prev_recorder);
4296 if (msg_recorder != null && !msg_recorder.IsEmpty) {
4298 msg_recorder.Merge (prev_recorder);
4303 int candidate_top = candidates.Count;
4305 if (applicable_type == null) {
4307 // When we found a top level method which does not match and it's
4308 // not an extension method. We start extension methods lookup from here
4310 if (InstanceExpression != null) {
4311 ExtensionMethodGroupExpr ex_method_lookup = ec.LookupExtensionMethod (type, Name, loc);
4312 if (ex_method_lookup != null) {
4313 ex_method_lookup.ExtensionExpression = InstanceExpression;
4314 ex_method_lookup.SetTypeArguments (ec, type_arguments);
4315 return ex_method_lookup.OverloadResolve (ec, ref Arguments, may_fail, loc);
4323 // Okay so we have failed to find exact match so we
4324 // return error info about the closest match
4326 if (best_candidate != null) {
4327 if (CustomErrorHandler != null && !has_inaccessible_candidates_only && CustomErrorHandler.NoExactMatch (ec, best_candidate))
4330 if (NoExactMatch (ec, ref Arguments, candidate_to_form))
4335 // We failed to find any method with correct argument count
4337 if (Name == ConstructorInfo.ConstructorName) {
4338 ec.Report.SymbolRelatedToPreviousError (queried_type);
4339 ec.Report.Error (1729, loc,
4340 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4341 TypeManager.CSharpName (queried_type), arg_count);
4343 Error_ArgumentCountWrong (ec, arg_count);
4349 if (arg_count != 0 && Arguments.HasDynamic) {
4350 best_candidate = null;
4356 // At this point, applicable_type is _one_ of the most derived types
4357 // in the set of types containing the methods in this MethodGroup.
4358 // Filter the candidates so that they only contain methods from the
4359 // most derived types.
4362 int finalized = 0; // Number of finalized candidates
4365 // Invariant: applicable_type is a most derived type
4367 // We'll try to complete Section 14.5.5.1 for 'applicable_type' by
4368 // eliminating all it's base types. At the same time, we'll also move
4369 // every unrelated type to the end of the array, and pick the next
4370 // 'applicable_type'.
4372 Type next_applicable_type = null;
4373 int j = finalized; // where to put the next finalized candidate
4374 int k = finalized; // where to put the next undiscarded candidate
4375 for (int i = finalized; i < candidate_top; ++i) {
4376 var candidate = candidates [i];
4377 Type decl_type = candidate.DeclaringType;
4379 if (decl_type == applicable_type) {
4380 candidates [k++] = candidates [j];
4381 candidates [j++] = candidates [i];
4385 if (IsAncestralType (decl_type, applicable_type))
4388 if (next_applicable_type != null &&
4389 IsAncestralType (decl_type, next_applicable_type))
4392 candidates [k++] = candidates [i];
4394 if (next_applicable_type == null ||
4395 IsAncestralType (next_applicable_type, decl_type))
4396 next_applicable_type = decl_type;
4399 applicable_type = next_applicable_type;
4402 } while (applicable_type != null);
4406 // Now we actually find the best method
4409 best_candidate = candidates [0];
4410 method_params = candidate_to_form != null && candidate_to_form.ContainsKey (best_candidate);
4413 // TODO: Broken inverse order of candidates logic does not work with optional
4414 // parameters used for method overrides and I am not going to fix it for SRE
4416 if (candidates_expanded != null && candidates_expanded.ContainsKey (best_candidate)) {
4417 candidate_args = candidates_expanded [best_candidate];
4418 arg_count = candidate_args.Count;
4421 for (int ix = 1; ix < candidate_top; ix++) {
4422 var candidate = candidates [ix];
4424 if (candidate.MetaInfo == best_candidate.MetaInfo)
4427 bool cand_params = candidate_to_form != null && candidate_to_form.ContainsKey (candidate);
4429 if (BetterFunction (ec, candidate_args, arg_count,
4430 candidate, cand_params,
4431 best_candidate, method_params)) {
4432 best_candidate = candidate;
4433 method_params = cand_params;
4437 // Now check that there are no ambiguities i.e the selected method
4438 // should be better than all the others
4440 MethodSpec ambiguous = null;
4441 for (int ix = 1; ix < candidate_top; ix++) {
4442 var candidate = candidates [ix];
4444 if (candidate.MetaInfo == best_candidate.MetaInfo)
4447 bool cand_params = candidate_to_form != null && candidate_to_form.ContainsKey (candidate);
4448 if (!BetterFunction (ec, candidate_args, arg_count,
4449 best_candidate, method_params,
4450 candidate, cand_params))
4453 ec.Report.SymbolRelatedToPreviousError (candidate.MetaInfo);
4454 ambiguous = candidate;
4458 if (ambiguous != null) {
4459 Error_AmbiguousCall (ec, ambiguous);
4464 // If the method is a virtual function, pick an override closer to the LHS type.
4466 if (!IsBase && best_candidate.IsVirtual) {
4467 if (TypeManager.IsOverride (best_candidate))
4468 throw new InternalErrorException (
4469 "Should not happen. An 'override' method took part in overload resolution: " + best_candidate);
4471 if (candidate_overrides != null) {
4472 Type[] gen_args = null;
4473 bool gen_override = false;
4474 if (best_candidate.IsGenericMethod)
4475 gen_args = TypeManager.GetGenericArguments (best_candidate.MetaInfo);
4477 foreach (var candidate in candidate_overrides) {
4478 if (candidate.IsGenericMethod) {
4479 if (gen_args == null)
4482 if (gen_args.Length != TypeManager.GetGenericArguments (candidate.MetaInfo).Length)
4485 if (gen_args != null)
4489 if (IsOverride (candidate.MetaInfo, best_candidate.MetaInfo)) {
4490 gen_override = true;
4491 best_candidate = candidate;
4495 if (gen_override && gen_args != null) {
4496 best_candidate = best_candidate.Inflate (gen_args);
4502 // And now check if the arguments are all
4503 // compatible, perform conversions if
4504 // necessary etc. and return if everything is
4507 if (!VerifyArgumentsCompat (ec, ref candidate_args, arg_count, best_candidate,
4508 method_params, may_fail, loc))
4511 if (best_candidate == null)
4514 MethodBase the_method = TypeManager.DropGenericMethodArguments (best_candidate);
4515 if (TypeManager.IsGenericMethodDefinition (the_method) &&
4516 !ConstraintChecker.CheckConstraints (ec, the_method, best_candidate.MetaInfo, loc))
4520 // Check ObsoleteAttribute on the best method
4522 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (the_method);
4523 if (oa != null && !ec.IsObsolete)
4524 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
4526 IMethodData data = TypeManager.GetMethod (the_method);
4530 Arguments = candidate_args;
4534 bool NoExactMatch (ResolveContext ec, ref Arguments Arguments, IDictionary<MethodSpec, MethodSpec> candidate_to_form)
4536 AParametersCollection pd = best_candidate.Parameters;
4537 int arg_count = Arguments == null ? 0 : Arguments.Count;
4539 if (arg_count == pd.Count || pd.HasParams) {
4540 if (TypeManager.IsGenericMethodDefinition (best_candidate.MetaInfo)) {
4541 if (type_arguments == null) {
4542 ec.Report.Error (411, loc,
4543 "The type arguments for method `{0}' cannot be inferred from " +
4544 "the usage. Try specifying the type arguments explicitly",
4545 TypeManager.CSharpSignature (best_candidate.MetaInfo));
4549 Type[] g_args = TypeManager.GetGenericArguments (best_candidate.MetaInfo);
4550 if (type_arguments.Count != g_args.Length) {
4551 ec.Report.SymbolRelatedToPreviousError (best_candidate.MetaInfo);
4552 ec.Report.Error (305, loc, "Using the generic method `{0}' requires `{1}' type argument(s)",
4553 TypeManager.CSharpSignature (best_candidate.MetaInfo),
4554 g_args.Length.ToString ());
4558 if (type_arguments != null && !best_candidate.IsGenericMethod) {
4559 Error_TypeArgumentsCannotBeUsed (ec.Report, loc);
4564 if (has_inaccessible_candidates_only) {
4565 if (InstanceExpression != null && type != ec.CurrentType && TypeManager.IsNestedFamilyAccessible (ec.CurrentType, best_candidate.DeclaringType)) {
4566 // Although a derived class can access protected members of
4567 // its base class it cannot do so through an instance of the
4568 // base class (CS1540). If the qualifier_type is a base of the
4569 // ec.CurrentType and the lookup succeeds with the latter one,
4570 // then we are in this situation.
4571 Error_CannotAccessProtected (ec, loc, best_candidate.MetaInfo, queried_type, ec.CurrentType);
4573 ec.Report.SymbolRelatedToPreviousError (best_candidate.MetaInfo);
4574 ErrorIsInaccesible (loc, GetSignatureForError (), ec.Report);
4578 bool cand_params = candidate_to_form != null && candidate_to_form.ContainsKey (best_candidate);
4579 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate, cand_params, false, loc))
4582 if (has_inaccessible_candidates_only)
4589 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4591 type_arguments = ta;
4594 public bool VerifyArgumentsCompat (ResolveContext ec, ref Arguments arguments,
4595 int arg_count, MethodSpec method,
4596 bool chose_params_expanded,
4597 bool may_fail, Location loc)
4599 AParametersCollection pd = method.Parameters;
4600 int param_count = GetApplicableParametersCount (method, pd);
4602 int errors = ec.Report.Errors;
4603 Parameter.Modifier p_mod = 0;
4605 int a_idx = 0, a_pos = 0;
4607 ArrayInitializer params_initializers = null;
4608 bool has_unsafe_arg = method.ReturnType.IsPointer;
4610 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4611 a = arguments [a_idx];
4612 if (p_mod != Parameter.Modifier.PARAMS) {
4613 p_mod = pd.FixedParameters [a_idx].ModFlags;
4614 pt = pd.Types [a_idx];
4615 has_unsafe_arg |= pt.IsPointer;
4617 if (p_mod == Parameter.Modifier.PARAMS) {
4618 if (chose_params_expanded) {
4619 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
4620 pt = TypeManager.GetElementType (pt);
4626 // Types have to be identical when ref or out modifer is used
4628 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4629 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4632 if (!TypeManager.IsEqual (a.Expr.Type, pt))
4637 NamedArgument na = a as NamedArgument;
4639 int name_index = pd.GetParameterIndexByName (na.Name);
4640 if (name_index < 0 || name_index >= param_count) {
4641 if (DeclaringType != null && TypeManager.IsDelegateType (DeclaringType)) {
4642 ec.Report.SymbolRelatedToPreviousError (DeclaringType);
4643 ec.Report.Error (1746, na.Location,
4644 "The delegate `{0}' does not contain a parameter named `{1}'",
4645 TypeManager.CSharpName (DeclaringType), na.Name);
4647 ec.Report.SymbolRelatedToPreviousError (best_candidate.MetaInfo);
4648 ec.Report.Error (1739, na.Location,
4649 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
4650 TypeManager.CSharpSignature (method.MetaInfo), na.Name);
4652 } else if (arguments[name_index] != a) {
4653 if (DeclaringType != null && TypeManager.IsDelegateType (DeclaringType))
4654 ec.Report.SymbolRelatedToPreviousError (DeclaringType);
4656 ec.Report.SymbolRelatedToPreviousError (best_candidate.MetaInfo);
4658 ec.Report.Error (1744, na.Location,
4659 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
4665 if (TypeManager.IsDynamicType (a.Expr.Type))
4668 if (delegate_type != null && !Delegate.IsTypeCovariant (a.Expr, pt))
4671 Expression conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4676 // Convert params arguments to an array initializer
4678 if (params_initializers != null) {
4679 // we choose to use 'a.Expr' rather than 'conv' so that
4680 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
4681 params_initializers.Add (a.Expr);
4682 arguments.RemoveAt (a_idx--);
4687 // Update the argument with the implicit conversion
4691 if (a_idx != arg_count) {
4692 if (!may_fail && ec.Report.Errors == errors) {
4693 if (CustomErrorHandler != null)
4694 CustomErrorHandler.NoExactMatch (ec, best_candidate);
4696 Error_InvalidArguments (ec, loc, a_pos, method, a, pd, pt);
4702 // Fill not provided arguments required by params modifier
4704 if (params_initializers == null && pd.HasParams && arg_count + 1 == param_count) {
4705 if (arguments == null)
4706 arguments = new Arguments (1);
4708 pt = pd.Types [param_count - 1];
4709 pt = TypeManager.GetElementType (pt);
4710 has_unsafe_arg |= pt.IsPointer;
4711 params_initializers = new ArrayInitializer (0, loc);
4715 // Append an array argument with all params arguments
4717 if (params_initializers != null) {
4718 arguments.Add (new Argument (
4719 new ArrayCreation (new TypeExpression (pt, loc), "[]", params_initializers, loc).Resolve (ec)));
4723 if (arg_count < param_count) {
4725 Error_ArgumentCountWrong (ec, arg_count);
4729 if (has_unsafe_arg && !ec.IsUnsafe) {
4731 UnsafeError (ec, loc);
4739 public class ConstantExpr : MemberExpr
4743 public ConstantExpr (ConstSpec constant, Location loc)
4745 this.constant = constant;
4749 public override string Name {
4750 get { throw new NotImplementedException (); }
4753 public override bool IsInstance {
4754 get { return !IsStatic; }
4757 public override bool IsStatic {
4758 get { return true; }
4761 public override Type DeclaringType {
4762 get { return constant.DeclaringType; }
4765 public override Expression CreateExpressionTree (ResolveContext ec)
4767 throw new NotSupportedException ("ET");
4770 protected override Expression DoResolve (ResolveContext rc)
4772 constant.MemberDefinition.SetIsUsed ();
4774 if (!rc.IsObsolete) {
4775 var oa = constant.GetObsoleteAttribute ();
4777 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (constant.MetaInfo), loc, rc.Report);
4780 // Constants are resolved on-demand
4781 var c = constant.Value.Resolve (rc) as Constant;
4783 // Creates reference expression to the constant value
4784 return Constant.CreateConstant (rc, c.Type, c.GetValue (), loc);
4787 public override void Emit (EmitContext ec)
4789 throw new NotSupportedException ();
4792 public override string GetSignatureForError ()
4794 return TypeManager.GetFullNameSignature (constant.MetaInfo);
4799 /// Fully resolved expression that evaluates to a Field
4801 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference {
4802 protected FieldSpec spec;
4803 readonly Type constructed_generic_type;
4804 VariableInfo variable_info;
4806 LocalTemporary temp;
4809 protected FieldExpr (Location l)
4814 public FieldExpr (FieldSpec spec, Location loc)
4819 type = TypeManager.TypeToCoreType (spec.FieldType);
4822 public FieldExpr (FieldBase fi, Location l)
4828 public FieldExpr (Field fi, Type genericType, Location l)
4831 if (TypeManager.IsGenericTypeDefinition (genericType))
4833 this.constructed_generic_type = genericType;
4836 public override string Name {
4842 public override bool IsInstance {
4844 return !spec.IsStatic;
4848 public override bool IsStatic {
4850 return spec.IsStatic;
4854 public FieldSpec Spec {
4860 public override Type DeclaringType {
4862 return spec.MetaInfo.DeclaringType;
4866 public override string GetSignatureForError ()
4868 return TypeManager.GetFullNameSignature (spec.MetaInfo);
4871 public VariableInfo VariableInfo {
4873 return variable_info;
4877 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, Location loc,
4878 SimpleName original)
4880 FieldInfo fi = TypeManager.GetGenericFieldDefinition (spec.MetaInfo);
4881 Type t = fi.FieldType;
4883 if (t.IsPointer && !ec.IsUnsafe) {
4884 UnsafeError (ec, loc);
4887 return base.ResolveMemberAccess (ec, left, loc, original);
4890 public void SetHasAddressTaken ()
4892 IVariableReference vr = InstanceExpression as IVariableReference;
4894 vr.SetHasAddressTaken ();
4897 public override Expression CreateExpressionTree (ResolveContext ec)
4899 Expression instance;
4900 if (InstanceExpression == null) {
4901 instance = new NullLiteral (loc);
4903 instance = InstanceExpression.CreateExpressionTree (ec);
4906 Arguments args = Arguments.CreateForExpressionTree (ec, null,
4908 CreateTypeOfExpression ());
4910 return CreateExpressionFactoryCall (ec, "Field", args);
4913 public Expression CreateTypeOfExpression ()
4915 return new TypeOfField (Import.CreateField (GetConstructedFieldInfo ()), loc);
4918 protected override Expression DoResolve (ResolveContext ec)
4920 return DoResolve (ec, false, false);
4923 Expression DoResolve (ResolveContext ec, bool lvalue_instance, bool out_access)
4926 if (InstanceExpression == null){
4928 // This can happen when referencing an instance field using
4929 // a fully qualified type expression: TypeName.InstanceField = xxx
4931 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4935 // Resolve the field's instance expression while flow analysis is turned
4936 // off: when accessing a field "a.b", we must check whether the field
4937 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4939 if (lvalue_instance) {
4940 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
4941 Expression right_side =
4942 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4944 if (InstanceExpression != EmptyExpression.Null)
4945 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
4948 if (InstanceExpression != EmptyExpression.Null) {
4949 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
4950 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
4955 if (InstanceExpression == null)
4958 using (ec.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
4959 InstanceExpression.CheckMarshalByRefAccess (ec);
4963 if (!ec.IsObsolete) {
4964 FieldBase f = TypeManager.GetField (spec.MetaInfo);
4966 f.CheckObsoleteness (loc);
4968 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (spec.MetaInfo);
4970 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (spec.MetaInfo), loc, ec.Report);
4974 var fb = spec as FixedFieldSpec;
4975 IVariableReference var = InstanceExpression as IVariableReference;
4978 IFixedExpression fe = InstanceExpression as IFixedExpression;
4979 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
4980 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4983 if (InstanceExpression.eclass != ExprClass.Variable) {
4984 ec.Report.SymbolRelatedToPreviousError (spec.MetaInfo);
4985 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4986 TypeManager.GetFullNameSignature (spec.MetaInfo));
4987 } else if (var != null && var.IsHoisted) {
4988 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
4991 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4994 eclass = ExprClass.Variable;
4996 // If the instance expression is a local variable or parameter.
4997 if (var == null || var.VariableInfo == null)
5000 VariableInfo vi = var.VariableInfo;
5001 if (!vi.IsFieldAssigned (ec, Name, loc))
5004 variable_info = vi.GetSubStruct (Name);
5008 static readonly int [] codes = {
5009 191, // instance, write access
5010 192, // instance, out access
5011 198, // static, write access
5012 199, // static, out access
5013 1648, // member of value instance, write access
5014 1649, // member of value instance, out access
5015 1650, // member of value static, write access
5016 1651 // member of value static, out access
5019 static readonly string [] msgs = {
5020 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
5021 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5022 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5023 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
5024 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
5025 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5026 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5027 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
5030 // The return value is always null. Returning a value simplifies calling code.
5031 Expression Report_AssignToReadonly (ResolveContext ec, Expression right_side)
5034 if (right_side == EmptyExpression.OutAccess.Instance || right_side == EmptyExpression.LValueMemberOutAccess)
5038 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
5040 ec.Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
5045 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5047 IVariableReference var = InstanceExpression as IVariableReference;
5048 if (var != null && var.VariableInfo != null)
5049 var.VariableInfo.SetFieldAssigned (ec, Name);
5051 bool lvalue_instance = !spec.IsStatic && TypeManager.IsValueType (spec.MetaInfo.DeclaringType);
5052 bool out_access = right_side == EmptyExpression.OutAccess.Instance || right_side == EmptyExpression.LValueMemberOutAccess;
5054 Expression e = DoResolve (ec, lvalue_instance, out_access);
5059 FieldBase fb = TypeManager.GetField (spec.MetaInfo);
5063 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess.Instance) &&
5064 (fb.ModFlags & Modifiers.VOLATILE) != 0) {
5065 ec.Report.Warning (420, 1, loc,
5066 "`{0}': A volatile field references will not be treated as volatile",
5067 fb.GetSignatureForError ());
5071 if (spec.IsReadOnly) {
5072 // InitOnly fields can only be assigned in constructors or initializers
5073 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
5074 return Report_AssignToReadonly (ec, right_side);
5076 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
5077 Type ctype = ec.CurrentType;
5079 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
5080 if (!TypeManager.IsEqual (ctype, DeclaringType))
5081 return Report_AssignToReadonly (ec, right_side);
5082 // static InitOnly fields cannot be assigned-to in an instance constructor
5083 if (IsStatic && !ec.IsStatic)
5084 return Report_AssignToReadonly (ec, right_side);
5085 // instance constructors can't modify InitOnly fields of other instances of the same type
5086 if (!IsStatic && !(InstanceExpression is This))
5087 return Report_AssignToReadonly (ec, right_side);
5091 if (right_side == EmptyExpression.OutAccess.Instance &&
5092 !IsStatic && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type)) {
5093 ec.Report.SymbolRelatedToPreviousError (DeclaringType);
5094 ec.Report.Warning (197, 1, loc,
5095 "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",
5096 GetSignatureForError ());
5099 eclass = ExprClass.Variable;
5103 bool is_marshal_by_ref ()
5105 return !IsStatic && TypeManager.IsStruct (Type) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type);
5108 public override void CheckMarshalByRefAccess (ResolveContext ec)
5110 if (is_marshal_by_ref () && !(InstanceExpression is This)) {
5111 ec.Report.SymbolRelatedToPreviousError (DeclaringType);
5112 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",
5113 GetSignatureForError ());
5117 public override int GetHashCode ()
5119 return spec.GetHashCode ();
5122 public bool IsFixed {
5125 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
5127 IVariableReference variable = InstanceExpression as IVariableReference;
5128 if (variable != null)
5129 return TypeManager.IsStruct (InstanceExpression.Type) && variable.IsFixed;
5131 IFixedExpression fe = InstanceExpression as IFixedExpression;
5132 return fe != null && fe.IsFixed;
5136 public bool IsHoisted {
5138 IVariableReference hv = InstanceExpression as IVariableReference;
5139 return hv != null && hv.IsHoisted;
5143 public override bool Equals (object obj)
5145 FieldExpr fe = obj as FieldExpr;
5149 if (spec.MetaInfo != fe.spec.MetaInfo)
5152 if (InstanceExpression == null || fe.InstanceExpression == null)
5155 return InstanceExpression.Equals (fe.InstanceExpression);
5158 public void Emit (EmitContext ec, bool leave_copy)
5160 ILGenerator ig = ec.ig;
5161 bool is_volatile = false;
5163 var f = TypeManager.GetField (spec.MetaInfo);
5165 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
5173 ig.Emit (OpCodes.Volatile);
5175 ig.Emit (OpCodes.Ldsfld, GetConstructedFieldInfo ());
5178 EmitInstance (ec, false);
5180 // Optimization for build-in types
5181 if (TypeManager.IsStruct (type) && TypeManager.IsEqual (type, ec.MemberContext.CurrentType) && TypeManager.IsEqual (InstanceExpression.Type, type)) {
5182 LoadFromPtr (ig, type);
5184 var ff = spec as FixedFieldSpec;
5186 ig.Emit (OpCodes.Ldflda, GetConstructedFieldInfo ());
5187 ig.Emit (OpCodes.Ldflda, ff.Element);
5190 ig.Emit (OpCodes.Volatile);
5192 ig.Emit (OpCodes.Ldfld, GetConstructedFieldInfo ());
5198 ec.ig.Emit (OpCodes.Dup);
5200 temp = new LocalTemporary (this.Type);
5206 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5208 //FieldAttributes fa = FieldInfo.Attributes;
5209 //bool is_static = (fa & FieldAttributes.Static) != 0;
5210 ILGenerator ig = ec.ig;
5212 prepared = prepare_for_load;
5213 EmitInstance (ec, prepared);
5217 ec.ig.Emit (OpCodes.Dup);
5219 temp = new LocalTemporary (this.Type);
5224 FieldBase f = TypeManager.GetField (spec.MetaInfo);
5226 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
5227 ig.Emit (OpCodes.Volatile);
5233 ig.Emit (OpCodes.Stsfld, GetConstructedFieldInfo ());
5235 ig.Emit (OpCodes.Stfld, GetConstructedFieldInfo ());
5244 public override void Emit (EmitContext ec)
5249 public override void EmitSideEffect (EmitContext ec)
5251 FieldBase f = TypeManager.GetField (spec.MetaInfo);
5252 bool is_volatile = f != null && (f.ModFlags & Modifiers.VOLATILE) != 0;
5254 if (is_volatile || is_marshal_by_ref ())
5255 base.EmitSideEffect (ec);
5258 public override void Error_VariableIsUsedBeforeItIsDeclared (Report r, string name)
5261 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the field `{1}'",
5262 name, GetSignatureForError ());
5265 public void AddressOf (EmitContext ec, AddressOp mode)
5267 ILGenerator ig = ec.ig;
5269 FieldBase f = TypeManager.GetField (spec.MetaInfo);
5271 if ((mode & AddressOp.Store) != 0)
5273 if ((mode & AddressOp.Load) != 0)
5278 // Handle initonly fields specially: make a copy and then
5279 // get the address of the copy.
5282 if (spec.IsReadOnly){
5284 if (ec.HasSet (EmitContext.Options.ConstructorScope)){
5297 local = ig.DeclareLocal (type);
5298 ig.Emit (OpCodes.Stloc, local);
5299 ig.Emit (OpCodes.Ldloca, local);
5305 ig.Emit (OpCodes.Ldsflda, GetConstructedFieldInfo ());
5308 EmitInstance (ec, false);
5309 ig.Emit (OpCodes.Ldflda, GetConstructedFieldInfo ());
5313 FieldInfo GetConstructedFieldInfo ()
5315 if (constructed_generic_type == null)
5316 return spec.MetaInfo;
5318 return TypeBuilder.GetField (constructed_generic_type, spec.MetaInfo);
5321 public SLE.Expression MakeAssignExpression (BuilderContext ctx)
5323 return MakeExpression (ctx);
5326 public override SLE.Expression MakeExpression (BuilderContext ctx)
5328 return SLE.Expression.Field (InstanceExpression.MakeExpression (ctx), spec.MetaInfo);
5331 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5333 storey.MutateField (spec);
5334 base.MutateHoistedGenericType (storey);
5340 /// Expression that evaluates to a Property. The Assign class
5341 /// might set the `Value' expression if we are in an assignment.
5343 /// This is not an LValue because we need to re-write the expression, we
5344 /// can not take data from the stack and store it.
5346 public class PropertyExpr : MemberExpr, IDynamicAssign
5349 MethodSpec getter, setter;
5352 TypeArguments targs;
5354 LocalTemporary temp;
5357 public PropertyExpr (Type container_type, PropertySpec spec, Location l)
5362 type = TypeManager.TypeToCoreType (spec.PropertyType);
5364 ResolveAccessors (container_type);
5367 public override string Name {
5373 public override bool IsInstance {
5379 public override bool IsStatic {
5385 public override Expression CreateExpressionTree (ResolveContext ec)
5388 if (IsSingleDimensionalArrayLength ()) {
5389 args = new Arguments (1);
5390 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5391 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
5395 Error_BaseAccessInExpressionTree (ec, loc);
5399 args = new Arguments (2);
5400 if (InstanceExpression == null)
5401 args.Add (new Argument (new NullLiteral (loc)));
5403 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5404 args.Add (new Argument (new TypeOfMethod (getter, loc)));
5405 return CreateExpressionFactoryCall (ec, "Property", args);
5408 public Expression CreateSetterTypeOfExpression ()
5410 return new TypeOfMethod (setter, loc);
5413 public override Type DeclaringType {
5415 return spec.DeclaringType;
5419 public override string GetSignatureForError ()
5421 return TypeManager.GetFullNameSignature (spec.MetaInfo);
5424 void FindAccessors (Type invocation_type)
5426 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
5427 BindingFlags.Static | BindingFlags.Instance |
5428 BindingFlags.DeclaredOnly;
5430 Type current = spec.DeclaringType;
5431 for (; current != null; current = current.BaseType) {
5432 MemberInfo[] group = TypeManager.MemberLookup (
5433 invocation_type, invocation_type, current,
5434 MemberTypes.Property, flags, spec.Name, null);
5439 if (group.Length != 1)
5440 // Oooops, can this ever happen ?
5443 PropertyInfo pi = (PropertyInfo) group [0];
5445 if (getter == null) {
5446 var m = pi.GetGetMethod (true);
5448 getter = Import.CreateMethod (m);
5451 if (setter == null) {
5452 var m = pi.GetSetMethod (true);
5454 setter = Import.CreateMethod (m);
5457 var accessor = getter != null ? getter : setter;
5459 if (!accessor.IsVirtual)
5465 // We also perform the permission checking here, as the PropertyInfo does not
5466 // hold the information for the accessibility of its setter/getter
5468 // TODO: Refactor to use some kind of cache together with GetPropertyFromAccessor
5469 void ResolveAccessors (Type container_type)
5471 FindAccessors (container_type);
5473 if (getter != null) {
5474 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
5475 IMethodData md = TypeManager.GetMethod (the_getter);
5479 is_static = getter.IsStatic;
5482 if (setter != null) {
5483 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
5484 IMethodData md = TypeManager.GetMethod (the_setter);
5488 is_static = setter.IsStatic;
5492 public SLE.Expression MakeAssignExpression (BuilderContext ctx)
5494 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) setter.MetaInfo);
5497 public override SLE.Expression MakeExpression (BuilderContext ctx)
5499 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) getter.MetaInfo);
5502 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5504 if (InstanceExpression != null)
5505 InstanceExpression.MutateHoistedGenericType (storey);
5507 type = storey.MutateType (type);
5509 storey.MutateGenericMethod (getter);
5511 storey.MutateGenericMethod (setter);
5514 public PropertyInfo PropertyInfo {
5516 return spec.MetaInfo;
5520 bool InstanceResolve (ResolveContext ec, bool lvalue_instance, bool must_do_cs1540_check)
5523 InstanceExpression = null;
5527 if (InstanceExpression == null) {
5528 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5532 InstanceExpression = InstanceExpression.Resolve (ec);
5533 if (lvalue_instance && InstanceExpression != null)
5534 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess);
5536 if (InstanceExpression == null)
5539 InstanceExpression.CheckMarshalByRefAccess (ec);
5541 if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) &&
5542 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.CurrentType) &&
5543 !TypeManager.IsNestedChildOf (ec.CurrentType, InstanceExpression.Type) &&
5544 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.CurrentType)) {
5545 ec.Report.SymbolRelatedToPreviousError (spec.MetaInfo);
5546 Error_CannotAccessProtected (ec, loc, spec.MetaInfo, InstanceExpression.Type, ec.CurrentType);
5553 void Error_PropertyNotFound (ResolveContext ec, MethodSpec mi, bool getter)
5555 // TODO: correctly we should compare arguments but it will lead to bigger changes
5556 if (mi.MetaInfo is MethodBuilder) {
5557 Error_TypeDoesNotContainDefinition (ec, loc, spec.DeclaringType, Name);
5561 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
5563 AParametersCollection iparams = mi.Parameters;
5564 sig.Append (getter ? "get_" : "set_");
5566 sig.Append (iparams.GetSignatureForError ());
5568 ec.Report.SymbolRelatedToPreviousError (mi.MetaInfo);
5569 ec.Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
5570 Name, sig.ToString ());
5573 public bool IsAccessibleFrom (Type invocation_type, bool lvalue)
5576 var accessor = lvalue ? setter : getter;
5577 if (accessor == null && lvalue)
5579 return accessor != null && IsAccessorAccessible (invocation_type, accessor, out dummy);
5582 bool IsSingleDimensionalArrayLength ()
5584 if (DeclaringType != TypeManager.array_type || getter == null || Name != "Length")
5587 string t_name = InstanceExpression.Type.Name;
5588 int t_name_len = t_name.Length;
5589 return t_name_len > 2 && t_name [t_name_len - 2] == '[';
5592 protected override Expression DoResolve (ResolveContext ec)
5594 eclass = ExprClass.PropertyAccess;
5596 bool must_do_cs1540_check = false;
5597 ec.Report.DisableReporting ();
5598 bool res = ResolveGetter (ec, ref must_do_cs1540_check);
5599 ec.Report.EnableReporting ();
5602 if (InstanceExpression != null) {
5603 Type expr_type = InstanceExpression.Type;
5604 ExtensionMethodGroupExpr ex_method_lookup = ec.LookupExtensionMethod (expr_type, Name, loc);
5605 if (ex_method_lookup != null) {
5606 ex_method_lookup.ExtensionExpression = InstanceExpression;
5607 ex_method_lookup.SetTypeArguments (ec, targs);
5608 return ex_method_lookup.Resolve (ec);
5612 ResolveGetter (ec, ref must_do_cs1540_check);
5616 if (!InstanceResolve (ec, false, must_do_cs1540_check))
5620 // Only base will allow this invocation to happen.
5622 if (IsBase && getter.IsAbstract) {
5623 Error_CannotCallAbstractBase (ec, TypeManager.GetFullNameSignature (spec.MetaInfo));
5626 if (spec.PropertyType.IsPointer && !ec.IsUnsafe){
5627 UnsafeError (ec, loc);
5630 if (!ec.IsObsolete) {
5631 PropertyBase pb = TypeManager.GetProperty (spec.MetaInfo);
5633 pb.CheckObsoleteness (loc);
5635 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (spec.MetaInfo);
5637 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
5644 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5646 eclass = ExprClass.PropertyAccess;
5648 if (right_side == EmptyExpression.OutAccess.Instance) {
5649 if (ec.CurrentBlock.Toplevel.GetParameterReference (spec.Name, loc) is MemberAccess) {
5650 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5653 right_side.DoResolveLValue (ec, this);
5658 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5659 Error_CannotModifyIntermediateExpressionValue (ec);
5662 if (setter == null){
5664 // The following condition happens if the PropertyExpr was
5665 // created, but is invalid (ie, the property is inaccessible),
5666 // and we did not want to embed the knowledge about this in
5667 // the caller routine. This only avoids double error reporting.
5672 if (ec.CurrentBlock.Toplevel.GetParameterReference (spec.Name, loc) is MemberAccess) {
5673 ec.Report.Error (1947, loc, "A range variable `{0}' cannot be assigned to. Consider using `let' clause to store the value",
5676 ec.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
5677 GetSignatureForError ());
5682 if (targs != null) {
5683 base.SetTypeArguments (ec, targs);
5687 if (setter.Parameters.Count != 1){
5688 Error_PropertyNotFound (ec, setter, false);
5692 bool must_do_cs1540_check;
5693 if (!IsAccessorAccessible (ec.CurrentType, setter, out must_do_cs1540_check)) {
5694 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter.MetaInfo) as PropertyBase.PropertyMethod;
5695 if (pm != null && pm.HasCustomAccessModifier) {
5696 ec.Report.SymbolRelatedToPreviousError (pm);
5697 ec.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5698 TypeManager.CSharpSignature (setter));
5701 ec.Report.SymbolRelatedToPreviousError (setter.MetaInfo);
5702 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter), ec.Report);
5707 if (!InstanceResolve (ec, TypeManager.IsStruct (spec.DeclaringType), must_do_cs1540_check))
5711 // Only base will allow this invocation to happen.
5713 if (IsBase && setter.IsAbstract){
5714 Error_CannotCallAbstractBase (ec, TypeManager.GetFullNameSignature (spec.MetaInfo));
5717 if (spec.PropertyType.IsPointer && !ec.IsUnsafe) {
5718 UnsafeError (ec, loc);
5721 if (!ec.IsObsolete) {
5722 PropertyBase pb = TypeManager.GetProperty (spec.MetaInfo);
5724 pb.CheckObsoleteness (loc);
5726 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (spec.MetaInfo);
5728 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
5735 public override void Emit (EmitContext ec)
5740 public void Emit (EmitContext ec, bool leave_copy)
5743 // Special case: length of single dimension array property is turned into ldlen
5745 if (IsSingleDimensionalArrayLength ()) {
5747 EmitInstance (ec, false);
5748 ec.ig.Emit (OpCodes.Ldlen);
5749 ec.ig.Emit (OpCodes.Conv_I4);
5753 Invocation.EmitCall (ec, IsBase, InstanceExpression, getter, null, loc, prepared, false);
5756 ec.ig.Emit (OpCodes.Dup);
5758 temp = new LocalTemporary (this.Type);
5765 // Implements the IAssignMethod interface for assignments
5767 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5769 Expression my_source = source;
5771 if (prepare_for_load) {
5776 ec.ig.Emit (OpCodes.Dup);
5778 temp = new LocalTemporary (this.Type);
5782 } else if (leave_copy) {
5784 temp = new LocalTemporary (this.Type);
5789 Arguments args = new Arguments (1);
5790 args.Add (new Argument (my_source));
5792 Invocation.EmitCall (ec, IsBase, InstanceExpression, setter, args, loc, false, prepared);
5800 bool ResolveGetter (ResolveContext ec, ref bool must_do_cs1540_check)
5802 if (targs != null) {
5803 base.SetTypeArguments (ec, targs);
5807 if (getter != null) {
5808 if (!getter.Parameters.IsEmpty) {
5809 Error_PropertyNotFound (ec, getter, true);
5814 if (getter == null) {
5816 // The following condition happens if the PropertyExpr was
5817 // created, but is invalid (ie, the property is inaccessible),
5818 // and we did not want to embed the knowledge about this in
5819 // the caller routine. This only avoids double error reporting.
5824 if (InstanceExpression != EmptyExpression.Null) {
5825 ec.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5826 TypeManager.GetFullNameSignature (spec.MetaInfo));
5831 if (getter != null &&
5832 !IsAccessorAccessible (ec.CurrentType, getter, out must_do_cs1540_check)) {
5833 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter.MetaInfo) as PropertyBase.PropertyMethod;
5834 if (pm != null && pm.HasCustomAccessModifier) {
5835 ec.Report.SymbolRelatedToPreviousError (pm);
5836 ec.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5837 TypeManager.CSharpSignature (getter.MetaInfo));
5839 ec.Report.SymbolRelatedToPreviousError (getter.MetaInfo);
5840 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter.MetaInfo), ec.Report);
5849 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5856 /// Fully resolved expression that evaluates to an Event
5858 public class EventExpr : MemberExpr
5860 readonly EventSpec spec;
5862 public EventExpr (EventSpec spec, Location loc)
5868 public override string Name {
5874 public override bool IsInstance {
5876 return !spec.IsStatic;
5880 public override bool IsStatic {
5882 return spec.IsStatic;
5886 public override Type DeclaringType {
5888 return spec.DeclaringType;
5892 public void Error_AssignmentEventOnly (ResolveContext ec)
5894 ec.Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5895 GetSignatureForError ());
5898 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, Location loc,
5899 SimpleName original)
5902 // If the event is local to this class, we transform ourselves into a FieldExpr
5905 if (spec.DeclaringType == ec.CurrentType ||
5906 TypeManager.IsNestedChildOf(ec.CurrentType, spec.DeclaringType)) {
5908 // TODO: Breaks dynamic binder as currect context fields are imported and not compiled
5909 EventField mi = TypeManager.GetEventField (spec.MetaInfo).MemberDefinition as EventField;
5911 if (mi != null && mi.HasBackingField) {
5914 mi.CheckObsoleteness (loc);
5916 if ((mi.ModFlags & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0 && !ec.HasSet (ResolveContext.Options.CompoundAssignmentScope))
5917 Error_AssignmentEventOnly (ec);
5919 FieldExpr ml = new FieldExpr (mi.BackingField, loc);
5921 InstanceExpression = null;
5923 return ml.ResolveMemberAccess (ec, left, loc, original);
5927 if (left is This && !ec.HasSet (ResolveContext.Options.CompoundAssignmentScope))
5928 Error_AssignmentEventOnly (ec);
5930 return base.ResolveMemberAccess (ec, left, loc, original);
5933 bool InstanceResolve (ResolveContext ec, bool must_do_cs1540_check)
5936 InstanceExpression = null;
5940 if (InstanceExpression == null) {
5941 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5945 InstanceExpression = InstanceExpression.Resolve (ec);
5946 if (InstanceExpression == null)
5949 if (IsBase && spec.IsAbstract) {
5950 Error_CannotCallAbstractBase (ec, TypeManager.CSharpSignature(spec.MetaInfo));
5955 // This is using the same mechanism as the CS1540 check in PropertyExpr.
5956 // However, in the Event case, we reported a CS0122 instead.
5958 // TODO: Exact copy from PropertyExpr
5960 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
5961 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.CurrentType) &&
5962 !TypeManager.IsNestedChildOf (ec.CurrentType, InstanceExpression.Type) &&
5963 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.CurrentType)) {
5964 ec.Report.SymbolRelatedToPreviousError (spec.MetaInfo);
5965 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (spec.MetaInfo), ec.Report);
5972 public bool IsAccessibleFrom (Type invocation_type)
5975 return IsAccessorAccessible (invocation_type, spec.AccessorAdd, out dummy) &&
5976 IsAccessorAccessible (invocation_type, spec.AccessorRemove, out dummy);
5979 public override Expression CreateExpressionTree (ResolveContext ec)
5981 throw new NotSupportedException ("ET");
5984 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5986 // contexts where an LValue is valid have already devolved to FieldExprs
5987 Error_CannotAssign (ec);
5991 protected override Expression DoResolve (ResolveContext ec)
5993 eclass = ExprClass.EventAccess;
5995 bool must_do_cs1540_check;
5996 if (!(IsAccessorAccessible (ec.CurrentType, spec.AccessorAdd, out must_do_cs1540_check) &&
5997 IsAccessorAccessible (ec.CurrentType, spec.AccessorRemove, out must_do_cs1540_check))) {
5998 ec.Report.SymbolRelatedToPreviousError (spec.MetaInfo);
5999 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (spec.MetaInfo), ec.Report);
6003 if (!InstanceResolve (ec, must_do_cs1540_check))
6006 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6007 Error_CannotAssign (ec);
6011 if (!ec.IsObsolete) {
6012 var oa = spec.GetObsoleteAttribute ();
6014 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
6017 spec.MemberDefinition.SetIsUsed ();
6018 type = spec.EventType;
6023 public override void Emit (EmitContext ec)
6025 throw new NotSupportedException ();
6026 //Error_CannotAssign ();
6029 public void Error_CannotAssign (ResolveContext ec)
6031 ec.Report.Error (70, loc,
6032 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
6033 GetSignatureForError (), TypeManager.CSharpName (spec.DeclaringType));
6036 public override string GetSignatureForError ()
6038 return TypeManager.CSharpSignature (spec.MetaInfo);
6041 public void EmitAddOrRemove (EmitContext ec, bool is_add, Expression source)
6043 Arguments args = new Arguments (1);
6044 args.Add (new Argument (source));
6045 Invocation.EmitCall (ec, IsBase, InstanceExpression,
6046 is_add ? spec.AccessorAdd : spec.AccessorRemove,
6051 public class TemporaryVariable : VariableReference
6055 public TemporaryVariable (Type type, Location loc)
6061 public override Expression CreateExpressionTree (ResolveContext ec)
6063 throw new NotSupportedException ("ET");
6066 protected override Expression DoResolve (ResolveContext ec)
6068 eclass = ExprClass.Variable;
6070 TypeExpr te = new TypeExpression (type, loc);
6071 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
6072 if (!li.Resolve (ec))
6076 // Don't capture temporary variables except when using
6077 // iterator redirection
6079 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.IsIterator && ec.IsVariableCapturingRequired) {
6080 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
6081 storey.CaptureLocalVariable (ec, li);
6087 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6089 return Resolve (ec);
6092 public override void Emit (EmitContext ec)
6097 public void EmitAssign (EmitContext ec, Expression source)
6099 EmitAssign (ec, source, false, false);
6102 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6104 return li.HoistedVariant;
6107 public override bool IsFixed {
6108 get { return true; }
6111 public override bool IsRef {
6112 get { return false; }
6115 public override string Name {
6116 get { throw new NotImplementedException (); }
6119 public override void SetHasAddressTaken ()
6121 throw new NotImplementedException ();
6124 protected override ILocalVariable Variable {
6128 public override VariableInfo VariableInfo {
6129 get { throw new NotImplementedException (); }
6134 /// Handles `var' contextual keyword; var becomes a keyword only
6135 /// if no type called var exists in a variable scope
6137 class VarExpr : SimpleName
6139 // Used for error reporting only
6140 int initializers_count;
6142 public VarExpr (Location loc)
6145 initializers_count = 1;
6148 public int VariableInitializersCount {
6150 this.initializers_count = value;
6154 public bool InferType (ResolveContext ec, Expression right_side)
6157 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
6159 type = right_side.Type;
6160 if (type == TypeManager.null_type || type == TypeManager.void_type || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
6161 ec.Report.Error (815, loc, "An implicitly typed local variable declaration cannot be initialized with `{0}'",
6162 right_side.GetSignatureForError ());
6166 eclass = ExprClass.Variable;
6170 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
6172 if (RootContext.Version < LanguageVersion.V_3)
6173 base.Error_TypeOrNamespaceNotFound (ec);
6175 ec.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");
6178 public override TypeExpr ResolveAsContextualType (IMemberContext rc, bool silent)
6180 TypeExpr te = base.ResolveAsContextualType (rc, true);
6184 if (RootContext.Version < LanguageVersion.V_3)
6185 rc.Compiler.Report.FeatureIsNotAvailable (loc, "implicitly typed local variable");
6187 if (initializers_count == 1)
6190 if (initializers_count > 1) {
6191 rc.Compiler.Report.Error (819, loc, "An implicitly typed local variable declaration cannot include multiple declarators");
6192 initializers_count = 1;
6196 if (initializers_count == 0) {
6197 initializers_count = 1;
6198 rc.Compiler.Report.Error (818, loc, "An implicitly typed local variable declarator must include an initializer");