2 // ecore.cs: Core of the Expression representation for the intermediate tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@seznam.cz)
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
13 namespace Mono.CSharp {
15 using System.Collections;
16 using System.Diagnostics;
17 using System.Reflection;
18 using System.Reflection.Emit;
22 /// The ExprClass class contains the is used to pass the
23 /// classification of an expression (value, variable, namespace,
24 /// type, method group, property access, event access, indexer access,
27 public enum ExprClass : byte {
42 /// This is used to tell Resolve in which types of expressions we're
46 public enum ResolveFlags {
47 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
50 // Returns a type expression.
53 // Returns a method group.
56 // Mask of all the expression class flags.
59 // Disable control flow analysis while resolving the expression.
60 // This is used when resolving the instance expression of a field expression.
61 DisableFlowAnalysis = 8,
63 // Set if this is resolving the first part of a MemberAccess.
66 // Disable control flow analysis _of struct_ while resolving the expression.
67 // This is used when resolving the instance expression of a field expression.
68 DisableStructFlowAnalysis = 32,
73 // This is just as a hint to AddressOf of what will be done with the
76 public enum AddressOp {
83 /// This interface is implemented by variables
85 public interface IMemoryLocation {
87 /// The AddressOf method should generate code that loads
88 /// the address of the object and leaves it on the stack.
90 /// The `mode' argument is used to notify the expression
91 /// of whether this will be used to read from the address or
92 /// write to the address.
94 /// This is just a hint that can be used to provide good error
95 /// reporting, and should have no other side effects.
97 void AddressOf (EmitContext ec, AddressOp mode);
100 // TODO: Rename to something meaningful, this is flow-analysis interface only
101 public interface IVariable {
102 VariableInfo VariableInfo { get; }
103 bool IsFixed { get; }
107 /// Base class for expressions
109 public abstract class Expression {
110 public ExprClass eclass;
112 protected Location loc;
116 set { type = value; }
119 public virtual Location Location {
124 /// Utility wrapper routine for Error, just to beautify the code
126 public void Error (int error, string s)
128 Report.Error (error, loc, s);
131 // Not nice but we have broken hierarchy.
132 public virtual void CheckMarshalByRefAccess (EmitContext ec)
136 public virtual bool GetAttributableValue (Type value_type, out object value)
138 Attribute.Error_AttributeArgumentNotValid (loc);
143 public virtual string GetSignatureForError ()
145 return TypeManager.CSharpName (type);
148 public static bool IsAccessorAccessible (Type invocation_type, MethodInfo mi, out bool must_do_cs1540_check)
150 MethodAttributes ma = mi.Attributes & MethodAttributes.MemberAccessMask;
152 must_do_cs1540_check = false; // by default we do not check for this
154 if (ma == MethodAttributes.Public)
158 // If only accessible to the current class or children
160 if (ma == MethodAttributes.Private)
161 return TypeManager.IsPrivateAccessible (invocation_type, mi.DeclaringType) ||
162 TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType);
164 if (TypeManager.IsThisOrFriendAssembly (mi.DeclaringType.Assembly)) {
165 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamORAssem)
168 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamANDAssem)
172 // Family and FamANDAssem require that we derive.
173 // FamORAssem requires that we derive if in different assemblies.
174 if (!TypeManager.IsNestedFamilyAccessible (invocation_type, mi.DeclaringType))
177 if (!TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType))
178 must_do_cs1540_check = true;
183 public virtual bool IsNull {
190 /// Performs semantic analysis on the Expression
194 /// The Resolve method is invoked to perform the semantic analysis
197 /// The return value is an expression (it can be the
198 /// same expression in some cases) or a new
199 /// expression that better represents this node.
201 /// For example, optimizations of Unary (LiteralInt)
202 /// would return a new LiteralInt with a negated
205 /// If there is an error during semantic analysis,
206 /// then an error should be reported (using Report)
207 /// and a null value should be returned.
209 /// There are two side effects expected from calling
210 /// Resolve(): the the field variable "eclass" should
211 /// be set to any value of the enumeration
212 /// `ExprClass' and the type variable should be set
213 /// to a valid type (this is the type of the
216 public abstract Expression DoResolve (EmitContext ec);
218 public virtual Expression DoResolveLValue (EmitContext ec, Expression right_side)
224 // This is used if the expression should be resolved as a type or namespace name.
225 // the default implementation fails.
227 public virtual FullNamedExpression ResolveAsTypeStep (IResolveContext rc, bool silent)
231 EmitContext ec = rc as EmitContext;
235 e.Error_UnexpectedKind (ResolveFlags.Type, loc);
241 // C# 3.0 introduced contextual keywords (var) which behaves like a type if type with
242 // same name exists or as a keyword when no type was found
244 public virtual TypeExpr ResolveAsContextualType (IResolveContext rc, bool silent)
246 return ResolveAsTypeTerminal (rc, silent);
250 // This is used to resolve the expression as a type, a null
251 // value will be returned if the expression is not a type
254 public virtual TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
256 TypeExpr te = ResolveAsBaseTerminal (ec, silent);
260 if (!silent) { // && !(te is TypeParameterExpr)) {
261 ObsoleteAttribute obsolete_attr = AttributeTester.GetObsoleteAttribute (te.Type);
262 if (obsolete_attr != null && !ec.IsInObsoleteScope) {
263 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location);
267 // Constrains don't need to be checked for overrides
268 GenericMethod gm = ec.GenericDeclContainer as GenericMethod;
269 if (gm != null && (gm.ModFlags & Modifiers.OVERRIDE) != 0) {
274 ConstructedType ct = te as ConstructedType;
275 if ((ct != null) && !ct.CheckConstraints (ec))
281 public TypeExpr ResolveAsBaseTerminal (IResolveContext ec, bool silent)
283 int errors = Report.Errors;
285 FullNamedExpression fne = ResolveAsTypeStep (ec, silent);
290 if (fne.eclass != ExprClass.Type) {
291 if (!silent && errors == Report.Errors)
292 fne.Error_UnexpectedKind (null, "type", loc);
296 TypeExpr te = fne as TypeExpr;
298 if (!te.CheckAccessLevel (ec.DeclContainer)) {
299 Report.SymbolRelatedToPreviousError (te.Type);
300 ErrorIsInaccesible (loc, TypeManager.CSharpName (te.Type));
308 public static void ErrorIsInaccesible (Location loc, string name)
310 Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", name);
313 protected static void Error_CannotAccessProtected (Location loc, MemberInfo m, Type qualifier, Type container)
315 Report.Error (1540, loc, "Cannot access protected member `{0}' via a qualifier of type `{1}'."
316 + " The qualifier must be of type `{2}' or derived from it",
317 TypeManager.GetFullNameSignature (m),
318 TypeManager.CSharpName (qualifier),
319 TypeManager.CSharpName (container));
323 public static void Error_InvalidExpressionStatement (Location loc)
325 Report.Error (201, loc, "Only assignment, call, increment, decrement, and new object " +
326 "expressions can be used as a statement");
329 public void Error_InvalidExpressionStatement ()
331 Error_InvalidExpressionStatement (loc);
334 protected void Error_CannotAssign (string to, string roContext)
336 Report.Error (1656, loc, "Cannot assign to `{0}' because it is a `{1}'",
340 public static void Error_VoidInvalidInTheContext (Location loc)
342 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
345 public virtual void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl)
347 // The error was already reported as CS1660
348 if (type == TypeManager.anonymous_method_type)
351 if (TypeManager.IsGenericParameter (Type) && TypeManager.IsGenericParameter (target) && type.Name == target.Name) {
353 string sig1 = type.DeclaringMethod == null ?
354 TypeManager.CSharpName (type.DeclaringType) :
355 TypeManager.CSharpSignature (type.DeclaringMethod);
356 string sig2 = target.DeclaringMethod == null ?
357 TypeManager.CSharpName (target.DeclaringType) :
358 TypeManager.CSharpSignature (target.DeclaringMethod);
359 Report.ExtraInformation (loc,
361 "The generic parameter `{0}' of `{1}' cannot be converted to the generic parameter `{0}' of `{2}' (in the previous ",
362 Type.Name, sig1, sig2));
364 } else if (Type.FullName == target.FullName){
365 Report.ExtraInformation (loc,
367 "The type `{0}' has two conflicting definitions, one comes from `{1}' and the other from `{2}' (in the previous ",
368 Type.FullName, Type.Assembly.FullName, target.Assembly.FullName));
372 Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
373 TypeManager.CSharpName (type), TypeManager.CSharpName (target));
377 Expression e = (this is EnumConstant) ? ((EnumConstant)this).Child : this;
378 bool b = Convert.ExplicitNumericConversion (e, target) != null;
381 Convert.ExplicitReferenceConversionExists (Type, target) ||
382 Convert.ExplicitUnsafe (e, target) != null ||
383 (ec != null && Convert.ExplicitUserConversion (ec, this, target, Location.Null) != null))
385 Report.Error (266, loc, "Cannot implicitly convert type `{0}' to `{1}'. " +
386 "An explicit conversion exists (are you missing a cast?)",
387 TypeManager.CSharpName (Type), TypeManager.CSharpName (target));
391 Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
392 TypeManager.CSharpName (type),
393 TypeManager.CSharpName (target));
396 protected void Error_VariableIsUsedBeforeItIsDeclared (string name)
398 Report.Error (841, loc, "The variable `{0}' cannot be used before it is declared",
402 protected virtual void Error_TypeDoesNotContainDefinition (Type type, string name)
404 Error_TypeDoesNotContainDefinition (loc, type, name);
407 public static void Error_TypeDoesNotContainDefinition (Location loc, Type type, string name)
409 Report.SymbolRelatedToPreviousError (type);
410 Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
411 TypeManager.CSharpName (type), name);
414 protected static void Error_ValueAssignment (Location loc)
416 Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
419 ResolveFlags ExprClassToResolveFlags
424 case ExprClass.Namespace:
425 return ResolveFlags.Type;
427 case ExprClass.MethodGroup:
428 return ResolveFlags.MethodGroup;
430 case ExprClass.Value:
431 case ExprClass.Variable:
432 case ExprClass.PropertyAccess:
433 case ExprClass.EventAccess:
434 case ExprClass.IndexerAccess:
435 return ResolveFlags.VariableOrValue;
438 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
444 /// Resolves an expression and performs semantic analysis on it.
448 /// Currently Resolve wraps DoResolve to perform sanity
449 /// checking and assertion checking on what we expect from Resolve.
451 public Expression Resolve (EmitContext ec, ResolveFlags flags)
453 if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type)
454 return ResolveAsTypeStep (ec, false);
456 bool do_flow_analysis = ec.DoFlowAnalysis;
457 bool omit_struct_analysis = ec.OmitStructFlowAnalysis;
458 if ((flags & ResolveFlags.DisableFlowAnalysis) != 0)
459 do_flow_analysis = false;
460 if ((flags & ResolveFlags.DisableStructFlowAnalysis) != 0)
461 omit_struct_analysis = true;
464 using (ec.WithFlowAnalysis (do_flow_analysis, omit_struct_analysis)) {
465 if (this is SimpleName) {
466 bool intermediate = (flags & ResolveFlags.Intermediate) == ResolveFlags.Intermediate;
467 e = ((SimpleName) this).DoResolve (ec, intermediate);
476 if ((flags & e.ExprClassToResolveFlags) == 0) {
477 e.Error_UnexpectedKind (flags, loc);
481 if (e.type == null && !(e is Namespace)) {
482 throw new Exception (
483 "Expression " + e.GetType () +
484 " did not set its type after Resolve\n" +
485 "called from: " + this.GetType ());
492 /// Resolves an expression and performs semantic analysis on it.
494 public Expression Resolve (EmitContext ec)
496 Expression e = Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
498 if (e != null && e.eclass == ExprClass.MethodGroup && RootContext.Version == LanguageVersion.ISO_1) {
499 ((MethodGroupExpr) e).ReportUsageError ();
505 public Constant ResolveAsConstant (EmitContext ec, MemberCore mc)
507 Expression e = Resolve (ec);
511 Constant c = e as Constant;
515 Const.Error_ExpressionMustBeConstant (loc, mc.GetSignatureForError ());
520 /// Resolves an expression for LValue assignment
524 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
525 /// checking and assertion checking on what we expect from Resolve
527 public Expression ResolveLValue (EmitContext ec, Expression right_side, Location loc)
529 int errors = Report.Errors;
530 bool out_access = right_side == EmptyExpression.OutAccess;
532 Expression e = DoResolveLValue (ec, right_side);
534 if (e != null && out_access && !(e is IMemoryLocation)) {
535 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
536 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
538 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
539 // e.GetType () + " " + e.GetSignatureForError ());
544 if (errors == Report.Errors) {
546 Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
548 Error_ValueAssignment (loc);
553 if (e.eclass == ExprClass.Invalid)
554 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
556 if (e.eclass == ExprClass.MethodGroup) {
557 ((MethodGroupExpr) e).ReportUsageError ();
561 if ((e.type == null) && !(e is ConstructedType))
562 throw new Exception ("Expression " + e + " did not set its type after Resolve");
568 /// Emits the code for the expression
572 /// The Emit method is invoked to generate the code
573 /// for the expression.
575 public abstract void Emit (EmitContext ec);
577 // Emit code to branch to @target if this expression is equivalent to @on_true.
578 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
579 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
580 // including the use of conditional branches. Note also that a branch MUST be emitted
581 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
584 ec.ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
587 // Emit this expression for its side effects, not for its value.
588 // The default implementation is to emit the value, and then throw it away.
589 // Subclasses can provide more efficient implementations, but those MUST be equivalent
590 public virtual void EmitSideEffect (EmitContext ec)
593 ec.ig.Emit (OpCodes.Pop);
597 /// Protected constructor. Only derivate types should
598 /// be able to be created
601 protected Expression ()
603 eclass = ExprClass.Invalid;
608 /// Returns a fully formed expression after a MemberLookup
611 public static Expression ExprClassFromMemberInfo (Type container_type, MemberInfo mi, Location loc)
614 return new EventExpr ((EventInfo) mi, loc);
615 else if (mi is FieldInfo) {
616 FieldInfo fi = (FieldInfo) mi;
617 if (fi.IsLiteral || (fi.IsInitOnly && fi.FieldType == TypeManager.decimal_type))
618 return new ConstantExpr (fi, loc);
619 return new FieldExpr (fi, loc);
620 } else if (mi is PropertyInfo)
621 return new PropertyExpr (container_type, (PropertyInfo) mi, loc);
622 else if (mi is Type) {
623 return new TypeExpression ((System.Type) mi, loc);
629 protected static ArrayList almost_matched_members = new ArrayList (4);
632 // FIXME: Probably implement a cache for (t,name,current_access_set)?
634 // This code could use some optimizations, but we need to do some
635 // measurements. For example, we could use a delegate to `flag' when
636 // something can not any longer be a method-group (because it is something
640 // If the return value is an Array, then it is an array of
643 // If the return value is an MemberInfo, it is anything, but a Method
647 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
648 // the arguments here and have MemberLookup return only the methods that
649 // match the argument count/type, unlike we are doing now (we delay this
652 // This is so we can catch correctly attempts to invoke instance methods
653 // from a static body (scan for error 120 in ResolveSimpleName).
656 // FIXME: Potential optimization, have a static ArrayList
659 public static Expression MemberLookup (Type container_type, Type queried_type, string name,
660 MemberTypes mt, BindingFlags bf, Location loc)
662 return MemberLookup (container_type, null, queried_type, name, mt, bf, loc);
666 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
667 // `qualifier_type' or null to lookup members in the current class.
670 public static Expression MemberLookup (Type container_type,
671 Type qualifier_type, Type queried_type,
672 string name, MemberTypes mt,
673 BindingFlags bf, Location loc)
675 almost_matched_members.Clear ();
677 MemberInfo [] mi = TypeManager.MemberLookup (container_type, qualifier_type,
678 queried_type, mt, bf, name, almost_matched_members);
684 bool is_interface = qualifier_type != null && qualifier_type.IsInterface;
685 ArrayList methods = new ArrayList (2);
686 ArrayList non_methods = null;
688 foreach (MemberInfo m in mi) {
689 if (m is MethodBase) {
694 if (non_methods == null) {
695 non_methods = new ArrayList (2);
700 foreach (MemberInfo n_m in non_methods) {
701 if (m.DeclaringType.IsInterface && TypeManager.ImplementsInterface (m.DeclaringType, n_m.DeclaringType))
704 Report.SymbolRelatedToPreviousError (m);
705 Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
706 TypeManager.GetFullNameSignature (m), TypeManager.GetFullNameSignature (n_m));
711 if (methods.Count == 0)
712 return ExprClassFromMemberInfo (container_type, (MemberInfo)non_methods [0], loc);
714 if (non_methods != null) {
715 MethodBase method = (MethodBase) methods [0];
716 MemberInfo non_method = (MemberInfo) non_methods [0];
717 if (method.DeclaringType == non_method.DeclaringType) {
718 // Cannot happen with C# code, but is valid in IL
719 Report.SymbolRelatedToPreviousError (method);
720 Report.SymbolRelatedToPreviousError (non_method);
721 Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
722 TypeManager.GetFullNameSignature (non_method),
723 TypeManager.CSharpSignature (method));
728 Report.SymbolRelatedToPreviousError (method);
729 Report.SymbolRelatedToPreviousError (non_method);
730 Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and non-method `{1}'. Using method `{0}'",
731 TypeManager.CSharpSignature (method), TypeManager.GetFullNameSignature (non_method));
735 return new MethodGroupExpr (methods, queried_type, loc);
738 if (mi [0] is MethodBase)
739 return new MethodGroupExpr (mi, queried_type, loc);
741 return ExprClassFromMemberInfo (container_type, mi [0], loc);
744 public const MemberTypes AllMemberTypes =
745 MemberTypes.Constructor |
749 MemberTypes.NestedType |
750 MemberTypes.Property;
752 public const BindingFlags AllBindingFlags =
753 BindingFlags.Public |
754 BindingFlags.Static |
755 BindingFlags.Instance;
757 public static Expression MemberLookup (Type container_type, Type queried_type,
758 string name, Location loc)
760 return MemberLookup (container_type, null, queried_type, name,
761 AllMemberTypes, AllBindingFlags, loc);
764 public static Expression MemberLookup (Type container_type, Type qualifier_type,
765 Type queried_type, string name, Location loc)
767 return MemberLookup (container_type, qualifier_type, queried_type,
768 name, AllMemberTypes, AllBindingFlags, loc);
771 public static MethodGroupExpr MethodLookup (Type container_type, Type queried_type,
772 string name, Location loc)
774 return (MethodGroupExpr)MemberLookup (container_type, null, queried_type, name,
775 MemberTypes.Method, AllBindingFlags, loc);
779 /// This is a wrapper for MemberLookup that is not used to "probe", but
780 /// to find a final definition. If the final definition is not found, we
781 /// look for private members and display a useful debugging message if we
784 protected Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
785 Type queried_type, string name,
786 MemberTypes mt, BindingFlags bf,
791 int errors = Report.Errors;
793 e = MemberLookup (ec.ContainerType, qualifier_type, queried_type, name, mt, bf, loc);
795 if (e != null || errors != Report.Errors)
798 // No errors were reported by MemberLookup, but there was an error.
799 return Error_MemberLookupFailed (ec.ContainerType, qualifier_type, queried_type,
803 protected virtual Expression Error_MemberLookupFailed (Type container_type, Type qualifier_type,
804 Type queried_type, string name, string class_name,
805 MemberTypes mt, BindingFlags bf)
807 if (almost_matched_members.Count != 0) {
808 for (int i = 0; i < almost_matched_members.Count; ++i) {
809 MemberInfo m = (MemberInfo) almost_matched_members [i];
810 for (int j = 0; j < i; ++j) {
811 if (m == almost_matched_members [j]) {
819 Type declaring_type = m.DeclaringType;
821 Report.SymbolRelatedToPreviousError (m);
822 if (qualifier_type == null) {
823 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
824 TypeManager.CSharpName (m.DeclaringType),
825 TypeManager.CSharpName (container_type));
827 } else if (qualifier_type != container_type &&
828 TypeManager.IsNestedFamilyAccessible (container_type, declaring_type)) {
829 // Although a derived class can access protected members of
830 // its base class it cannot do so through an instance of the
831 // base class (CS1540). If the qualifier_type is a base of the
832 // ec.ContainerType and the lookup succeeds with the latter one,
833 // then we are in this situation.
834 Error_CannotAccessProtected (loc, m, qualifier_type, container_type);
836 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (m));
839 almost_matched_members.Clear ();
843 MemberInfo[] lookup = null;
844 if (queried_type == null) {
845 class_name = "global::";
847 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
848 mt, (bf & ~BindingFlags.Public) | BindingFlags.NonPublic,
851 if (lookup != null) {
852 Report.SymbolRelatedToPreviousError (lookup [0]);
853 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (lookup [0]));
854 return Error_MemberLookupFailed (lookup);
857 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
858 AllMemberTypes, AllBindingFlags | BindingFlags.NonPublic,
862 if (lookup == null) {
863 if (class_name != null) {
864 Report.Error (103, loc, "The name `{0}' does not exist in the current context",
867 Error_TypeDoesNotContainDefinition (queried_type, name);
872 if (TypeManager.MemberLookup (queried_type, null, queried_type,
873 AllMemberTypes, AllBindingFlags |
874 BindingFlags.NonPublic, name, null) == null) {
875 if ((lookup.Length == 1) && (lookup [0] is Type)) {
876 Type t = (Type) lookup [0];
878 Report.Error (305, loc,
879 "Using the generic type `{0}' " +
880 "requires {1} type arguments",
881 TypeManager.CSharpName (t),
882 TypeManager.GetNumberOfTypeArguments (t).ToString ());
887 return Error_MemberLookupFailed (lookup);
890 protected virtual Expression Error_MemberLookupFailed (MemberInfo[] members)
892 for (int i = 0; i < members.Length; ++i) {
893 if (!(members [i] is MethodBase))
897 // By default propagate the closest candidates upwards
898 return new MethodGroupExpr (members, type, loc);
901 protected virtual void Error_NegativeArrayIndex (Location loc)
903 throw new NotImplementedException ();
906 protected void Error_PointerInsideExpressionTree ()
908 Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
912 /// Returns an expression that can be used to invoke operator true
913 /// on the expression if it exists.
915 static public Expression GetOperatorTrue (EmitContext ec, Expression e, Location loc)
917 return GetOperatorTrueOrFalse (ec, e, true, loc);
921 /// Returns an expression that can be used to invoke operator false
922 /// on the expression if it exists.
924 static public Expression GetOperatorFalse (EmitContext ec, Expression e, Location loc)
926 return GetOperatorTrueOrFalse (ec, e, false, loc);
929 static Expression GetOperatorTrueOrFalse (EmitContext ec, Expression e, bool is_true, Location loc)
931 MethodGroupExpr operator_group;
932 string mname = Operator.GetMetadataName (is_true ? Operator.OpType.True : Operator.OpType.False);
933 operator_group = MethodLookup (ec.ContainerType, e.Type, mname, loc) as MethodGroupExpr;
934 if (operator_group == null)
937 ArrayList arguments = new ArrayList (1);
938 arguments.Add (new Argument (e, Argument.AType.Expression));
939 operator_group = operator_group.OverloadResolve (
940 ec, ref arguments, false, loc);
942 if (operator_group == null)
945 return new UserOperatorCall (operator_group, arguments, null, loc);
949 /// Resolves the expression `e' into a boolean expression: either through
950 /// an implicit conversion, or through an `operator true' invocation
952 public static Expression ResolveBoolean (EmitContext ec, Expression e, Location loc)
958 if (e.Type == TypeManager.bool_type)
961 Expression converted = Convert.ImplicitConversion (ec, e, TypeManager.bool_type, Location.Null);
963 if (converted != null)
967 // If no implicit conversion to bool exists, try using `operator true'
969 converted = Expression.GetOperatorTrue (ec, e, loc);
970 if (converted == null){
971 e.Error_ValueCannotBeConverted (ec, loc, TypeManager.bool_type, false);
977 public virtual string ExprClassName
981 case ExprClass.Invalid:
983 case ExprClass.Value:
985 case ExprClass.Variable:
987 case ExprClass.Namespace:
991 case ExprClass.MethodGroup:
992 return "method group";
993 case ExprClass.PropertyAccess:
994 return "property access";
995 case ExprClass.EventAccess:
996 return "event access";
997 case ExprClass.IndexerAccess:
998 return "indexer access";
999 case ExprClass.Nothing:
1002 throw new Exception ("Should not happen");
1007 /// Reports that we were expecting `expr' to be of class `expected'
1009 public void Error_UnexpectedKind (DeclSpace ds, string expected, Location loc)
1011 Error_UnexpectedKind (ds, expected, ExprClassName, loc);
1014 public void Error_UnexpectedKind (DeclSpace ds, string expected, string was, Location loc)
1016 string name = GetSignatureForError ();
1018 name = ds.GetSignatureForError () + '.' + name;
1020 Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
1021 name, was, expected);
1024 public void Error_UnexpectedKind (ResolveFlags flags, Location loc)
1026 string [] valid = new string [4];
1029 if ((flags & ResolveFlags.VariableOrValue) != 0) {
1030 valid [count++] = "variable";
1031 valid [count++] = "value";
1034 if ((flags & ResolveFlags.Type) != 0)
1035 valid [count++] = "type";
1037 if ((flags & ResolveFlags.MethodGroup) != 0)
1038 valid [count++] = "method group";
1041 valid [count++] = "unknown";
1043 StringBuilder sb = new StringBuilder (valid [0]);
1044 for (int i = 1; i < count - 1; i++) {
1046 sb.Append (valid [i]);
1049 sb.Append ("' or `");
1050 sb.Append (valid [count - 1]);
1053 Report.Error (119, loc,
1054 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1057 public static void UnsafeError (Location loc)
1059 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1063 // Load the object from the pointer.
1065 public static void LoadFromPtr (ILGenerator ig, Type t)
1067 if (t == TypeManager.int32_type)
1068 ig.Emit (OpCodes.Ldind_I4);
1069 else if (t == TypeManager.uint32_type)
1070 ig.Emit (OpCodes.Ldind_U4);
1071 else if (t == TypeManager.short_type)
1072 ig.Emit (OpCodes.Ldind_I2);
1073 else if (t == TypeManager.ushort_type)
1074 ig.Emit (OpCodes.Ldind_U2);
1075 else if (t == TypeManager.char_type)
1076 ig.Emit (OpCodes.Ldind_U2);
1077 else if (t == TypeManager.byte_type)
1078 ig.Emit (OpCodes.Ldind_U1);
1079 else if (t == TypeManager.sbyte_type)
1080 ig.Emit (OpCodes.Ldind_I1);
1081 else if (t == TypeManager.uint64_type)
1082 ig.Emit (OpCodes.Ldind_I8);
1083 else if (t == TypeManager.int64_type)
1084 ig.Emit (OpCodes.Ldind_I8);
1085 else if (t == TypeManager.float_type)
1086 ig.Emit (OpCodes.Ldind_R4);
1087 else if (t == TypeManager.double_type)
1088 ig.Emit (OpCodes.Ldind_R8);
1089 else if (t == TypeManager.bool_type)
1090 ig.Emit (OpCodes.Ldind_I1);
1091 else if (t == TypeManager.intptr_type)
1092 ig.Emit (OpCodes.Ldind_I);
1093 else if (TypeManager.IsEnumType (t)) {
1094 if (t == TypeManager.enum_type)
1095 ig.Emit (OpCodes.Ldind_Ref);
1097 LoadFromPtr (ig, TypeManager.GetEnumUnderlyingType (t));
1098 } else if (t.IsValueType || TypeManager.IsGenericParameter (t))
1099 ig.Emit (OpCodes.Ldobj, t);
1100 else if (t.IsPointer)
1101 ig.Emit (OpCodes.Ldind_I);
1103 ig.Emit (OpCodes.Ldind_Ref);
1107 // The stack contains the pointer and the value of type `type'
1109 public static void StoreFromPtr (ILGenerator ig, Type type)
1111 if (TypeManager.IsEnumType (type))
1112 type = TypeManager.GetEnumUnderlyingType (type);
1113 if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
1114 ig.Emit (OpCodes.Stind_I4);
1115 else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
1116 ig.Emit (OpCodes.Stind_I8);
1117 else if (type == TypeManager.char_type || type == TypeManager.short_type ||
1118 type == TypeManager.ushort_type)
1119 ig.Emit (OpCodes.Stind_I2);
1120 else if (type == TypeManager.float_type)
1121 ig.Emit (OpCodes.Stind_R4);
1122 else if (type == TypeManager.double_type)
1123 ig.Emit (OpCodes.Stind_R8);
1124 else if (type == TypeManager.byte_type || type == TypeManager.sbyte_type ||
1125 type == TypeManager.bool_type)
1126 ig.Emit (OpCodes.Stind_I1);
1127 else if (type == TypeManager.intptr_type)
1128 ig.Emit (OpCodes.Stind_I);
1129 else if (type.IsValueType || TypeManager.IsGenericParameter (type))
1130 ig.Emit (OpCodes.Stobj, type);
1132 ig.Emit (OpCodes.Stind_Ref);
1136 // Returns the size of type `t' if known, otherwise, 0
1138 public static int GetTypeSize (Type t)
1140 t = TypeManager.TypeToCoreType (t);
1141 if (t == TypeManager.int32_type ||
1142 t == TypeManager.uint32_type ||
1143 t == TypeManager.float_type)
1145 else if (t == TypeManager.int64_type ||
1146 t == TypeManager.uint64_type ||
1147 t == TypeManager.double_type)
1149 else if (t == TypeManager.byte_type ||
1150 t == TypeManager.sbyte_type ||
1151 t == TypeManager.bool_type)
1153 else if (t == TypeManager.short_type ||
1154 t == TypeManager.char_type ||
1155 t == TypeManager.ushort_type)
1157 else if (t == TypeManager.decimal_type)
1163 protected void Error_CannotCallAbstractBase (string name)
1165 Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
1168 protected void Error_CannotModifyIntermediateExpressionValue (EmitContext ec)
1170 Report.SymbolRelatedToPreviousError (type);
1171 if (ec.CurrentInitializerVariable != null) {
1172 Report.Error (1918, loc, "Members of a value type property `{0}' cannot be assigned with an object initializer",
1173 GetSignatureForError ());
1175 Report.Error (1612, loc, "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
1176 GetSignatureForError ());
1181 // Converts `source' to an int, uint, long or ulong.
1183 public Expression ConvertExpressionToArrayIndex (EmitContext ec, Expression source)
1185 Expression converted;
1187 using (ec.With (EmitContext.Flags.CheckState, true)) {
1188 converted = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, source.loc);
1189 if (converted == null)
1190 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, source.loc);
1191 if (converted == null)
1192 converted = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, source.loc);
1193 if (converted == null)
1194 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, source.loc);
1196 if (converted == null) {
1197 source.Error_ValueCannotBeConverted (ec, source.loc, TypeManager.int32_type, false);
1203 // Only positive constants are allowed at compile time
1205 Constant c = converted as Constant;
1208 Error_NegativeArrayIndex (source.loc);
1213 return new ArrayIndexCast (converted).Resolve (ec);
1217 // Derived classes implement this method by cloning the fields that
1218 // could become altered during the Resolve stage
1220 // Only expressions that are created for the parser need to implement
1223 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1225 throw new NotImplementedException (
1227 "CloneTo not implemented for expression {0}", this.GetType ()));
1231 // Clones an expression created by the parser.
1233 // We only support expressions created by the parser so far, not
1234 // expressions that have been resolved (many more classes would need
1235 // to implement CloneTo).
1237 // This infrastructure is here merely for Lambda expressions which
1238 // compile the same code using different type values for the same
1239 // arguments to find the correct overload
1241 public Expression Clone (CloneContext clonectx)
1243 Expression cloned = (Expression) MemberwiseClone ();
1244 CloneTo (clonectx, cloned);
1250 // Implementation of expression to expression tree conversion
1252 public abstract Expression CreateExpressionTree (EmitContext ec);
1254 protected Expression CreateExpressionFactoryCall (string name, ArrayList args)
1256 return CreateExpressionFactoryCall (name, null, args, loc);
1259 protected Expression CreateExpressionFactoryCall (string name, TypeArguments typeArguments, ArrayList args)
1261 return CreateExpressionFactoryCall (name, typeArguments, args, loc);
1264 public static Expression CreateExpressionFactoryCall (string name, TypeArguments typeArguments, ArrayList args, Location loc)
1266 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (loc), name, typeArguments, loc), args);
1269 protected static TypeExpr CreateExpressionTypeExpression (Location loc)
1271 TypeExpr texpr = TypeManager.expression_type_expr;
1272 if (texpr == null) {
1273 Type t = TypeManager.CoreLookupType ("System.Linq.Expressions", "Expression", Kind.Class, true);
1277 TypeManager.expression_type_expr = texpr = new TypeExpression (t, Location.Null);
1285 /// This is just a base class for expressions that can
1286 /// appear on statements (invocations, object creation,
1287 /// assignments, post/pre increment and decrement). The idea
1288 /// being that they would support an extra Emition interface that
1289 /// does not leave a result on the stack.
1291 public abstract class ExpressionStatement : Expression {
1293 public virtual ExpressionStatement ResolveStatement (EmitContext ec)
1295 Expression e = Resolve (ec);
1299 ExpressionStatement es = e as ExpressionStatement;
1301 Error_InvalidExpressionStatement ();
1307 /// Requests the expression to be emitted in a `statement'
1308 /// context. This means that no new value is left on the
1309 /// stack after invoking this method (constrasted with
1310 /// Emit that will always leave a value on the stack).
1312 public abstract void EmitStatement (EmitContext ec);
1314 public override void EmitSideEffect (EmitContext ec)
1321 /// This kind of cast is used to encapsulate the child
1322 /// whose type is child.Type into an expression that is
1323 /// reported to return "return_type". This is used to encapsulate
1324 /// expressions which have compatible types, but need to be dealt
1325 /// at higher levels with.
1327 /// For example, a "byte" expression could be encapsulated in one
1328 /// of these as an "unsigned int". The type for the expression
1329 /// would be "unsigned int".
1332 public abstract class TypeCast : Expression
1334 protected Expression child;
1336 protected TypeCast (Expression child, Type return_type)
1338 eclass = child.eclass;
1339 loc = child.Location;
1344 public override Expression CreateExpressionTree (EmitContext ec)
1346 ArrayList args = new ArrayList (2);
1347 args.Add (new Argument (child.CreateExpressionTree (ec)));
1348 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1350 if (type.IsPointer || child.Type.IsPointer)
1351 Error_PointerInsideExpressionTree ();
1353 return CreateExpressionFactoryCall (ec.CheckState ? "ConvertChecked" : "Convert", args);
1356 public override Expression DoResolve (EmitContext ec)
1358 // This should never be invoked, we are born in fully
1359 // initialized state.
1364 public override void Emit (EmitContext ec)
1369 public override bool GetAttributableValue (Type value_type, out object value)
1371 return child.GetAttributableValue (value_type, out value);
1374 protected override void CloneTo (CloneContext clonectx, Expression t)
1376 TypeCast target = (TypeCast) t;
1378 target.child = child.Clone (clonectx);
1381 public override bool IsNull {
1382 get { return child.IsNull; }
1386 public class EmptyCast : TypeCast {
1387 EmptyCast (Expression child, Type target_type)
1388 : base (child, target_type)
1392 public static Expression Create (Expression child, Type type)
1394 Constant c = child as Constant;
1396 return new EmptyConstantCast (c, type);
1398 EmptyCast e = child as EmptyCast;
1400 return new EmptyCast (e.child, type);
1402 return new EmptyCast (child, type);
1405 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1407 child.EmitBranchable (ec, label, on_true);
1410 public override void EmitSideEffect (EmitContext ec)
1412 child.EmitSideEffect (ec);
1417 /// Performs a cast using an operator (op_Explicit or op_Implicit)
1419 public class OperatorCast : TypeCast {
1420 MethodInfo conversion_operator;
1423 public OperatorCast (Expression child, Type target_type) : this (child, target_type, false) {}
1425 public OperatorCast (Expression child, Type target_type, bool find_explicit)
1426 : base (child, target_type)
1428 this.find_explicit = find_explicit;
1431 // Returns the implicit operator that converts from
1432 // 'child.Type' to our target type (type)
1433 MethodInfo GetConversionOperator (bool find_explicit)
1435 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1439 mi = TypeManager.MemberLookup (child.Type, child.Type, child.Type, MemberTypes.Method,
1440 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1443 mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1444 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1447 foreach (MethodInfo oper in mi) {
1448 ParameterData pd = TypeManager.GetParameterData (oper);
1450 if (pd.ParameterType (0) == child.Type && TypeManager.TypeToCoreType (oper.ReturnType) == type)
1458 public override void Emit (EmitContext ec)
1460 ILGenerator ig = ec.ig;
1463 conversion_operator = GetConversionOperator (find_explicit);
1465 if (conversion_operator == null)
1466 throw new InternalErrorException ("Outer conversion routine is out of sync");
1468 ig.Emit (OpCodes.Call, conversion_operator);
1474 /// This is a numeric cast to a Decimal
1476 public class CastToDecimal : TypeCast {
1477 MethodInfo conversion_operator;
1479 public CastToDecimal (Expression child)
1480 : this (child, false)
1484 public CastToDecimal (Expression child, bool find_explicit)
1485 : base (child, TypeManager.decimal_type)
1487 conversion_operator = GetConversionOperator (find_explicit);
1489 if (conversion_operator == null)
1490 throw new InternalErrorException ("Outer conversion routine is out of sync");
1493 // Returns the implicit operator that converts from
1494 // 'child.Type' to System.Decimal.
1495 MethodInfo GetConversionOperator (bool find_explicit)
1497 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1499 MemberInfo [] mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1500 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1502 foreach (MethodInfo oper in mi) {
1503 ParameterData pd = TypeManager.GetParameterData (oper);
1505 if (pd.ParameterType (0) == child.Type && TypeManager.TypeToCoreType (oper.ReturnType) == type)
1511 public override void Emit (EmitContext ec)
1513 ILGenerator ig = ec.ig;
1516 ig.Emit (OpCodes.Call, conversion_operator);
1521 /// This is an explicit numeric cast from a Decimal
1523 public class CastFromDecimal : TypeCast
1525 static IDictionary operators;
1527 public CastFromDecimal (Expression child, Type return_type)
1528 : base (child, return_type)
1530 if (child.Type != TypeManager.decimal_type)
1531 throw new InternalErrorException (
1532 "The expected type is Decimal, instead it is " + child.Type.FullName);
1535 // Returns the explicit operator that converts from an
1536 // express of type System.Decimal to 'type'.
1537 public Expression Resolve ()
1539 if (operators == null) {
1540 MemberInfo[] all_oper = TypeManager.MemberLookup (TypeManager.decimal_type,
1541 TypeManager.decimal_type, TypeManager.decimal_type, MemberTypes.Method,
1542 BindingFlags.Static | BindingFlags.Public, "op_Explicit", null);
1544 operators = new System.Collections.Specialized.HybridDictionary ();
1545 foreach (MethodInfo oper in all_oper) {
1546 ParameterData pd = TypeManager.GetParameterData (oper);
1547 if (pd.ParameterType (0) == TypeManager.decimal_type)
1548 operators.Add (TypeManager.TypeToCoreType (oper.ReturnType), oper);
1552 return operators.Contains (type) ? this : null;
1555 public override void Emit (EmitContext ec)
1557 ILGenerator ig = ec.ig;
1560 ig.Emit (OpCodes.Call, (MethodInfo)operators [type]);
1566 // Constant specialization of EmptyCast.
1567 // We need to special case this since an empty cast of
1568 // a constant is still a constant.
1570 public class EmptyConstantCast : Constant
1572 public readonly Constant child;
1574 public EmptyConstantCast(Constant child, Type type)
1575 : base (child.Location)
1577 eclass = child.eclass;
1582 public override string AsString ()
1584 return child.AsString ();
1587 public override object GetValue ()
1589 return child.GetValue ();
1592 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
1594 // FIXME: check that 'type' can be converted to 'target_type' first
1595 return child.ConvertExplicitly (in_checked_context, target_type);
1598 public override Expression CreateExpressionTree (EmitContext ec)
1600 ArrayList args = new ArrayList (2);
1601 args.Add (new Argument (child.CreateExpressionTree (ec)));
1602 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1604 Error_PointerInsideExpressionTree ();
1606 return CreateExpressionFactoryCall ("Convert", args);
1609 public override Constant Increment ()
1611 return child.Increment ();
1614 public override bool IsDefaultValue {
1615 get { return child.IsDefaultValue; }
1618 public override bool IsNegative {
1619 get { return child.IsNegative; }
1622 public override bool IsNull {
1623 get { return child.IsNull; }
1626 public override bool IsZeroInteger {
1627 get { return child.IsZeroInteger; }
1630 public override void Emit (EmitContext ec)
1635 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1637 child.EmitBranchable (ec, label, on_true);
1640 public override void EmitSideEffect (EmitContext ec)
1642 child.EmitSideEffect (ec);
1645 public override Constant ConvertImplicitly (Type target_type)
1647 // FIXME: Do we need to check user conversions?
1648 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1650 return child.ConvertImplicitly (target_type);
1656 /// This class is used to wrap literals which belong inside Enums
1658 public class EnumConstant : Constant {
1659 public Constant Child;
1661 public EnumConstant (Constant child, Type enum_type):
1662 base (child.Location)
1664 eclass = child.eclass;
1669 public override Expression DoResolve (EmitContext ec)
1671 // This should never be invoked, we are born in fully
1672 // initialized state.
1677 public override void Emit (EmitContext ec)
1682 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1684 Child.EmitBranchable (ec, label, on_true);
1687 public override void EmitSideEffect (EmitContext ec)
1689 Child.EmitSideEffect (ec);
1692 public override bool GetAttributableValue (Type value_type, out object value)
1694 value = GetTypedValue ();
1698 public override string GetSignatureForError()
1700 return TypeManager.CSharpName (Type);
1703 public override object GetValue ()
1705 return Child.GetValue ();
1708 public override object GetTypedValue ()
1710 // FIXME: runtime is not ready to work with just emited enums
1711 if (!RootContext.StdLib) {
1712 return Child.GetValue ();
1715 return System.Enum.ToObject (type, Child.GetValue ());
1718 public override string AsString ()
1720 return TypeManager.CSharpEnumValue (type, Child.GetValue ());
1723 public override Constant Increment()
1725 return new EnumConstant (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 (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 (type.UnderlyingSystemType);
1768 if (!Convert.ImplicitStandardConversionExists (this, type)){
1772 return Child.ConvertImplicitly(type);
1778 /// This kind of cast is used to encapsulate Value Types in objects.
1780 /// The effect of it is to box the value type emitted by the previous
1783 public class BoxedCast : TypeCast {
1785 public BoxedCast (Expression expr, Type target_type)
1786 : base (expr, target_type)
1788 eclass = ExprClass.Value;
1791 public override Expression DoResolve (EmitContext ec)
1793 // This should never be invoked, we are born in fully
1794 // initialized state.
1799 public override void Emit (EmitContext ec)
1803 ec.ig.Emit (OpCodes.Box, child.Type);
1806 public override void EmitSideEffect (EmitContext ec)
1808 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1809 // so, we need to emit the box+pop instructions in most cases
1810 if (child.Type.IsValueType &&
1811 (type == TypeManager.object_type || type == TypeManager.value_type))
1812 child.EmitSideEffect (ec);
1814 base.EmitSideEffect (ec);
1818 public class UnboxCast : TypeCast {
1819 public UnboxCast (Expression expr, Type return_type)
1820 : base (expr, return_type)
1824 public override Expression DoResolve (EmitContext ec)
1826 // This should never be invoked, we are born in fully
1827 // initialized state.
1832 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1834 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
1835 Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
1836 return base.DoResolveLValue (ec, right_side);
1839 public override void Emit (EmitContext ec)
1842 ILGenerator ig = ec.ig;
1846 if (t.IsGenericParameter || t.IsGenericType && t.IsValueType)
1847 ig.Emit (OpCodes.Unbox_Any, t);
1851 ig.Emit (OpCodes.Unbox, t);
1853 LoadFromPtr (ig, t);
1859 /// This is used to perform explicit numeric conversions.
1861 /// Explicit numeric conversions might trigger exceptions in a checked
1862 /// context, so they should generate the conv.ovf opcodes instead of
1865 public class ConvCast : TypeCast {
1866 public enum Mode : byte {
1867 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1869 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1870 U2_I1, U2_U1, U2_I2, U2_CH,
1871 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1872 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1873 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH,
1874 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH,
1875 CH_I1, CH_U1, CH_I2,
1876 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1877 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4
1882 public ConvCast (Expression child, Type return_type, Mode m)
1883 : base (child, return_type)
1888 public override Expression DoResolve (EmitContext ec)
1890 // This should never be invoked, we are born in fully
1891 // initialized state.
1896 public override string ToString ()
1898 return String.Format ("ConvCast ({0}, {1})", mode, child);
1901 public override void Emit (EmitContext ec)
1903 ILGenerator ig = ec.ig;
1909 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1910 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1911 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1912 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1913 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1915 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1916 case Mode.U1_CH: /* nothing */ break;
1918 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1919 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1920 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1921 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1922 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1923 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1925 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1926 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1927 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1928 case Mode.U2_CH: /* nothing */ break;
1930 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1931 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1932 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1933 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1934 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1935 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1936 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1938 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1939 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1940 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1941 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1942 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1943 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1945 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1946 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1947 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1948 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1949 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1950 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1951 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1952 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1954 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1955 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1956 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1957 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1958 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1959 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1960 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1961 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1963 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1964 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1965 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1967 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1968 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1969 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1970 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1971 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1972 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1973 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1974 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1975 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1977 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1978 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1979 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1980 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1981 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1982 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1983 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1984 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1985 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1986 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1990 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
1991 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
1992 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
1993 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
1994 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
1996 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
1997 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
1999 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
2000 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
2001 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
2002 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
2003 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
2004 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
2006 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
2007 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
2008 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
2009 case Mode.U2_CH: /* nothing */ break;
2011 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
2012 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
2013 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
2014 case Mode.I4_U4: /* nothing */ break;
2015 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
2016 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
2017 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
2019 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
2020 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
2021 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
2022 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
2023 case Mode.U4_I4: /* nothing */ break;
2024 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
2026 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
2027 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
2028 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
2029 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
2030 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
2031 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
2032 case Mode.I8_U8: /* nothing */ break;
2033 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
2035 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
2036 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
2037 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
2038 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
2039 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
2040 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
2041 case Mode.U8_I8: /* nothing */ break;
2042 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
2044 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
2045 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
2046 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
2048 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
2049 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
2050 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
2051 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
2052 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
2053 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
2054 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
2055 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
2056 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
2058 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
2059 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
2060 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
2061 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
2062 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
2063 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
2064 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
2065 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
2066 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
2067 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
2073 public class OpcodeCast : TypeCast {
2077 public OpcodeCast (Expression child, Type return_type, OpCode op)
2078 : base (child, return_type)
2082 second_valid = false;
2085 public OpcodeCast (Expression child, Type return_type, OpCode op, OpCode op2)
2086 : base (child, return_type)
2091 second_valid = true;
2094 public override Expression DoResolve (EmitContext ec)
2096 // This should never be invoked, we are born in fully
2097 // initialized state.
2102 public override void Emit (EmitContext ec)
2111 public Type UnderlyingType {
2112 get { return child.Type; }
2117 /// This kind of cast is used to encapsulate a child and cast it
2118 /// to the class requested
2120 public class ClassCast : TypeCast {
2121 public ClassCast (Expression child, Type return_type)
2122 : base (child, return_type)
2127 public override Expression DoResolve (EmitContext ec)
2129 // This should never be invoked, we are born in fully
2130 // initialized state.
2135 public override void Emit (EmitContext ec)
2139 if (TypeManager.IsGenericParameter (child.Type))
2140 ec.ig.Emit (OpCodes.Box, child.Type);
2143 if (type.IsGenericParameter)
2144 ec.ig.Emit (OpCodes.Unbox_Any, type);
2147 ec.ig.Emit (OpCodes.Castclass, type);
2152 // Used when resolved expression has different representations for
2153 // expression trees and emit phase
2155 public class ReducedExpression : Expression
2157 class ReducedConstantExpression : Constant
2159 readonly Constant expr;
2160 readonly Expression orig_expr;
2162 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2163 : base (expr.Location)
2166 this.orig_expr = orig_expr;
2167 eclass = expr.eclass;
2171 public override string AsString ()
2173 return expr.AsString ();
2176 public override Expression CreateExpressionTree (EmitContext ec)
2178 return orig_expr.CreateExpressionTree (ec);
2181 public override object GetValue ()
2183 return expr.GetValue ();
2186 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
2188 throw new NotImplementedException ();
2191 public override Expression DoResolve (EmitContext ec)
2196 public override Constant Increment ()
2198 throw new NotImplementedException ();
2201 public override bool IsDefaultValue {
2203 return expr.IsDefaultValue;
2207 public override bool IsNegative {
2209 return expr.IsNegative;
2213 public override void Emit (EmitContext ec)
2219 readonly Expression expr, orig_expr;
2221 private ReducedExpression (Expression expr, Expression orig_expr)
2224 this.orig_expr = orig_expr;
2225 this.loc = orig_expr.Location;
2228 public static Expression Create (Constant expr, Expression original_expr)
2230 return new ReducedConstantExpression (expr, original_expr);
2233 public static Expression Create (Expression expr, Expression original_expr)
2235 Constant c = expr as Constant;
2237 return Create (c, original_expr);
2239 return new ReducedExpression (expr, original_expr);
2242 public override Expression CreateExpressionTree (EmitContext ec)
2244 return orig_expr.CreateExpressionTree (ec);
2247 public override Expression DoResolve (EmitContext ec)
2249 eclass = expr.eclass;
2254 public override void Emit (EmitContext ec)
2259 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2261 expr.EmitBranchable (ec, target, on_true);
2266 // Unresolved type name expressions
2268 public abstract class ATypeNameExpression : FullNamedExpression
2270 public readonly string Name;
2271 protected TypeArguments targs;
2273 protected ATypeNameExpression (string name, Location l)
2279 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2286 public bool HasTypeArguments {
2288 return targs != null;
2292 public override string GetSignatureForError ()
2294 if (targs != null) {
2295 return TypeManager.RemoveGenericArity (Name) + "<" +
2296 targs.GetSignatureForError () + ">";
2304 /// SimpleName expressions are formed of a single word and only happen at the beginning
2305 /// of a dotted-name.
2307 public class SimpleName : ATypeNameExpression {
2310 public SimpleName (string name, Location l)
2315 public SimpleName (string name, TypeArguments args, Location l)
2316 : base (name, args, l)
2320 public SimpleName (string name, TypeParameter[] type_params, Location l)
2323 targs = new TypeArguments (l);
2324 foreach (TypeParameter type_param in type_params)
2325 targs.Add (new TypeParameterExpr (type_param, l));
2328 public static string RemoveGenericArity (string name)
2331 StringBuilder sb = null;
2333 int pos = name.IndexOf ('`', start);
2338 sb.Append (name.Substring (start));
2343 sb = new StringBuilder ();
2344 sb.Append (name.Substring (start, pos-start));
2347 while ((pos < name.Length) && Char.IsNumber (name [pos]))
2351 } while (start < name.Length);
2353 return sb.ToString ();
2356 public SimpleName GetMethodGroup ()
2358 return new SimpleName (RemoveGenericArity (Name), targs, loc);
2361 public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
2363 if (ec.IsInFieldInitializer)
2364 Report.Error (236, l,
2365 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2369 120, l, "`{0}': An object reference is required for the nonstatic field, method or property",
2373 public bool IdenticalNameAndTypeName (EmitContext ec, Expression resolved_to, Location loc)
2375 return resolved_to != null && resolved_to.Type != null &&
2376 resolved_to.Type.Name == Name &&
2377 (ec.DeclContainer.LookupNamespaceOrType (Name, loc, /* ignore_cs0104 = */ true) != null);
2380 public override Expression DoResolve (EmitContext ec)
2382 return SimpleNameResolve (ec, null, false);
2385 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
2387 return SimpleNameResolve (ec, right_side, false);
2391 public Expression DoResolve (EmitContext ec, bool intermediate)
2393 return SimpleNameResolve (ec, null, intermediate);
2396 static bool IsNestedChild (Type t, Type parent)
2398 while (parent != null) {
2399 if (TypeManager.IsNestedChildOf (t, TypeManager.DropGenericTypeArguments (parent)))
2402 parent = parent.BaseType;
2408 FullNamedExpression ResolveNested (IResolveContext ec, Type t)
2410 if (!TypeManager.IsGenericTypeDefinition (t) && !TypeManager.IsGenericType (t))
2413 DeclSpace ds = ec.DeclContainer;
2414 while (ds != null && !IsNestedChild (t, ds.TypeBuilder))
2420 Type[] gen_params = TypeManager.GetTypeArguments (t);
2422 int arg_count = targs != null ? targs.Count : 0;
2424 for (; (ds != null) && ds.IsGeneric; ds = ds.Parent) {
2425 if (arg_count + ds.CountTypeParameters == gen_params.Length) {
2426 TypeArguments new_args = new TypeArguments (loc);
2427 foreach (TypeParameter param in ds.TypeParameters)
2428 new_args.Add (new TypeParameterExpr (param, loc));
2431 new_args.Add (targs);
2433 return new ConstructedType (t, new_args, loc);
2440 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2442 FullNamedExpression fne = ec.GenericDeclContainer.LookupGeneric (Name, loc);
2444 return fne.ResolveAsTypeStep (ec, silent);
2446 int errors = Report.Errors;
2447 fne = ec.DeclContainer.LookupNamespaceOrType (Name, loc, /*ignore_cs0104=*/ false);
2450 if (fne.Type == null)
2453 FullNamedExpression nested = ResolveNested (ec, fne.Type);
2455 return nested.ResolveAsTypeStep (ec, false);
2457 if (targs != null) {
2458 ConstructedType ct = new ConstructedType (fne, targs, loc);
2459 return ct.ResolveAsTypeStep (ec, false);
2465 if (silent || errors != Report.Errors)
2468 Error_TypeOrNamespaceNotFound (ec);
2472 protected virtual void Error_TypeOrNamespaceNotFound (IResolveContext ec)
2474 MemberCore mc = ec.DeclContainer.GetDefinition (Name);
2476 Error_UnexpectedKind (ec.DeclContainer, "type", GetMemberType (mc), loc);
2480 string ns = ec.DeclContainer.NamespaceEntry.NS.Name;
2481 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2482 foreach (Assembly a in RootNamespace.Global.Assemblies) {
2483 Type type = a.GetType (fullname);
2485 Report.SymbolRelatedToPreviousError (type);
2486 Expression.ErrorIsInaccesible (loc, TypeManager.CSharpName (type));
2491 Type t = ec.DeclContainer.LookupAnyGeneric (Name);
2493 Namespace.Error_InvalidNumberOfTypeArguments (t, loc);
2497 if (targs != null) {
2498 FullNamedExpression retval = ec.DeclContainer.LookupNamespaceOrType (SimpleName.RemoveGenericArity (Name), loc, true);
2499 if (retval != null) {
2500 Namespace.Error_TypeArgumentsCannotBeUsed (retval.Type, loc);
2505 NamespaceEntry.Error_NamespaceNotFound (loc, Name);
2508 // TODO: I am still not convinced about this. If someone else will need it
2509 // implement this as virtual property in MemberCore hierarchy
2510 public static string GetMemberType (MemberCore mc)
2516 if (mc is FieldBase)
2518 if (mc is MethodCore)
2520 if (mc is EnumMember)
2528 Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2534 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2540 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2547 /// 7.5.2: Simple Names.
2549 /// Local Variables and Parameters are handled at
2550 /// parse time, so they never occur as SimpleNames.
2552 /// The `intermediate' flag is used by MemberAccess only
2553 /// and it is used to inform us that it is ok for us to
2554 /// avoid the static check, because MemberAccess might end
2555 /// up resolving the Name as a Type name and the access as
2556 /// a static type access.
2558 /// ie: Type Type; .... { Type.GetType (""); }
2560 /// Type is both an instance variable and a Type; Type.GetType
2561 /// is the static method not an instance method of type.
2563 Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2565 Expression e = null;
2568 // Stage 1: Performed by the parser (binding to locals or parameters).
2570 Block current_block = ec.CurrentBlock;
2571 if (current_block != null){
2572 LocalInfo vi = current_block.GetLocalInfo (Name);
2574 if (targs != null) {
2575 Report.Error (307, loc,
2576 "The variable `{0}' cannot be used with type arguments",
2581 LocalVariableReference var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2582 if (right_side != null) {
2583 return var.ResolveLValue (ec, right_side, loc);
2585 ResolveFlags rf = ResolveFlags.VariableOrValue;
2587 rf |= ResolveFlags.DisableFlowAnalysis;
2588 return var.Resolve (ec, rf);
2592 ParameterReference pref = current_block.Toplevel.GetParameterReference (Name, loc);
2594 if (targs != null) {
2595 Report.Error (307, loc,
2596 "The variable `{0}' cannot be used with type arguments",
2601 if (right_side != null)
2602 return pref.ResolveLValue (ec, right_side, loc);
2604 return pref.Resolve (ec);
2607 Expression expr = current_block.Toplevel.GetTransparentIdentifier (Name);
2609 if (right_side != null)
2610 return expr.ResolveLValue (ec, right_side, loc);
2611 return expr.Resolve (ec);
2616 // Stage 2: Lookup members
2619 Type almost_matched_type = null;
2620 ArrayList almost_matched = null;
2621 for (DeclSpace lookup_ds = ec.DeclContainer; lookup_ds != null; lookup_ds = lookup_ds.Parent) {
2622 // either RootDeclSpace or GenericMethod
2623 if (lookup_ds.TypeBuilder == null)
2626 e = MemberLookup (ec.ContainerType, lookup_ds.TypeBuilder, Name, loc);
2628 if (e is PropertyExpr) {
2629 // since TypeManager.MemberLookup doesn't know if we're doing a lvalue access or not,
2630 // it doesn't know which accessor to check permissions against
2631 if (((PropertyExpr) e).IsAccessibleFrom (ec.ContainerType, right_side != null))
2633 } else if (e is EventExpr) {
2634 if (((EventExpr) e).IsAccessibleFrom (ec.ContainerType))
2642 if (almost_matched == null && almost_matched_members.Count > 0) {
2643 almost_matched_type = lookup_ds.TypeBuilder;
2644 almost_matched = (ArrayList) almost_matched_members.Clone ();
2649 if (almost_matched == null && almost_matched_members.Count > 0) {
2650 almost_matched_type = ec.ContainerType;
2651 almost_matched = (ArrayList) almost_matched_members.Clone ();
2653 e = ResolveAsTypeStep (ec, true);
2657 if (current_block != null) {
2658 IKnownVariable ikv = current_block.Explicit.GetKnownVariable (Name);
2660 LocalInfo li = ikv as LocalInfo;
2661 // Supress CS0219 warning
2665 Error_VariableIsUsedBeforeItIsDeclared (Name);
2670 if (almost_matched != null)
2671 almost_matched_members = almost_matched;
2672 if (almost_matched_type == null)
2673 almost_matched_type = ec.ContainerType;
2674 Error_MemberLookupFailed (ec.ContainerType, null, almost_matched_type, Name,
2675 ec.DeclContainer.Name, AllMemberTypes, AllBindingFlags);
2679 if (e is TypeExpr) {
2683 ConstructedType ct = new ConstructedType (
2684 e.Type, targs, loc);
2685 return ct.ResolveAsTypeStep (ec, false);
2688 if (e is MemberExpr) {
2689 MemberExpr me = (MemberExpr) e;
2692 if (me.IsInstance) {
2693 if (ec.IsStatic || ec.IsInFieldInitializer) {
2695 // Note that an MemberExpr can be both IsInstance and IsStatic.
2696 // An unresolved MethodGroupExpr can contain both kinds of methods
2697 // and each predicate is true if the MethodGroupExpr contains
2698 // at least one of that kind of method.
2702 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2703 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2708 // Pass the buck to MemberAccess and Invocation.
2710 left = EmptyExpression.Null;
2712 left = ec.GetThis (loc);
2715 left = new TypeExpression (ec.ContainerType, loc);
2718 me = me.ResolveMemberAccess (ec, left, loc, null);
2722 if (targs != null) {
2724 me.SetTypeArguments (targs);
2727 if (!me.IsStatic && (me.InstanceExpression != null) &&
2728 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2729 me.InstanceExpression.Type != me.DeclaringType &&
2730 !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2731 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2732 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2733 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2737 return (right_side != null)
2738 ? me.DoResolveLValue (ec, right_side)
2739 : me.DoResolve (ec);
2745 protected override void CloneTo (CloneContext clonectx, Expression target)
2747 // CloneTo: Nothing, we do not keep any state on this expression
2752 /// Represents a namespace or a type. The name of the class was inspired by
2753 /// section 10.8.1 (Fully Qualified Names).
2755 public abstract class FullNamedExpression : Expression {
2757 public override Expression CreateExpressionTree (EmitContext ec)
2759 throw new NotSupportedException ("ET");
2762 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2767 public override void Emit (EmitContext ec)
2769 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2770 GetSignatureForError ());
2775 /// Expression that evaluates to a type
2777 public abstract class TypeExpr : FullNamedExpression {
2778 override public FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2780 TypeExpr t = DoResolveAsTypeStep (ec);
2784 eclass = ExprClass.Type;
2788 override public Expression DoResolve (EmitContext ec)
2790 return ResolveAsTypeTerminal (ec, false);
2793 public virtual bool CheckAccessLevel (DeclSpace ds)
2795 return ds.CheckAccessLevel (Type);
2798 public virtual bool AsAccessible (DeclSpace ds)
2800 return ds.IsAccessibleAs (Type);
2803 public virtual bool IsClass {
2804 get { return Type.IsClass; }
2807 public virtual bool IsValueType {
2808 get { return Type.IsValueType; }
2811 public virtual bool IsInterface {
2812 get { return Type.IsInterface; }
2815 public virtual bool IsSealed {
2816 get { return Type.IsSealed; }
2819 public virtual bool CanInheritFrom ()
2821 if (Type == TypeManager.enum_type ||
2822 (Type == TypeManager.value_type && RootContext.StdLib) ||
2823 Type == TypeManager.multicast_delegate_type ||
2824 Type == TypeManager.delegate_type ||
2825 Type == TypeManager.array_type)
2831 protected abstract TypeExpr DoResolveAsTypeStep (IResolveContext ec);
2833 public override bool Equals (object obj)
2835 TypeExpr tobj = obj as TypeExpr;
2839 return Type == tobj.Type;
2842 public override int GetHashCode ()
2844 return Type.GetHashCode ();
2849 /// Fully resolved Expression that already evaluated to a type
2851 public class TypeExpression : TypeExpr {
2852 public TypeExpression (Type t, Location l)
2855 eclass = ExprClass.Type;
2859 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2864 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2871 /// Used to create types from a fully qualified name. These are just used
2872 /// by the parser to setup the core types. A TypeLookupExpression is always
2873 /// classified as a type.
2875 public sealed class TypeLookupExpression : TypeExpr {
2876 readonly string name;
2878 public TypeLookupExpression (string name)
2881 eclass = ExprClass.Type;
2884 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2886 // It's null for corlib compilation only
2888 return DoResolveAsTypeStep (ec);
2893 private class UnexpectedType
2897 // This performes recursive type lookup, providing support for generic types.
2898 // For example, given the type:
2900 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]]
2902 // The types will be checked in the following order:
2905 // System.Collections |
2906 // System.Collections.Generic |
2908 // System | recursive call 1 |
2909 // System.Int32 _| | main method call
2911 // System | recursive call 2 |
2912 // System.String _| |
2914 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]] _|
2916 private Type TypeLookup (IResolveContext ec, string name)
2921 FullNamedExpression resolved = null;
2923 Type recursive_type = null;
2924 while (index < name.Length) {
2925 if (name[index] == '[') {
2930 if (name[index] == '[')
2932 else if (name[index] == ']')
2934 } while (braces > 0);
2935 recursive_type = TypeLookup (ec, name.Substring (open + 1, index - open - 1));
2936 if (recursive_type == null || (recursive_type == typeof(UnexpectedType)))
2937 return recursive_type;
2940 if (name[index] == ',')
2942 else if ((name[index] == '.' && !done) || (index == name.Length && name[0] != '[')) {
2943 string substring = name.Substring(dot, index - dot);
2945 if (resolved == null)
2946 resolved = RootNamespace.Global.Lookup (ec.DeclContainer, substring, Location.Null);
2947 else if (resolved is Namespace)
2948 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
2949 else if (type != null)
2950 type = TypeManager.GetNestedType (type, substring);
2954 if (resolved == null)
2956 else if (type == null && resolved is TypeExpr)
2957 type = resolved.Type;
2964 if (name[0] != '[') {
2965 string substring = name.Substring(dot, index - dot);
2968 return TypeManager.GetNestedType (type, substring);
2970 if (resolved != null) {
2971 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
2972 if (resolved is TypeExpr)
2973 return resolved.Type;
2975 if (resolved == null)
2978 resolved.Error_UnexpectedKind (ec.DeclContainer, "type", loc);
2979 return typeof (UnexpectedType);
2985 return recursive_type;
2988 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2990 Type t = TypeLookup (ec, name);
2992 NamespaceEntry.Error_NamespaceNotFound (loc, name);
2995 if (t == typeof(UnexpectedType))
3001 protected override void CloneTo (CloneContext clonectx, Expression target)
3003 // CloneTo: Nothing, we do not keep any state on this expression
3006 public override string GetSignatureForError ()
3009 return TypeManager.CSharpName (name);
3011 return base.GetSignatureForError ();
3016 /// Represents an "unbound generic type", ie. typeof (Foo<>).
3019 public class UnboundTypeExpression : TypeExpr
3023 public UnboundTypeExpression (MemberName name, Location l)
3029 protected override void CloneTo (CloneContext clonectx, Expression target)
3034 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
3037 if (name.Left != null) {
3038 Expression lexpr = name.Left.GetTypeExpression ();
3039 expr = new MemberAccess (lexpr, name.Basename);
3041 expr = new SimpleName (name.Basename, loc);
3044 FullNamedExpression fne = expr.ResolveAsTypeStep (ec, false);
3049 return new TypeExpression (type, loc);
3054 /// This class denotes an expression which evaluates to a member
3055 /// of a struct or a class.
3057 public abstract class MemberExpr : Expression
3059 protected bool is_base;
3062 /// The name of this member.
3064 public abstract string Name {
3069 // When base.member is used
3071 public bool IsBase {
3072 get { return is_base; }
3073 set { is_base = value; }
3077 /// Whether this is an instance member.
3079 public abstract bool IsInstance {
3084 /// Whether this is a static member.
3086 public abstract bool IsStatic {
3091 /// The type which declares this member.
3093 public abstract Type DeclaringType {
3098 /// The instance expression associated with this member, if it's a
3099 /// non-static member.
3101 public Expression InstanceExpression;
3103 public static void error176 (Location loc, string name)
3105 Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
3106 "with an instance reference, qualify it with a type name instead", name);
3109 public static void Error_BaseAccessInExpressionTree (Location loc)
3111 Report.Error (831, loc, "An expression tree may not contain a base access");
3114 // TODO: possible optimalization
3115 // Cache resolved constant result in FieldBuilder <-> expression map
3116 public virtual MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3117 SimpleName original)
3121 // original == null || original.Resolve (...) ==> left
3124 if (left is TypeExpr) {
3125 left = left.ResolveAsTypeTerminal (ec, true);
3130 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3138 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3141 return ResolveExtensionMemberAccess (left);
3144 InstanceExpression = left;
3148 protected virtual MemberExpr ResolveExtensionMemberAccess (Expression left)
3150 error176 (loc, GetSignatureForError ());
3154 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3159 if (InstanceExpression == EmptyExpression.Null) {
3160 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3164 if (InstanceExpression.Type.IsValueType) {
3165 if (InstanceExpression is IMemoryLocation) {
3166 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
3168 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
3169 InstanceExpression.Emit (ec);
3171 t.AddressOf (ec, AddressOp.Store);
3174 InstanceExpression.Emit (ec);
3176 if (prepare_for_load)
3177 ec.ig.Emit (OpCodes.Dup);
3180 public virtual void SetTypeArguments (TypeArguments ta)
3182 // TODO: need to get correct member type
3183 Report.Error (307, loc, "The property `{0}' cannot be used with type arguments",
3184 GetSignatureForError ());
3189 /// Represents group of extension methods
3191 public class ExtensionMethodGroupExpr : MethodGroupExpr
3193 readonly NamespaceEntry namespace_entry;
3194 public Expression ExtensionExpression;
3195 Argument extension_argument;
3197 public ExtensionMethodGroupExpr (ArrayList list, NamespaceEntry n, Type extensionType, Location l)
3198 : base (list, extensionType, l)
3200 this.namespace_entry = n;
3203 public override bool IsStatic {
3204 get { return true; }
3207 public bool IsTopLevel {
3208 get { return namespace_entry == null; }
3211 public override void EmitArguments (EmitContext ec, ArrayList arguments)
3213 if (arguments == null)
3214 arguments = new ArrayList (1);
3215 arguments.Insert (0, extension_argument);
3216 base.EmitArguments (ec, arguments);
3219 public override void EmitCall (EmitContext ec, ArrayList arguments)
3221 if (arguments == null)
3222 arguments = new ArrayList (1);
3223 arguments.Insert (0, extension_argument);
3224 base.EmitCall (ec, arguments);
3227 public override MethodGroupExpr OverloadResolve (EmitContext ec, ref ArrayList arguments, bool may_fail, Location loc)
3229 if (arguments == null)
3230 arguments = new ArrayList (1);
3232 arguments.Insert (0, new Argument (ExtensionExpression));
3233 MethodGroupExpr mg = ResolveOverloadExtensions (ec, arguments, namespace_entry, loc);
3235 // Store resolved argument and restore original arguments
3237 ((ExtensionMethodGroupExpr)mg).extension_argument = (Argument)arguments [0];
3238 arguments.RemoveAt (0);
3243 MethodGroupExpr ResolveOverloadExtensions (EmitContext ec, ArrayList arguments, NamespaceEntry ns, Location loc)
3245 // Use normal resolve rules
3246 MethodGroupExpr mg = base.OverloadResolve (ec, ref arguments, ns != null, loc);
3254 ExtensionMethodGroupExpr e = ns.LookupExtensionMethod (type, null, Name, loc);
3256 return base.OverloadResolve (ec, ref arguments, false, loc);
3258 e.ExtensionExpression = ExtensionExpression;
3259 return e.ResolveOverloadExtensions (ec, arguments, e.namespace_entry, loc);
3264 /// MethodGroupExpr represents a group of method candidates which
3265 /// can be resolved to the best method overload
3267 public class MethodGroupExpr : MemberExpr
3269 public interface IErrorHandler
3271 bool NoExactMatch (EmitContext ec, MethodBase method);
3274 public IErrorHandler CustomErrorHandler;
3275 public MethodBase [] Methods;
3276 MethodBase best_candidate;
3277 // TODO: make private
3278 public TypeArguments type_arguments;
3279 bool identical_type_name;
3282 public MethodGroupExpr (MemberInfo [] mi, Type type, Location l)
3285 Methods = new MethodBase [mi.Length];
3286 mi.CopyTo (Methods, 0);
3289 public MethodGroupExpr (ArrayList list, Type type, Location l)
3293 Methods = (MethodBase[])list.ToArray (typeof (MethodBase));
3295 foreach (MemberInfo m in list){
3296 if (!(m is MethodBase)){
3297 Console.WriteLine ("Name " + m.Name);
3298 Console.WriteLine ("Found a: " + m.GetType ().FullName);
3307 protected MethodGroupExpr (Type type, Location loc)
3310 eclass = ExprClass.MethodGroup;
3314 public override Type DeclaringType {
3317 // We assume that the top-level type is in the end
3319 return Methods [Methods.Length - 1].DeclaringType;
3320 //return Methods [0].DeclaringType;
3324 public Type DelegateType {
3326 delegate_type = value;
3330 public bool IdenticalTypeName {
3332 return identical_type_name;
3336 identical_type_name = value;
3340 public override string GetSignatureForError ()
3342 if (best_candidate != null)
3343 return TypeManager.CSharpSignature (best_candidate);
3345 return TypeManager.CSharpSignature (Methods [0]);
3348 public override string Name {
3350 return Methods [0].Name;
3354 public override bool IsInstance {
3356 if (best_candidate != null)
3357 return !best_candidate.IsStatic;
3359 foreach (MethodBase mb in Methods)
3367 public override bool IsStatic {
3369 if (best_candidate != null)
3370 return best_candidate.IsStatic;
3372 foreach (MethodBase mb in Methods)
3380 public static explicit operator ConstructorInfo (MethodGroupExpr mg)
3382 return (ConstructorInfo)mg.best_candidate;
3385 public static explicit operator MethodInfo (MethodGroupExpr mg)
3387 return (MethodInfo)mg.best_candidate;
3391 // 7.4.3.3 Better conversion from expression
3392 // Returns : 1 if a->p is better,
3393 // 2 if a->q is better,
3394 // 0 if neither is better
3396 static int BetterExpressionConversion (EmitContext ec, Argument a, Type p, Type q)
3398 Type argument_type = TypeManager.TypeToCoreType (a.Type);
3399 if (argument_type == TypeManager.anonymous_method_type && RootContext.Version > LanguageVersion.ISO_2) {
3401 // Uwrap delegate from Expression<T>
3403 if (TypeManager.DropGenericTypeArguments (p) == TypeManager.expression_type) {
3404 p = TypeManager.GetTypeArguments (p) [0];
3406 if (TypeManager.DropGenericTypeArguments (q) == TypeManager.expression_type) {
3407 q = TypeManager.GetTypeArguments (q) [0];
3410 p = Delegate.GetInvokeMethod (null, p).ReturnType;
3411 q = Delegate.GetInvokeMethod (null, q).ReturnType;
3413 if (argument_type == p)
3416 if (argument_type == q)
3420 return BetterTypeConversion (ec, p, q);
3424 // 7.4.3.4 Better conversion from type
3426 public static int BetterTypeConversion (EmitContext ec, Type p, Type q)
3428 if (p == null || q == null)
3429 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3431 if (p == TypeManager.int32_type) {
3432 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3434 } else if (p == TypeManager.int64_type) {
3435 if (q == TypeManager.uint64_type)
3437 } else if (p == TypeManager.sbyte_type) {
3438 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3439 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3441 } else if (p == TypeManager.short_type) {
3442 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3443 q == TypeManager.uint64_type)
3447 if (q == TypeManager.int32_type) {
3448 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3450 } if (q == TypeManager.int64_type) {
3451 if (p == TypeManager.uint64_type)
3453 } else if (q == TypeManager.sbyte_type) {
3454 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3455 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3457 } if (q == TypeManager.short_type) {
3458 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3459 p == TypeManager.uint64_type)
3463 // TODO: this is expensive
3464 Expression p_tmp = new EmptyExpression (p);
3465 Expression q_tmp = new EmptyExpression (q);
3467 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3468 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3470 if (p_to_q && !q_to_p)
3473 if (q_to_p && !p_to_q)
3480 /// Determines "Better function" between candidate
3481 /// and the current best match
3484 /// Returns a boolean indicating :
3485 /// false if candidate ain't better
3486 /// true if candidate is better than the current best match
3488 static bool BetterFunction (EmitContext ec, ArrayList args, int argument_count,
3489 MethodBase candidate, bool candidate_params,
3490 MethodBase best, bool best_params)
3492 ParameterData candidate_pd = TypeManager.GetParameterData (candidate);
3493 ParameterData best_pd = TypeManager.GetParameterData (best);
3495 bool better_at_least_one = false;
3497 for (int j = 0, c_idx = 0, b_idx = 0; j < argument_count; ++j, ++c_idx, ++b_idx)
3499 Argument a = (Argument) args [j];
3501 Type ct = TypeManager.TypeToCoreType (candidate_pd.ParameterType (c_idx));
3502 Type bt = TypeManager.TypeToCoreType (best_pd.ParameterType (b_idx));
3504 if (candidate_params && candidate_pd.ParameterModifier (c_idx) == Parameter.Modifier.PARAMS)
3506 ct = TypeManager.GetElementType (ct);
3510 if (best_params && best_pd.ParameterModifier (b_idx) == Parameter.Modifier.PARAMS)
3512 bt = TypeManager.GetElementType (bt);
3520 int result = BetterExpressionConversion (ec, a, ct, bt);
3522 // for each argument, the conversion to 'ct' should be no worse than
3523 // the conversion to 'bt'.
3527 // for at least one argument, the conversion to 'ct' should be better than
3528 // the conversion to 'bt'.
3530 better_at_least_one = true;
3533 if (better_at_least_one)
3537 // This handles the case
3539 // Add (float f1, float f2, float f3);
3540 // Add (params decimal [] foo);
3542 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3543 // first candidate would've chosen as better.
3549 // The two methods have equal parameter types. Now apply tie-breaking rules
3551 if (TypeManager.IsGenericMethod (best) && !TypeManager.IsGenericMethod (candidate))
3553 if (!TypeManager.IsGenericMethod (best) && TypeManager.IsGenericMethod (candidate))
3557 // This handles the following cases:
3559 // Trim () is better than Trim (params char[] chars)
3560 // Concat (string s1, string s2, string s3) is better than
3561 // Concat (string s1, params string [] srest)
3562 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3564 if (!candidate_params && best_params)
3566 if (candidate_params && !best_params)
3569 int candidate_param_count = candidate_pd.Count;
3570 int best_param_count = best_pd.Count;
3572 if (candidate_param_count != best_param_count)
3573 // can only happen if (candidate_params && best_params)
3574 return candidate_param_count > best_param_count;
3577 // now, both methods have the same number of parameters, and the parameters have the same types
3578 // Pick the "more specific" signature
3581 MethodBase orig_candidate = TypeManager.DropGenericMethodArguments (candidate);
3582 MethodBase orig_best = TypeManager.DropGenericMethodArguments (best);
3584 ParameterData orig_candidate_pd = TypeManager.GetParameterData (orig_candidate);
3585 ParameterData orig_best_pd = TypeManager.GetParameterData (orig_best);
3587 bool specific_at_least_once = false;
3588 for (int j = 0; j < candidate_param_count; ++j)
3590 Type ct = TypeManager.TypeToCoreType (orig_candidate_pd.ParameterType (j));
3591 Type bt = TypeManager.TypeToCoreType (orig_best_pd.ParameterType (j));
3594 Type specific = MoreSpecific (ct, bt);
3598 specific_at_least_once = true;
3601 if (specific_at_least_once)
3604 // FIXME: handle lifted operators
3610 protected override MemberExpr ResolveExtensionMemberAccess (Expression left)
3613 return base.ResolveExtensionMemberAccess (left);
3616 // When left side is an expression and at least one candidate method is
3617 // static, it can be extension method
3619 InstanceExpression = left;
3623 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3624 SimpleName original)
3626 if (!(left is TypeExpr) &&
3627 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3628 IdenticalTypeName = true;
3630 return base.ResolveMemberAccess (ec, left, loc, original);
3633 public override Expression CreateExpressionTree (EmitContext ec)
3635 if (best_candidate == null) {
3636 Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3640 if (best_candidate.IsConstructor)
3641 return new TypeOfConstructorInfo (best_candidate, loc);
3643 IMethodData md = TypeManager.GetMethod (best_candidate);
3644 if (md != null && md.IsExcluded ())
3645 Report.Error (765, loc,
3646 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3648 return new TypeOfMethodInfo (best_candidate, loc);
3651 override public Expression DoResolve (EmitContext ec)
3653 if (InstanceExpression != null) {
3654 InstanceExpression = InstanceExpression.DoResolve (ec);
3655 if (InstanceExpression == null)
3662 public void ReportUsageError ()
3664 Report.Error (654, loc, "Method `" + DeclaringType + "." +
3665 Name + "()' is referenced without parentheses");
3668 override public void Emit (EmitContext ec)
3670 ReportUsageError ();
3673 public virtual void EmitArguments (EmitContext ec, ArrayList arguments)
3675 Invocation.EmitArguments (ec, arguments, false, null);
3678 public virtual void EmitCall (EmitContext ec, ArrayList arguments)
3680 Invocation.EmitCall (ec, IsBase, InstanceExpression, best_candidate, arguments, loc);
3683 protected virtual void Error_InvalidArguments (EmitContext ec, Location loc, int idx, MethodBase method,
3684 Argument a, ParameterData expected_par, Type paramType)
3686 if (a is CollectionElementInitializer.ElementInitializerArgument) {
3687 Report.SymbolRelatedToPreviousError (method);
3688 if ((expected_par.ParameterModifier (idx) & Parameter.Modifier.ISBYREF) != 0) {
3689 Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
3690 TypeManager.CSharpSignature (method));
3693 Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
3694 TypeManager.CSharpSignature (method));
3695 } else if (delegate_type == null) {
3696 Report.SymbolRelatedToPreviousError (method);
3697 Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
3698 TypeManager.CSharpSignature (method));
3700 Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
3701 TypeManager.CSharpName (delegate_type));
3703 Parameter.Modifier mod = expected_par.ParameterModifier (idx);
3705 string index = (idx + 1).ToString ();
3706 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
3707 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
3708 if ((mod & Parameter.Modifier.ISBYREF) == 0)
3709 Report.Error (1615, loc, "Argument `{0}' should not be passed with the `{1}' keyword",
3710 index, Parameter.GetModifierSignature (a.Modifier));
3712 Report.Error (1620, loc, "Argument `{0}' must be passed with the `{1}' keyword",
3713 index, Parameter.GetModifierSignature (mod));
3715 string p1 = a.GetSignatureForError ();
3716 string p2 = TypeManager.CSharpName (paramType);
3719 Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
3720 Report.SymbolRelatedToPreviousError (a.Expr.Type);
3721 Report.SymbolRelatedToPreviousError (paramType);
3723 Report.Error (1503, loc, "Argument {0}: Cannot convert type `{1}' to `{2}'", index, p1, p2);
3727 public override void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl)
3729 Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3730 Name, TypeManager.CSharpName (target));
3733 protected virtual int GetApplicableParametersCount (MethodBase method, ParameterData parameters)
3735 return parameters.Count;
3738 public static bool IsAncestralType (Type first_type, Type second_type)
3740 return first_type != second_type &&
3741 (TypeManager.IsSubclassOf (second_type, first_type) ||
3742 TypeManager.ImplementsInterface (second_type, first_type));
3746 /// Determines if the candidate method is applicable (section 14.4.2.1)
3747 /// to the given set of arguments
3748 /// A return value rates candidate method compatibility,
3749 /// 0 = the best, int.MaxValue = the worst
3751 public int IsApplicable (EmitContext ec,
3752 ArrayList arguments, int arg_count, ref MethodBase method, ref bool params_expanded_form)
3754 MethodBase candidate = method;
3756 ParameterData pd = TypeManager.GetParameterData (candidate);
3757 int param_count = GetApplicableParametersCount (candidate, pd);
3759 if (arg_count != param_count) {
3761 return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
3762 if (arg_count < param_count - 1)
3763 return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
3768 // 1. Handle generic method using type arguments when specified or type inference
3770 if (TypeManager.IsGenericMethod (candidate)) {
3771 if (type_arguments != null) {
3772 Type [] g_args = candidate.GetGenericArguments ();
3773 if (g_args.Length != type_arguments.Count)
3774 return int.MaxValue - 20000 + Math.Abs (type_arguments.Count - g_args.Length);
3776 // TODO: Don't create new method, create Parameters only
3777 method = ((MethodInfo) candidate).MakeGenericMethod (type_arguments.Arguments);
3779 pd = TypeManager.GetParameterData (candidate);
3781 int score = TypeManager.InferTypeArguments (ec, arguments, ref candidate);
3783 return score - 20000;
3785 if (TypeManager.IsGenericMethodDefinition (candidate))
3786 throw new InternalErrorException ("A generic method `{0}' definition took part in overload resolution",
3787 TypeManager.CSharpSignature (candidate));
3789 pd = TypeManager.GetParameterData (candidate);
3792 if (type_arguments != null)
3793 return int.MaxValue - 15000;
3798 // 2. Each argument has to be implicitly convertible to method parameter
3801 Parameter.Modifier p_mod = 0;
3803 for (int i = 0; i < arg_count; i++) {
3804 Argument a = (Argument) arguments [i];
3805 Parameter.Modifier a_mod = a.Modifier &
3806 ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3808 if (p_mod != Parameter.Modifier.PARAMS) {
3809 p_mod = pd.ParameterModifier (i) & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3811 if (p_mod == Parameter.Modifier.ARGLIST) {
3812 if (a.Type == TypeManager.runtime_argument_handle_type)
3818 pt = pd.ParameterType (i);
3820 params_expanded_form = true;
3824 if (!params_expanded_form)
3825 score = IsArgumentCompatible (ec, a_mod, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
3827 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0) {
3828 // It can be applicable in expanded form
3829 score = IsArgumentCompatible (ec, a_mod, a, 0, pt.GetElementType ());
3831 params_expanded_form = true;
3835 if (params_expanded_form)
3837 return (arg_count - i) * 2 + score;
3841 if (arg_count != param_count)
3842 params_expanded_form = true;
3847 int IsArgumentCompatible (EmitContext ec, Parameter.Modifier arg_mod, Argument argument, Parameter.Modifier param_mod, Type parameter)
3850 // Types have to be identical when ref or out modifer is used
3852 if (arg_mod != 0 || param_mod != 0) {
3853 if (TypeManager.HasElementType (parameter))
3854 parameter = parameter.GetElementType ();
3856 Type a_type = argument.Type;
3857 if (TypeManager.HasElementType (a_type))
3858 a_type = a_type.GetElementType ();
3860 if (a_type != parameter)
3866 if (delegate_type != null ?
3867 !Delegate.IsTypeCovariant (argument.Expr, parameter) :
3868 !Convert.ImplicitConversionExists (ec, argument.Expr, parameter))
3871 if (arg_mod != param_mod)
3877 public static bool IsOverride (MethodBase cand_method, MethodBase base_method)
3879 if (!IsAncestralType (base_method.DeclaringType, cand_method.DeclaringType))
3882 ParameterData cand_pd = TypeManager.GetParameterData (cand_method);
3883 ParameterData base_pd = TypeManager.GetParameterData (base_method);
3885 if (cand_pd.Count != base_pd.Count)
3888 for (int j = 0; j < cand_pd.Count; ++j)
3890 Parameter.Modifier cm = cand_pd.ParameterModifier (j);
3891 Parameter.Modifier bm = base_pd.ParameterModifier (j);
3892 Type ct = TypeManager.TypeToCoreType (cand_pd.ParameterType (j));
3893 Type bt = TypeManager.TypeToCoreType (base_pd.ParameterType (j));
3895 if (cm != bm || ct != bt)
3902 public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2, Location loc)
3904 MemberInfo [] miset;
3905 MethodGroupExpr union;
3910 return (MethodGroupExpr) mg2;
3913 return (MethodGroupExpr) mg1;
3916 MethodGroupExpr left_set = null, right_set = null;
3917 int length1 = 0, length2 = 0;
3919 left_set = (MethodGroupExpr) mg1;
3920 length1 = left_set.Methods.Length;
3922 right_set = (MethodGroupExpr) mg2;
3923 length2 = right_set.Methods.Length;
3925 ArrayList common = new ArrayList ();
3927 foreach (MethodBase r in right_set.Methods){
3928 if (TypeManager.ArrayContainsMethod (left_set.Methods, r))
3932 miset = new MemberInfo [length1 + length2 - common.Count];
3933 left_set.Methods.CopyTo (miset, 0);
3937 foreach (MethodBase r in right_set.Methods) {
3938 if (!common.Contains (r))
3942 union = new MethodGroupExpr (miset, mg1.Type, loc);
3947 static Type MoreSpecific (Type p, Type q)
3949 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
3951 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
3954 if (TypeManager.HasElementType (p))
3956 Type pe = TypeManager.GetElementType (p);
3957 Type qe = TypeManager.GetElementType (q);
3958 Type specific = MoreSpecific (pe, qe);
3964 else if (TypeManager.IsGenericType (p))
3966 Type[] pargs = TypeManager.GetTypeArguments (p);
3967 Type[] qargs = TypeManager.GetTypeArguments (q);
3969 bool p_specific_at_least_once = false;
3970 bool q_specific_at_least_once = false;
3972 for (int i = 0; i < pargs.Length; i++)
3974 Type specific = MoreSpecific (pargs [i], qargs [i]);
3975 if (specific == pargs [i])
3976 p_specific_at_least_once = true;
3977 if (specific == qargs [i])
3978 q_specific_at_least_once = true;
3981 if (p_specific_at_least_once && !q_specific_at_least_once)
3983 if (!p_specific_at_least_once && q_specific_at_least_once)
3991 /// Find the Applicable Function Members (7.4.2.1)
3993 /// me: Method Group expression with the members to select.
3994 /// it might contain constructors or methods (or anything
3995 /// that maps to a method).
3997 /// Arguments: ArrayList containing resolved Argument objects.
3999 /// loc: The location if we want an error to be reported, or a Null
4000 /// location for "probing" purposes.
4002 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4003 /// that is the best match of me on Arguments.
4006 public virtual MethodGroupExpr OverloadResolve (EmitContext ec, ref ArrayList Arguments,
4007 bool may_fail, Location loc)
4009 bool method_params = false;
4010 Type applicable_type = null;
4012 ArrayList candidates = new ArrayList (2);
4013 ArrayList candidate_overrides = null;
4016 // Used to keep a map between the candidate
4017 // and whether it is being considered in its
4018 // normal or expanded form
4020 // false is normal form, true is expanded form
4022 Hashtable candidate_to_form = null;
4024 if (Arguments != null)
4025 arg_count = Arguments.Count;
4027 if (RootContext.Version == LanguageVersion.ISO_1 && Name == "Invoke" && TypeManager.IsDelegateType (DeclaringType)) {
4029 Report.Error (1533, loc, "Invoke cannot be called directly on a delegate");
4033 int nmethods = Methods.Length;
4037 // Methods marked 'override' don't take part in 'applicable_type'
4038 // computation, nor in the actual overload resolution.
4039 // However, they still need to be emitted instead of a base virtual method.
4040 // So, we salt them away into the 'candidate_overrides' array.
4042 // In case of reflected methods, we replace each overriding method with
4043 // its corresponding base virtual method. This is to improve compatibility
4044 // with non-C# libraries which change the visibility of overrides (#75636)
4047 for (int i = 0; i < Methods.Length; ++i) {
4048 MethodBase m = Methods [i];
4049 if (TypeManager.IsOverride (m)) {
4050 if (candidate_overrides == null)
4051 candidate_overrides = new ArrayList ();
4052 candidate_overrides.Add (m);
4053 m = TypeManager.TryGetBaseDefinition (m);
4062 // Enable message recording, it's used mainly by lambda expressions
4064 Report.IMessageRecorder msg_recorder = new Report.MessageRecorder ();
4065 Report.IMessageRecorder prev_recorder = Report.SetMessageRecorder (msg_recorder);
4068 // First we construct the set of applicable methods
4070 bool is_sorted = true;
4071 int best_candidate_rate = int.MaxValue;
4072 for (int i = 0; i < nmethods; i++) {
4073 Type decl_type = Methods [i].DeclaringType;
4076 // If we have already found an applicable method
4077 // we eliminate all base types (Section 14.5.5.1)
4079 if (applicable_type != null && IsAncestralType (decl_type, applicable_type))
4083 // Check if candidate is applicable (section 14.4.2.1)
4085 bool params_expanded_form = false;
4086 int candidate_rate = IsApplicable (ec, Arguments, arg_count, ref Methods [i], ref params_expanded_form);
4088 if (candidate_rate < best_candidate_rate) {
4089 best_candidate_rate = candidate_rate;
4090 best_candidate = Methods [i];
4093 if (params_expanded_form) {
4094 if (candidate_to_form == null)
4095 candidate_to_form = new PtrHashtable ();
4096 MethodBase candidate = Methods [i];
4097 candidate_to_form [candidate] = candidate;
4100 if (candidate_rate != 0) {
4101 if (msg_recorder != null)
4102 msg_recorder.EndSession ();
4106 msg_recorder = null;
4107 candidates.Add (Methods [i]);
4109 if (applicable_type == null)
4110 applicable_type = decl_type;
4111 else if (applicable_type != decl_type) {
4113 if (IsAncestralType (applicable_type, decl_type))
4114 applicable_type = decl_type;
4118 Report.SetMessageRecorder (prev_recorder);
4119 if (msg_recorder != null && msg_recorder.PrintMessages ())
4122 int candidate_top = candidates.Count;
4124 if (applicable_type == null) {
4126 // When we found a top level method which does not match and it's
4127 // not an extension method. We start extension methods lookup from here
4129 if (InstanceExpression != null) {
4130 ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (type, Name, loc);
4131 if (ex_method_lookup != null) {
4132 ex_method_lookup.ExtensionExpression = InstanceExpression;
4133 ex_method_lookup.SetTypeArguments (type_arguments);
4134 return ex_method_lookup.OverloadResolve (ec, ref Arguments, may_fail, loc);
4142 // Okay so we have failed to find exact match so we
4143 // return error info about the closest match
4145 if (best_candidate != null) {
4146 if (CustomErrorHandler != null) {
4147 if (CustomErrorHandler.NoExactMatch (ec, best_candidate))
4151 ParameterData pd = TypeManager.GetParameterData (best_candidate);
4152 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4153 if (arg_count == pd.Count || pd.HasParams) {
4154 if (TypeManager.IsGenericMethodDefinition (best_candidate)) {
4155 if (type_arguments == null) {
4156 Report.Error (411, loc,
4157 "The type arguments for method `{0}' cannot be inferred from " +
4158 "the usage. Try specifying the type arguments explicitly",
4159 TypeManager.CSharpSignature (best_candidate));
4163 Type [] g_args = TypeManager.GetGenericArguments (best_candidate);
4164 if (type_arguments.Count != g_args.Length) {
4165 Report.SymbolRelatedToPreviousError (best_candidate);
4166 Report.Error (305, loc, "Using the generic method `{0}' requires `{1}' type argument(s)",
4167 TypeManager.CSharpSignature (best_candidate),
4168 g_args.Length.ToString ());
4172 if (type_arguments != null && !TypeManager.IsGenericMethod (best_candidate)) {
4173 Namespace.Error_TypeArgumentsCannotBeUsed (best_candidate, loc);
4178 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate, cand_params, may_fail, loc))
4183 if (almost_matched_members.Count != 0) {
4184 Error_MemberLookupFailed (ec.ContainerType, type, type, ".ctor",
4185 null, MemberTypes.Constructor, AllBindingFlags);
4190 // We failed to find any method with correct argument count
4192 if (Name == ConstructorInfo.ConstructorName) {
4193 Report.SymbolRelatedToPreviousError (type);
4194 Report.Error (1729, loc,
4195 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4196 TypeManager.CSharpName (type), arg_count);
4198 Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4199 Name, arg_count.ToString ());
4207 // At this point, applicable_type is _one_ of the most derived types
4208 // in the set of types containing the methods in this MethodGroup.
4209 // Filter the candidates so that they only contain methods from the
4210 // most derived types.
4213 int finalized = 0; // Number of finalized candidates
4216 // Invariant: applicable_type is a most derived type
4218 // We'll try to complete Section 14.5.5.1 for 'applicable_type' by
4219 // eliminating all it's base types. At the same time, we'll also move
4220 // every unrelated type to the end of the array, and pick the next
4221 // 'applicable_type'.
4223 Type next_applicable_type = null;
4224 int j = finalized; // where to put the next finalized candidate
4225 int k = finalized; // where to put the next undiscarded candidate
4226 for (int i = finalized; i < candidate_top; ++i) {
4227 MethodBase candidate = (MethodBase) candidates [i];
4228 Type decl_type = candidate.DeclaringType;
4230 if (decl_type == applicable_type) {
4231 candidates [k++] = candidates [j];
4232 candidates [j++] = candidates [i];
4236 if (IsAncestralType (decl_type, applicable_type))
4239 if (next_applicable_type != null &&
4240 IsAncestralType (decl_type, next_applicable_type))
4243 candidates [k++] = candidates [i];
4245 if (next_applicable_type == null ||
4246 IsAncestralType (next_applicable_type, decl_type))
4247 next_applicable_type = decl_type;
4250 applicable_type = next_applicable_type;
4253 } while (applicable_type != null);
4257 // Now we actually find the best method
4260 best_candidate = (MethodBase) candidates [0];
4261 if (delegate_type == null)
4262 method_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4264 for (int ix = 1; ix < candidate_top; ix++) {
4265 MethodBase candidate = (MethodBase) candidates [ix];
4267 if (candidate == best_candidate)
4270 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4272 if (BetterFunction (ec, Arguments, arg_count,
4273 candidate, cand_params,
4274 best_candidate, method_params)) {
4275 best_candidate = candidate;
4276 method_params = cand_params;
4280 // Now check that there are no ambiguities i.e the selected method
4281 // should be better than all the others
4283 MethodBase ambiguous = null;
4284 for (int ix = 1; ix < candidate_top; ix++) {
4285 MethodBase candidate = (MethodBase) candidates [ix];
4287 if (candidate == best_candidate)
4290 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4291 if (!BetterFunction (ec, Arguments, arg_count,
4292 best_candidate, method_params,
4293 candidate, cand_params))
4296 Report.SymbolRelatedToPreviousError (candidate);
4297 ambiguous = candidate;
4301 if (ambiguous != null) {
4302 Report.SymbolRelatedToPreviousError (best_candidate);
4303 Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4304 TypeManager.CSharpSignature (ambiguous), TypeManager.CSharpSignature (best_candidate));
4309 // If the method is a virtual function, pick an override closer to the LHS type.
4311 if (!IsBase && best_candidate.IsVirtual) {
4312 if (TypeManager.IsOverride (best_candidate))
4313 throw new InternalErrorException (
4314 "Should not happen. An 'override' method took part in overload resolution: " + best_candidate);
4316 if (candidate_overrides != null) {
4317 Type[] gen_args = null;
4318 bool gen_override = false;
4319 if (TypeManager.IsGenericMethod (best_candidate))
4320 gen_args = TypeManager.GetGenericArguments (best_candidate);
4322 foreach (MethodBase candidate in candidate_overrides) {
4323 if (TypeManager.IsGenericMethod (candidate)) {
4324 if (gen_args == null)
4327 if (gen_args.Length != TypeManager.GetGenericArguments (candidate).Length)
4330 if (gen_args != null)
4334 if (IsOverride (candidate, best_candidate)) {
4335 gen_override = true;
4336 best_candidate = candidate;
4340 if (gen_override && gen_args != null) {
4342 best_candidate = ((MethodInfo) best_candidate).MakeGenericMethod (gen_args);
4349 // And now check if the arguments are all
4350 // compatible, perform conversions if
4351 // necessary etc. and return if everything is
4354 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate,
4355 method_params, may_fail, loc))
4358 if (best_candidate == null)
4361 MethodBase the_method = TypeManager.DropGenericMethodArguments (best_candidate);
4363 if (the_method.IsGenericMethodDefinition &&
4364 !ConstraintChecker.CheckConstraints (ec, the_method, best_candidate, loc))
4368 IMethodData data = TypeManager.GetMethod (the_method);
4370 data.SetMemberIsUsed ();
4375 public override void SetTypeArguments (TypeArguments ta)
4377 type_arguments = ta;
4380 public bool VerifyArgumentsCompat (EmitContext ec, ref ArrayList arguments,
4381 int arg_count, MethodBase method,
4382 bool chose_params_expanded,
4383 bool may_fail, Location loc)
4385 ParameterData pd = TypeManager.GetParameterData (method);
4387 int errors = Report.Errors;
4388 Parameter.Modifier p_mod = 0;
4390 int a_idx = 0, a_pos = 0;
4392 ArrayList params_initializers = null;
4394 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4395 a = (Argument) arguments [a_idx];
4396 if (p_mod != Parameter.Modifier.PARAMS) {
4397 p_mod = pd.ParameterModifier (a_idx);
4398 pt = pd.ParameterType (a_idx);
4400 if (p_mod == Parameter.Modifier.ARGLIST) {
4401 if (a.Type != TypeManager.runtime_argument_handle_type)
4406 if (pt.IsPointer && !ec.InUnsafe) {
4413 if (p_mod == Parameter.Modifier.PARAMS) {
4414 if (chose_params_expanded) {
4415 params_initializers = new ArrayList (arg_count - a_idx);
4416 pt = TypeManager.GetElementType (pt);
4418 } else if (p_mod != 0) {
4419 pt = TypeManager.GetElementType (pt);
4424 // Types have to be identical when ref or out modifer is used
4426 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4427 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4430 if (!TypeManager.IsEqual (a.Expr.Type, pt))
4437 if (TypeManager.IsEqual (a.Type, pt)) {
4440 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4446 // Convert params arguments to an array initializer
4448 if (params_initializers != null) {
4449 // we choose to use 'a.Expr' rather than 'conv' so that
4450 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
4451 params_initializers.Add (a.Expr);
4452 arguments.RemoveAt (a_idx--);
4457 // Update the argument with the implicit conversion
4462 // Fill not provided arguments required by params modifier
4464 if (params_initializers == null && pd.HasParams && arg_count < pd.Count && a_idx + 1 == pd.Count) {
4465 if (arguments == null)
4466 arguments = new ArrayList (1);
4468 pt = pd.Types [GetApplicableParametersCount (method, pd) - 1];
4469 pt = TypeManager.GetElementType (pt);
4470 params_initializers = new ArrayList (0);
4473 if (a_idx == arg_count) {
4475 // Append an array argument with all params arguments
4477 if (params_initializers != null) {
4478 arguments.Add (new Argument (
4479 new ArrayCreation (new TypeExpression (pt, loc), "[]",
4480 params_initializers, loc).Resolve (ec)));
4485 if (!may_fail && Report.Errors == errors) {
4486 if (CustomErrorHandler != null)
4487 CustomErrorHandler.NoExactMatch (ec, best_candidate);
4489 Error_InvalidArguments (ec, loc, a_pos, method, a, pd, pt);
4495 public class ConstantExpr : MemberExpr
4499 public ConstantExpr (FieldInfo constant, Location loc)
4501 this.constant = constant;
4505 public override string Name {
4506 get { throw new NotImplementedException (); }
4509 public override bool IsInstance {
4510 get { return !IsStatic; }
4513 public override bool IsStatic {
4514 get { return constant.IsStatic; }
4517 public override Type DeclaringType {
4518 get { return constant.DeclaringType; }
4521 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc, SimpleName original)
4523 constant = TypeManager.GetGenericFieldDefinition (constant);
4525 IConstant ic = TypeManager.GetConstant (constant);
4527 if (constant.IsLiteral) {
4528 ic = new ExternalConstant (constant);
4530 ic = ExternalConstant.CreateDecimal (constant);
4531 // HACK: decimal field was not resolved as constant
4533 return new FieldExpr (constant, loc).ResolveMemberAccess (ec, left, loc, original);
4535 TypeManager.RegisterConstant (constant, ic);
4538 return base.ResolveMemberAccess (ec, left, loc, original);
4541 public override Expression CreateExpressionTree (EmitContext ec)
4543 throw new NotSupportedException ("ET");
4546 public override Expression DoResolve (EmitContext ec)
4548 IConstant ic = TypeManager.GetConstant (constant);
4549 if (ic.ResolveValue ()) {
4550 if (!ec.IsInObsoleteScope)
4551 ic.CheckObsoleteness (loc);
4554 return ic.CreateConstantReference (loc);
4557 public override void Emit (EmitContext ec)
4559 throw new NotSupportedException ();
4562 public override string GetSignatureForError ()
4564 return TypeManager.GetFullNameSignature (constant);
4569 /// Fully resolved expression that evaluates to a Field
4571 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariable {
4572 public readonly FieldInfo FieldInfo;
4573 VariableInfo variable_info;
4575 LocalTemporary temp;
4577 bool in_initializer;
4579 public FieldExpr (FieldInfo fi, Location l, bool in_initializer):
4582 this.in_initializer = in_initializer;
4585 public FieldExpr (FieldInfo fi, Location l)
4588 eclass = ExprClass.Variable;
4589 type = TypeManager.TypeToCoreType (fi.FieldType);
4593 public override string Name {
4595 return FieldInfo.Name;
4599 public override bool IsInstance {
4601 return !FieldInfo.IsStatic;
4605 public override bool IsStatic {
4607 return FieldInfo.IsStatic;
4611 public override Type DeclaringType {
4613 return FieldInfo.DeclaringType;
4617 public override string GetSignatureForError ()
4619 return TypeManager.GetFullNameSignature (FieldInfo);
4622 public VariableInfo VariableInfo {
4624 return variable_info;
4628 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
4629 SimpleName original)
4631 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
4632 Type t = fi.FieldType;
4634 if (t.IsPointer && !ec.InUnsafe) {
4638 return base.ResolveMemberAccess (ec, left, loc, original);
4641 public override Expression CreateExpressionTree (EmitContext ec)
4643 Expression instance;
4644 if (InstanceExpression == null) {
4645 instance = new NullLiteral (loc);
4647 instance = InstanceExpression.CreateExpressionTree (ec);
4650 ArrayList args = new ArrayList (2);
4651 args.Add (new Argument (instance));
4652 args.Add (new Argument (CreateTypeOfExpression ()));
4653 return CreateExpressionFactoryCall ("Field", args);
4656 public Expression CreateTypeOfExpression ()
4658 return new TypeOfField (FieldInfo, loc);
4661 override public Expression DoResolve (EmitContext ec)
4663 return DoResolve (ec, false, false);
4666 Expression DoResolve (EmitContext ec, bool lvalue_instance, bool out_access)
4668 if (!FieldInfo.IsStatic){
4669 if (InstanceExpression == null){
4671 // This can happen when referencing an instance field using
4672 // a fully qualified type expression: TypeName.InstanceField = xxx
4674 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4678 // Resolve the field's instance expression while flow analysis is turned
4679 // off: when accessing a field "a.b", we must check whether the field
4680 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4682 if (lvalue_instance) {
4683 using (ec.With (EmitContext.Flags.DoFlowAnalysis, false)) {
4684 Expression right_side =
4685 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4686 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side, loc);
4689 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
4690 InstanceExpression = InstanceExpression.Resolve (ec, rf);
4693 if (InstanceExpression == null)
4696 using (ec.Set (EmitContext.Flags.OmitStructFlowAnalysis)) {
4697 InstanceExpression.CheckMarshalByRefAccess (ec);
4701 if (!in_initializer && !ec.IsInFieldInitializer) {
4702 ObsoleteAttribute oa;
4703 FieldBase f = TypeManager.GetField (FieldInfo);
4705 if (!ec.IsInObsoleteScope)
4706 f.CheckObsoleteness (loc);
4708 // To be sure that type is external because we do not register generated fields
4709 } else if (!(FieldInfo.DeclaringType is TypeBuilder)) {
4710 oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
4712 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
4716 AnonymousContainer am = ec.CurrentAnonymousMethod;
4718 if (!FieldInfo.IsStatic){
4719 if (!am.IsIterator && (ec.TypeContainer is Struct)){
4720 Report.Error (1673, loc,
4721 "Anonymous methods inside structs cannot access instance members of `{0}'. Consider copying `{0}' to a local variable outside the anonymous method and using the local instead",
4728 IFixedBuffer fb = AttributeTester.GetFixedBuffer (FieldInfo);
4730 if (!ec.InFixedInitializer && ec.ContainerType.IsValueType) {
4731 Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4734 if (InstanceExpression.eclass != ExprClass.Variable) {
4735 Report.SymbolRelatedToPreviousError (FieldInfo);
4736 Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4737 TypeManager.GetFullNameSignature (FieldInfo));
4740 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4743 // If the instance expression is a local variable or parameter.
4744 IVariable var = InstanceExpression as IVariable;
4745 if (var == null || var.VariableInfo == null)
4748 VariableInfo vi = var.VariableInfo;
4749 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
4752 variable_info = vi.GetSubStruct (FieldInfo.Name);
4756 static readonly int [] codes = {
4757 191, // instance, write access
4758 192, // instance, out access
4759 198, // static, write access
4760 199, // static, out access
4761 1648, // member of value instance, write access
4762 1649, // member of value instance, out access
4763 1650, // member of value static, write access
4764 1651 // member of value static, out access
4767 static readonly string [] msgs = {
4768 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4769 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4770 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4771 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4772 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4773 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4774 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4775 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4778 // The return value is always null. Returning a value simplifies calling code.
4779 Expression Report_AssignToReadonly (Expression right_side)
4782 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4786 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4788 Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4793 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4795 IVariable var = InstanceExpression as IVariable;
4796 if (var != null && var.VariableInfo != null)
4797 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
4799 bool lvalue_instance = !FieldInfo.IsStatic && FieldInfo.DeclaringType.IsValueType;
4800 bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
4802 Expression e = DoResolve (ec, lvalue_instance, out_access);
4807 FieldBase fb = TypeManager.GetField (FieldInfo);
4811 if (FieldInfo.IsInitOnly) {
4812 // InitOnly fields can only be assigned in constructors or initializers
4813 if (!ec.IsInFieldInitializer && !ec.IsConstructor)
4814 return Report_AssignToReadonly (right_side);
4816 if (ec.IsConstructor) {
4817 Type ctype = ec.TypeContainer.CurrentType;
4819 ctype = ec.ContainerType;
4821 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4822 if (!TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
4823 return Report_AssignToReadonly (right_side);
4824 // static InitOnly fields cannot be assigned-to in an instance constructor
4825 if (IsStatic && !ec.IsStatic)
4826 return Report_AssignToReadonly (right_side);
4827 // instance constructors can't modify InitOnly fields of other instances of the same type
4828 if (!IsStatic && !(InstanceExpression is This))
4829 return Report_AssignToReadonly (right_side);
4833 if (right_side == EmptyExpression.OutAccess &&
4834 !IsStatic && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type)) {
4835 Report.SymbolRelatedToPreviousError (DeclaringType);
4836 Report.Warning (197, 1, loc,
4837 "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",
4838 GetSignatureForError ());
4844 bool is_marshal_by_ref ()
4846 return !IsStatic && Type.IsValueType && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type);
4849 public override void CheckMarshalByRefAccess (EmitContext ec)
4851 if (is_marshal_by_ref () && !(InstanceExpression is This)) {
4852 Report.SymbolRelatedToPreviousError (DeclaringType);
4853 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",
4854 GetSignatureForError ());
4858 public override int GetHashCode ()
4860 return FieldInfo.GetHashCode ();
4863 public bool IsFixed {
4865 IVariable variable = InstanceExpression as IVariable;
4866 // A variable of the form V.I is fixed when V is a fixed variable of a struct type.
4867 // We defer the InstanceExpression check after the variable check to avoid a
4868 // separate null check on InstanceExpression.
4869 return variable != null && InstanceExpression.Type.IsValueType && variable.IsFixed;
4873 public override bool Equals (object obj)
4875 FieldExpr fe = obj as FieldExpr;
4879 if (FieldInfo != fe.FieldInfo)
4882 if (InstanceExpression == null || fe.InstanceExpression == null)
4885 return InstanceExpression.Equals (fe.InstanceExpression);
4888 public void Emit (EmitContext ec, bool leave_copy)
4890 ILGenerator ig = ec.ig;
4891 bool is_volatile = false;
4893 FieldBase f = TypeManager.GetField (FieldInfo);
4895 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4898 f.SetMemberIsUsed ();
4901 if (FieldInfo.IsStatic){
4903 ig.Emit (OpCodes.Volatile);
4905 ig.Emit (OpCodes.Ldsfld, FieldInfo);
4908 EmitInstance (ec, false);
4910 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
4912 ig.Emit (OpCodes.Ldflda, FieldInfo);
4913 ig.Emit (OpCodes.Ldflda, ff.Element);
4916 ig.Emit (OpCodes.Volatile);
4918 ig.Emit (OpCodes.Ldfld, FieldInfo);
4923 ec.ig.Emit (OpCodes.Dup);
4924 if (!FieldInfo.IsStatic) {
4925 temp = new LocalTemporary (this.Type);
4931 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4933 FieldAttributes fa = FieldInfo.Attributes;
4934 bool is_static = (fa & FieldAttributes.Static) != 0;
4935 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
4936 ILGenerator ig = ec.ig;
4938 if (is_readonly && !ec.IsConstructor){
4939 Report_AssignToReadonly (source);
4943 prepared = prepare_for_load;
4944 EmitInstance (ec, prepared);
4948 ec.ig.Emit (OpCodes.Dup);
4949 if (!FieldInfo.IsStatic) {
4950 temp = new LocalTemporary (this.Type);
4955 FieldBase f = TypeManager.GetField (FieldInfo);
4957 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4958 ig.Emit (OpCodes.Volatile);
4964 ig.Emit (OpCodes.Stsfld, FieldInfo);
4966 ig.Emit (OpCodes.Stfld, FieldInfo);
4974 public override void Emit (EmitContext ec)
4979 public override void EmitSideEffect (EmitContext ec)
4981 FieldBase f = TypeManager.GetField (FieldInfo);
4982 bool is_volatile = f != null && (f.ModFlags & Modifiers.VOLATILE) != 0;
4984 if (is_volatile || is_marshal_by_ref ())
4985 base.EmitSideEffect (ec);
4988 public void AddressOf (EmitContext ec, AddressOp mode)
4990 ILGenerator ig = ec.ig;
4992 FieldBase f = TypeManager.GetField (FieldInfo);
4994 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
4995 Report.Warning (420, 1, loc, "`{0}': A volatile field references will not be treated as volatile",
4996 f.GetSignatureForError ());
4999 if ((mode & AddressOp.Store) != 0)
5001 if ((mode & AddressOp.Load) != 0)
5002 f.SetMemberIsUsed ();
5006 // Handle initonly fields specially: make a copy and then
5007 // get the address of the copy.
5010 if (FieldInfo.IsInitOnly){
5012 if (ec.IsConstructor){
5013 if (FieldInfo.IsStatic){
5025 local = ig.DeclareLocal (type);
5026 ig.Emit (OpCodes.Stloc, local);
5027 ig.Emit (OpCodes.Ldloca, local);
5032 if (FieldInfo.IsStatic){
5033 ig.Emit (OpCodes.Ldsflda, FieldInfo);
5036 EmitInstance (ec, false);
5037 ig.Emit (OpCodes.Ldflda, FieldInfo);
5044 /// Expression that evaluates to a Property. The Assign class
5045 /// might set the `Value' expression if we are in an assignment.
5047 /// This is not an LValue because we need to re-write the expression, we
5048 /// can not take data from the stack and store it.
5050 public class PropertyExpr : MemberExpr, IAssignMethod {
5051 public readonly PropertyInfo PropertyInfo;
5052 MethodInfo getter, setter;
5057 LocalTemporary temp;
5060 public PropertyExpr (Type container_type, PropertyInfo pi, Location l)
5063 eclass = ExprClass.PropertyAccess;
5067 type = TypeManager.TypeToCoreType (pi.PropertyType);
5069 ResolveAccessors (container_type);
5072 public override string Name {
5074 return PropertyInfo.Name;
5078 public override bool IsInstance {
5084 public override bool IsStatic {
5090 public override Expression CreateExpressionTree (EmitContext ec)
5093 if (IsSingleDimensionalArrayLength ()) {
5094 args = new ArrayList (1);
5095 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5096 return CreateExpressionFactoryCall ("ArrayLength", args);
5100 Error_BaseAccessInExpressionTree (loc);
5104 args = new ArrayList (2);
5105 if (InstanceExpression == null)
5106 args.Add (new Argument (new NullLiteral (loc)));
5108 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5109 args.Add (new Argument (new TypeOfMethodInfo (getter, loc)));
5110 return CreateExpressionFactoryCall ("Property", args);
5113 public Expression CreateSetterTypeOfExpression ()
5115 return new TypeOfMethodInfo (setter, loc);
5118 public override Type DeclaringType {
5120 return PropertyInfo.DeclaringType;
5124 public override string GetSignatureForError ()
5126 return TypeManager.GetFullNameSignature (PropertyInfo);
5129 void FindAccessors (Type invocation_type)
5131 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
5132 BindingFlags.Static | BindingFlags.Instance |
5133 BindingFlags.DeclaredOnly;
5135 Type current = PropertyInfo.DeclaringType;
5136 for (; current != null; current = current.BaseType) {
5137 MemberInfo[] group = TypeManager.MemberLookup (
5138 invocation_type, invocation_type, current,
5139 MemberTypes.Property, flags, PropertyInfo.Name, null);
5144 if (group.Length != 1)
5145 // Oooops, can this ever happen ?
5148 PropertyInfo pi = (PropertyInfo) group [0];
5151 getter = pi.GetGetMethod (true);
5154 setter = pi.GetSetMethod (true);
5156 MethodInfo accessor = getter != null ? getter : setter;
5158 if (!accessor.IsVirtual)
5164 // We also perform the permission checking here, as the PropertyInfo does not
5165 // hold the information for the accessibility of its setter/getter
5167 // TODO: Refactor to use some kind of cache together with GetPropertyFromAccessor
5168 void ResolveAccessors (Type container_type)
5170 FindAccessors (container_type);
5172 if (getter != null) {
5173 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
5174 IMethodData md = TypeManager.GetMethod (the_getter);
5176 md.SetMemberIsUsed ();
5178 is_static = getter.IsStatic;
5181 if (setter != null) {
5182 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
5183 IMethodData md = TypeManager.GetMethod (the_setter);
5185 md.SetMemberIsUsed ();
5187 is_static = setter.IsStatic;
5191 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
5194 InstanceExpression = null;
5198 if (InstanceExpression == null) {
5199 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5203 InstanceExpression = InstanceExpression.DoResolve (ec);
5204 if (lvalue_instance && InstanceExpression != null)
5205 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
5207 if (InstanceExpression == null)
5210 InstanceExpression.CheckMarshalByRefAccess (ec);
5212 if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) &&
5213 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
5214 !TypeManager.IsNestedChildOf (ec.ContainerType, InstanceExpression.Type) &&
5215 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.ContainerType)) {
5216 Report.SymbolRelatedToPreviousError (PropertyInfo);
5217 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
5224 void Error_PropertyNotFound (MethodInfo mi, bool getter)
5226 // TODO: correctly we should compare arguments but it will lead to bigger changes
5227 if (mi is MethodBuilder) {
5228 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
5232 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
5234 ParameterData iparams = TypeManager.GetParameterData (mi);
5235 sig.Append (getter ? "get_" : "set_");
5237 sig.Append (iparams.GetSignatureForError ());
5239 Report.SymbolRelatedToPreviousError (mi);
5240 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
5241 Name, sig.ToString ());
5244 public bool IsAccessibleFrom (Type invocation_type, bool lvalue)
5247 MethodInfo accessor = lvalue ? setter : getter;
5248 if (accessor == null && lvalue)
5250 return accessor != null && IsAccessorAccessible (invocation_type, accessor, out dummy);
5253 bool IsSingleDimensionalArrayLength ()
5255 if (DeclaringType != TypeManager.array_type || getter == null || Name != "Length")
5258 string t_name = InstanceExpression.Type.Name;
5259 int t_name_len = t_name.Length;
5260 return t_name_len > 2 && t_name [t_name_len - 2] == '[' && t_name [t_name_len - 3] != ']';
5263 override public Expression DoResolve (EmitContext ec)
5268 if (getter != null){
5269 if (TypeManager.GetParameterData (getter).Count != 0){
5270 Error_PropertyNotFound (getter, true);
5275 if (getter == null){
5277 // The following condition happens if the PropertyExpr was
5278 // created, but is invalid (ie, the property is inaccessible),
5279 // and we did not want to embed the knowledge about this in
5280 // the caller routine. This only avoids double error reporting.
5285 if (InstanceExpression != EmptyExpression.Null) {
5286 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5287 TypeManager.GetFullNameSignature (PropertyInfo));
5292 bool must_do_cs1540_check = false;
5293 if (getter != null &&
5294 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
5295 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
5296 if (pm != null && pm.HasCustomAccessModifier) {
5297 Report.SymbolRelatedToPreviousError (pm);
5298 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5299 TypeManager.CSharpSignature (getter));
5302 Report.SymbolRelatedToPreviousError (getter);
5303 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
5308 if (!InstanceResolve (ec, false, must_do_cs1540_check))
5312 // Only base will allow this invocation to happen.
5314 if (IsBase && getter.IsAbstract) {
5315 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5319 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
5329 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
5331 if (right_side == EmptyExpression.OutAccess) {
5332 if (ec.CurrentBlock.Toplevel.GetTransparentIdentifier (PropertyInfo.Name) != null) {
5333 Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5336 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as `ref' or `out' parameter",
5337 GetSignatureForError ());
5342 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5343 Error_CannotModifyIntermediateExpressionValue (ec);
5346 if (setter == null){
5348 // The following condition happens if the PropertyExpr was
5349 // created, but is invalid (ie, the property is inaccessible),
5350 // and we did not want to embed the knowledge about this in
5351 // the caller routine. This only avoids double error reporting.
5355 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
5356 GetSignatureForError ());
5360 if (TypeManager.GetParameterData (setter).Count != 1){
5361 Error_PropertyNotFound (setter, false);
5365 bool must_do_cs1540_check;
5366 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
5367 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
5368 if (pm != null && pm.HasCustomAccessModifier) {
5369 Report.SymbolRelatedToPreviousError (pm);
5370 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5371 TypeManager.CSharpSignature (setter));
5374 Report.SymbolRelatedToPreviousError (setter);
5375 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
5380 if (!InstanceResolve (ec, PropertyInfo.DeclaringType.IsValueType, must_do_cs1540_check))
5384 // Only base will allow this invocation to happen.
5386 if (IsBase && setter.IsAbstract){
5387 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5394 public override void Emit (EmitContext ec)
5399 public void Emit (EmitContext ec, bool leave_copy)
5402 // Special case: length of single dimension array property is turned into ldlen
5404 if (IsSingleDimensionalArrayLength ()) {
5406 EmitInstance (ec, false);
5407 ec.ig.Emit (OpCodes.Ldlen);
5408 ec.ig.Emit (OpCodes.Conv_I4);
5412 Invocation.EmitCall (ec, IsBase, InstanceExpression, getter, null, loc, prepared, false);
5415 ec.ig.Emit (OpCodes.Dup);
5417 temp = new LocalTemporary (this.Type);
5424 // Implements the IAssignMethod interface for assignments
5426 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5428 Expression my_source = source;
5430 if (prepare_for_load) {
5435 ec.ig.Emit (OpCodes.Dup);
5437 temp = new LocalTemporary (this.Type);
5441 } else if (leave_copy) {
5443 temp = new LocalTemporary (this.Type);
5448 ArrayList args = new ArrayList (1);
5449 args.Add (new Argument (my_source, Argument.AType.Expression));
5451 Invocation.EmitCall (ec, IsBase, InstanceExpression, setter, args, loc, false, prepared);
5461 /// Fully resolved expression that evaluates to an Event
5463 public class EventExpr : MemberExpr {
5464 public readonly EventInfo EventInfo;
5467 MethodInfo add_accessor, remove_accessor;
5469 public EventExpr (EventInfo ei, Location loc)
5473 eclass = ExprClass.EventAccess;
5475 add_accessor = TypeManager.GetAddMethod (ei);
5476 remove_accessor = TypeManager.GetRemoveMethod (ei);
5477 if (add_accessor.IsStatic || remove_accessor.IsStatic)
5480 if (EventInfo is MyEventBuilder){
5481 MyEventBuilder eb = (MyEventBuilder) EventInfo;
5482 type = eb.EventType;
5485 type = EventInfo.EventHandlerType;
5488 public override string Name {
5490 return EventInfo.Name;
5494 public override bool IsInstance {
5500 public override bool IsStatic {
5506 public override Type DeclaringType {
5508 return EventInfo.DeclaringType;
5512 void Error_AssignmentEventOnly ()
5514 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5515 GetSignatureForError ());
5518 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
5519 SimpleName original)
5522 // If the event is local to this class, we transform ourselves into a FieldExpr
5525 if (EventInfo.DeclaringType == ec.ContainerType ||
5526 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
5527 EventField mi = TypeManager.GetEventField (EventInfo);
5530 if (!ec.IsInObsoleteScope)
5531 mi.CheckObsoleteness (loc);
5533 if ((mi.ModFlags & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0 && !ec.IsInCompoundAssignment)
5534 Error_AssignmentEventOnly ();
5536 FieldExpr ml = new FieldExpr (mi.FieldBuilder, loc);
5538 InstanceExpression = null;
5540 return ml.ResolveMemberAccess (ec, left, loc, original);
5544 if (left is This && !ec.IsInCompoundAssignment)
5545 Error_AssignmentEventOnly ();
5547 return base.ResolveMemberAccess (ec, left, loc, original);
5550 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
5553 InstanceExpression = null;
5557 if (InstanceExpression == null) {
5558 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5562 InstanceExpression = InstanceExpression.DoResolve (ec);
5563 if (InstanceExpression == null)
5566 if (IsBase && add_accessor.IsAbstract) {
5567 Error_CannotCallAbstractBase(TypeManager.CSharpSignature(add_accessor));
5572 // This is using the same mechanism as the CS1540 check in PropertyExpr.
5573 // However, in the Event case, we reported a CS0122 instead.
5575 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
5576 InstanceExpression.Type != ec.ContainerType &&
5577 TypeManager.IsSubclassOf (ec.ContainerType, InstanceExpression.Type)) {
5578 Report.SymbolRelatedToPreviousError (EventInfo);
5579 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5586 public bool IsAccessibleFrom (Type invocation_type)
5589 return IsAccessorAccessible (invocation_type, add_accessor, out dummy) &&
5590 IsAccessorAccessible (invocation_type, remove_accessor, out dummy);
5593 public override Expression CreateExpressionTree (EmitContext ec)
5595 throw new NotSupportedException ("ET");
5598 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5600 // contexts where an LValue is valid have already devolved to FieldExprs
5601 Error_CannotAssign ();
5605 public override Expression DoResolve (EmitContext ec)
5607 bool must_do_cs1540_check;
5608 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
5609 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
5610 Report.SymbolRelatedToPreviousError (EventInfo);
5611 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5615 if (!InstanceResolve (ec, must_do_cs1540_check))
5618 if (!ec.IsInCompoundAssignment) {
5619 Error_CannotAssign ();
5626 public override void Emit (EmitContext ec)
5628 Error_CannotAssign ();
5631 public void Error_CannotAssign ()
5633 Report.Error (70, loc,
5634 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
5635 GetSignatureForError (), TypeManager.CSharpName (EventInfo.DeclaringType));
5638 public override string GetSignatureForError ()
5640 return TypeManager.CSharpSignature (EventInfo);
5643 public void EmitAddOrRemove (EmitContext ec, bool is_add, Expression source)
5645 ArrayList args = new ArrayList (1);
5646 args.Add (new Argument (source, Argument.AType.Expression));
5647 Invocation.EmitCall (ec, IsBase, InstanceExpression, is_add ? add_accessor : remove_accessor, args, loc);
5651 public class TemporaryVariable : Expression, IMemoryLocation
5656 public TemporaryVariable (Type type, Location loc)
5660 eclass = ExprClass.Value;
5663 public override Expression CreateExpressionTree (EmitContext ec)
5665 throw new NotSupportedException ("ET");
5668 public override Expression DoResolve (EmitContext ec)
5673 TypeExpr te = new TypeExpression (type, loc);
5674 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
5675 if (!li.Resolve (ec))
5678 if (ec.MustCaptureVariable (li)) {
5679 ScopeInfo scope = li.Block.CreateScopeInfo ();
5680 var = scope.AddLocal (li);
5687 public Variable Variable {
5688 get { return var != null ? var : li.Variable; }
5691 public override void Emit (EmitContext ec)
5693 Variable.EmitInstance (ec);
5697 public void EmitLoadAddress (EmitContext ec)
5699 Variable.EmitInstance (ec);
5700 Variable.EmitAddressOf (ec);
5703 public void Store (EmitContext ec, Expression right_side)
5705 Variable.EmitInstance (ec);
5706 right_side.Emit (ec);
5707 Variable.EmitAssign (ec);
5710 public void EmitThis (EmitContext ec)
5712 Variable.EmitInstance (ec);
5715 public void EmitStore (EmitContext ec)
5717 Variable.EmitAssign (ec);
5720 public void AddressOf (EmitContext ec, AddressOp mode)
5722 EmitLoadAddress (ec);
5727 /// Handles `var' contextual keyword; var becomes a keyword only
5728 /// if no type called var exists in a variable scope
5730 public class VarExpr : SimpleName
5732 // Used for error reporting only
5733 ArrayList initializer;
5735 public VarExpr (Location loc)
5740 public ArrayList VariableInitializer {
5742 this.initializer = value;
5746 public bool InferType (EmitContext ec, Expression right_side)
5749 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
5751 type = right_side.Type;
5752 if (type == TypeManager.null_type || type == TypeManager.void_type || type == TypeManager.anonymous_method_type) {
5753 Report.Error (815, loc, "An implicitly typed local variable declaration cannot be initialized with `{0}'",
5754 right_side.GetSignatureForError ());
5758 eclass = ExprClass.Variable;
5762 protected override void Error_TypeOrNamespaceNotFound (IResolveContext ec)
5764 Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");
5767 public override TypeExpr ResolveAsContextualType (IResolveContext rc, bool silent)
5769 TypeExpr te = base.ResolveAsContextualType (rc, true);
5773 if (initializer == null)
5776 if (initializer.Count > 1) {
5777 Location loc = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [1]).Location;
5778 Report.Error (819, loc, "An implicitly typed local variable declaration cannot include multiple declarators");
5783 Expression variable_initializer = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [0]).expression_or_array_initializer;
5784 if (variable_initializer == null) {
5785 Report.Error (818, loc, "An implicitly typed local variable declarator must include an initializer");