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 // (C) 2001, 2002, 2003 Ximian, Inc.
12 namespace Mono.CSharp {
14 using System.Collections;
15 using System.Diagnostics;
16 using System.Reflection;
17 using System.Reflection.Emit;
21 /// The ExprClass class contains the is used to pass the
22 /// classification of an expression (value, variable, namespace,
23 /// type, method group, property access, event access, indexer access,
26 public enum ExprClass : byte {
41 /// This is used to tell Resolve in which types of expressions we're
45 public enum ResolveFlags {
46 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
49 // Returns a type expression.
52 // Returns a method group.
55 // Mask of all the expression class flags.
58 // Disable control flow analysis while resolving the expression.
59 // This is used when resolving the instance expression of a field expression.
60 DisableFlowAnalysis = 8,
62 // Set if this is resolving the first part of a MemberAccess.
65 // Disable control flow analysis _of struct_ while resolving the expression.
66 // This is used when resolving the instance expression of a field expression.
67 DisableStructFlowAnalysis = 32,
72 // This is just as a hint to AddressOf of what will be done with the
75 public enum AddressOp {
82 /// This interface is implemented by variables
84 public interface IMemoryLocation {
86 /// The AddressOf method should generate code that loads
87 /// the address of the object and leaves it on the stack.
89 /// The `mode' argument is used to notify the expression
90 /// of whether this will be used to read from the address or
91 /// write to the address.
93 /// This is just a hint that can be used to provide good error
94 /// reporting, and should have no other side effects.
96 void AddressOf (EmitContext ec, AddressOp mode);
100 /// This interface is implemented by variables
102 public interface IVariable {
103 VariableInfo VariableInfo {
111 /// Base class for expressions
113 public abstract class Expression {
114 public ExprClass eclass;
116 protected Location loc;
120 set { type = value; }
123 public virtual Location Location {
128 /// Utility wrapper routine for Error, just to beautify the code
130 public void Error (int error, string s)
132 Report.Error (error, loc, s);
135 // Not nice but we have broken hierarchy.
136 public virtual void CheckMarshalByRefAccess (EmitContext ec)
140 public virtual bool GetAttributableValue (Type value_type, out object value)
142 Attribute.Error_AttributeArgumentNotValid (loc);
147 public virtual string GetSignatureForError ()
149 return TypeManager.CSharpName (type);
152 public static bool IsAccessorAccessible (Type invocation_type, MethodInfo mi, out bool must_do_cs1540_check)
154 MethodAttributes ma = mi.Attributes & MethodAttributes.MemberAccessMask;
156 must_do_cs1540_check = false; // by default we do not check for this
158 if (ma == MethodAttributes.Public)
162 // If only accessible to the current class or children
164 if (ma == MethodAttributes.Private)
165 return TypeManager.IsPrivateAccessible (invocation_type, mi.DeclaringType) ||
166 TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType);
168 if (TypeManager.IsThisOrFriendAssembly (mi.DeclaringType.Assembly)) {
169 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamORAssem)
172 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamANDAssem)
176 // Family and FamANDAssem require that we derive.
177 // FamORAssem requires that we derive if in different assemblies.
178 if (!TypeManager.IsNestedFamilyAccessible (invocation_type, mi.DeclaringType))
181 if (!TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType))
182 must_do_cs1540_check = true;
187 public virtual bool IsNull {
194 /// Performs semantic analysis on the Expression
198 /// The Resolve method is invoked to perform the semantic analysis
201 /// The return value is an expression (it can be the
202 /// same expression in some cases) or a new
203 /// expression that better represents this node.
205 /// For example, optimizations of Unary (LiteralInt)
206 /// would return a new LiteralInt with a negated
209 /// If there is an error during semantic analysis,
210 /// then an error should be reported (using Report)
211 /// and a null value should be returned.
213 /// There are two side effects expected from calling
214 /// Resolve(): the the field variable "eclass" should
215 /// be set to any value of the enumeration
216 /// `ExprClass' and the type variable should be set
217 /// to a valid type (this is the type of the
220 public abstract Expression DoResolve (EmitContext ec);
222 public virtual Expression DoResolveLValue (EmitContext ec, Expression right_side)
228 // This is used if the expression should be resolved as a type or namespace name.
229 // the default implementation fails.
231 public virtual FullNamedExpression ResolveAsTypeStep (IResolveContext rc, bool silent)
235 EmitContext ec = rc as EmitContext;
239 e.Error_UnexpectedKind (ResolveFlags.Type, loc);
245 // C# 3.0 introduced contextual keywords (var) which behaves like a type if type with
246 // same name exists or as a keyword when no type was found
248 public virtual TypeExpr ResolveAsContextualType (IResolveContext rc, bool silent)
250 return ResolveAsTypeTerminal (rc, silent);
254 // This is used to resolve the expression as a type, a null
255 // value will be returned if the expression is not a type
258 public virtual TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
260 TypeExpr te = ResolveAsBaseTerminal (ec, silent);
264 if (!silent) { // && !(te is TypeParameterExpr)) {
265 ObsoleteAttribute obsolete_attr = AttributeTester.GetObsoleteAttribute (te.Type);
266 if (obsolete_attr != null && !ec.IsInObsoleteScope) {
267 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location);
271 // Constrains don't need to be checked for overrides
272 GenericMethod gm = ec.GenericDeclContainer as GenericMethod;
273 if (gm != null && (gm.ModFlags & Modifiers.OVERRIDE) != 0) {
278 ConstructedType ct = te as ConstructedType;
279 if ((ct != null) && !ct.CheckConstraints (ec))
285 public TypeExpr ResolveAsBaseTerminal (IResolveContext ec, bool silent)
287 int errors = Report.Errors;
289 FullNamedExpression fne = ResolveAsTypeStep (ec, silent);
294 if (fne.eclass != ExprClass.Type) {
295 if (!silent && errors == Report.Errors)
296 fne.Error_UnexpectedKind (null, "type", loc);
300 TypeExpr te = fne as TypeExpr;
302 if (!te.CheckAccessLevel (ec.DeclContainer)) {
303 Report.SymbolRelatedToPreviousError (te.Type);
304 ErrorIsInaccesible (loc, TypeManager.CSharpName (te.Type));
312 public static void ErrorIsInaccesible (Location loc, string name)
314 Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", name);
317 protected static void Error_CannotAccessProtected (Location loc, MemberInfo m, Type qualifier, Type container)
319 Report.Error (1540, loc, "Cannot access protected member `{0}' via a qualifier of type `{1}'."
320 + " The qualifier must be of type `{2}' or derived from it",
321 TypeManager.GetFullNameSignature (m),
322 TypeManager.CSharpName (qualifier),
323 TypeManager.CSharpName (container));
327 public static void Error_InvalidExpressionStatement (Location loc)
329 Report.Error (201, loc, "Only assignment, call, increment, decrement, and new object " +
330 "expressions can be used as a statement");
333 public void Error_InvalidExpressionStatement ()
335 Error_InvalidExpressionStatement (loc);
338 protected void Error_CannotAssign (string to, string roContext)
340 Report.Error (1656, loc, "Cannot assign to `{0}' because it is a `{1}'",
344 public static void Error_VoidInvalidInTheContext (Location loc)
346 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
349 public virtual void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl)
351 // The error was already reported as CS1660
352 if (type == TypeManager.anonymous_method_type)
355 if (TypeManager.IsGenericParameter (Type) && TypeManager.IsGenericParameter (target) && type.Name == target.Name) {
357 string sig1 = type.DeclaringMethod == null ?
358 TypeManager.CSharpName (type.DeclaringType) :
359 TypeManager.CSharpSignature (type.DeclaringMethod);
360 string sig2 = target.DeclaringMethod == null ?
361 TypeManager.CSharpName (target.DeclaringType) :
362 TypeManager.CSharpSignature (target.DeclaringMethod);
363 Report.ExtraInformation (loc,
365 "The generic parameter `{0}' of `{1}' cannot be converted to the generic parameter `{0}' of `{2}' (in the previous ",
366 Type.Name, sig1, sig2));
368 } else if (Type.FullName == target.FullName){
369 Report.ExtraInformation (loc,
371 "The type `{0}' has two conflicting definitions, one comes from `{1}' and the other from `{2}' (in the previous ",
372 Type.FullName, Type.Assembly.FullName, target.Assembly.FullName));
376 Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
377 TypeManager.CSharpName (type), TypeManager.CSharpName (target));
381 Expression e = (this is EnumConstant) ? ((EnumConstant)this).Child : this;
382 bool b = Convert.ExplicitNumericConversion (e, target) != null;
385 Convert.ExplicitReferenceConversionExists (Type, target) ||
386 Convert.ExplicitUnsafe (e, target) != null ||
387 (ec != null && Convert.ExplicitUserConversion (ec, this, target, Location.Null) != null))
389 Report.Error (266, loc, "Cannot implicitly convert type `{0}' to `{1}'. " +
390 "An explicit conversion exists (are you missing a cast?)",
391 TypeManager.CSharpName (Type), TypeManager.CSharpName (target));
395 if (Type != TypeManager.string_type && this is Constant && !(this is EmptyConstantCast)) {
396 Report.Error (31, loc, "Constant value `{0}' cannot be converted to a `{1}'",
397 ((Constant)(this)).GetValue ().ToString (), TypeManager.CSharpName (target));
401 Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
402 TypeManager.CSharpName (type),
403 TypeManager.CSharpName (target));
406 protected void Error_VariableIsUsedBeforeItIsDeclared (string name)
408 Report.Error (841, loc, "The variable `{0}' cannot be used before it is declared",
412 protected virtual void Error_TypeDoesNotContainDefinition (Type type, string name)
414 Error_TypeDoesNotContainDefinition (loc, type, name);
417 public static void Error_TypeDoesNotContainDefinition (Location loc, Type type, string name)
419 Report.SymbolRelatedToPreviousError (type);
420 Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
421 TypeManager.CSharpName (type), name);
424 protected static void Error_ValueAssignment (Location loc)
426 Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
429 ResolveFlags ExprClassToResolveFlags
434 case ExprClass.Namespace:
435 return ResolveFlags.Type;
437 case ExprClass.MethodGroup:
438 return ResolveFlags.MethodGroup;
440 case ExprClass.Value:
441 case ExprClass.Variable:
442 case ExprClass.PropertyAccess:
443 case ExprClass.EventAccess:
444 case ExprClass.IndexerAccess:
445 return ResolveFlags.VariableOrValue;
448 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
454 /// Resolves an expression and performs semantic analysis on it.
458 /// Currently Resolve wraps DoResolve to perform sanity
459 /// checking and assertion checking on what we expect from Resolve.
461 public Expression Resolve (EmitContext ec, ResolveFlags flags)
463 if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type)
464 return ResolveAsTypeStep (ec, false);
466 bool do_flow_analysis = ec.DoFlowAnalysis;
467 bool omit_struct_analysis = ec.OmitStructFlowAnalysis;
468 if ((flags & ResolveFlags.DisableFlowAnalysis) != 0)
469 do_flow_analysis = false;
470 if ((flags & ResolveFlags.DisableStructFlowAnalysis) != 0)
471 omit_struct_analysis = true;
474 using (ec.WithFlowAnalysis (do_flow_analysis, omit_struct_analysis)) {
475 if (this is SimpleName) {
476 bool intermediate = (flags & ResolveFlags.Intermediate) == ResolveFlags.Intermediate;
477 e = ((SimpleName) this).DoResolve (ec, intermediate);
486 if ((flags & e.ExprClassToResolveFlags) == 0) {
487 e.Error_UnexpectedKind (flags, loc);
491 if (e.type == null && !(e is Namespace)) {
492 throw new Exception (
493 "Expression " + e.GetType () +
494 " did not set its type after Resolve\n" +
495 "called from: " + this.GetType ());
502 /// Resolves an expression and performs semantic analysis on it.
504 public Expression Resolve (EmitContext ec)
506 Expression e = Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
508 if (e != null && e.eclass == ExprClass.MethodGroup && RootContext.Version == LanguageVersion.ISO_1) {
509 ((MethodGroupExpr) e).ReportUsageError ();
515 public Constant ResolveAsConstant (EmitContext ec, MemberCore mc)
517 Expression e = Resolve (ec);
521 Constant c = e as Constant;
525 Const.Error_ExpressionMustBeConstant (loc, mc.GetSignatureForError ());
530 /// Resolves an expression for LValue assignment
534 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
535 /// checking and assertion checking on what we expect from Resolve
537 public Expression ResolveLValue (EmitContext ec, Expression right_side, Location loc)
539 int errors = Report.Errors;
540 bool out_access = right_side == EmptyExpression.OutAccess;
542 Expression e = DoResolveLValue (ec, right_side);
544 if (e != null && out_access && !(e is IMemoryLocation)) {
545 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
546 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
548 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
549 // e.GetType () + " " + e.GetSignatureForError ());
554 if (errors == Report.Errors) {
556 Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
558 Error_ValueAssignment (loc);
563 if (e.eclass == ExprClass.Invalid)
564 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
566 if (e.eclass == ExprClass.MethodGroup) {
567 ((MethodGroupExpr) e).ReportUsageError ();
571 if ((e.type == null) && !(e is ConstructedType))
572 throw new Exception ("Expression " + e + " did not set its type after Resolve");
578 /// Emits the code for the expression
582 /// The Emit method is invoked to generate the code
583 /// for the expression.
585 public abstract void Emit (EmitContext ec);
587 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
590 ec.ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
593 public virtual void EmitSideEffect (EmitContext ec)
596 ec.ig.Emit (OpCodes.Pop);
600 /// Protected constructor. Only derivate types should
601 /// be able to be created
604 protected Expression ()
606 eclass = ExprClass.Invalid;
611 /// Returns a fully formed expression after a MemberLookup
614 public static Expression ExprClassFromMemberInfo (Type container_type, MemberInfo mi, Location loc)
617 return new EventExpr ((EventInfo) mi, loc);
618 else if (mi is FieldInfo) {
619 FieldInfo fi = (FieldInfo) mi;
620 if (fi.IsLiteral || (fi.IsInitOnly && fi.FieldType == TypeManager.decimal_type))
621 return new ConstantExpr (fi, loc);
622 return new FieldExpr (fi, loc);
623 } else if (mi is PropertyInfo)
624 return new PropertyExpr (container_type, (PropertyInfo) mi, loc);
625 else if (mi is Type) {
626 return new TypeExpression ((System.Type) mi, loc);
632 protected static ArrayList almost_matched_members = new ArrayList (4);
635 // FIXME: Probably implement a cache for (t,name,current_access_set)?
637 // This code could use some optimizations, but we need to do some
638 // measurements. For example, we could use a delegate to `flag' when
639 // something can not any longer be a method-group (because it is something
643 // If the return value is an Array, then it is an array of
646 // If the return value is an MemberInfo, it is anything, but a Method
650 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
651 // the arguments here and have MemberLookup return only the methods that
652 // match the argument count/type, unlike we are doing now (we delay this
655 // This is so we can catch correctly attempts to invoke instance methods
656 // from a static body (scan for error 120 in ResolveSimpleName).
659 // FIXME: Potential optimization, have a static ArrayList
662 public static Expression MemberLookup (Type container_type, Type queried_type, string name,
663 MemberTypes mt, BindingFlags bf, Location loc)
665 return MemberLookup (container_type, null, queried_type, name, mt, bf, loc);
669 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
670 // `qualifier_type' or null to lookup members in the current class.
673 public static Expression MemberLookup (Type container_type,
674 Type qualifier_type, Type queried_type,
675 string name, MemberTypes mt,
676 BindingFlags bf, Location loc)
678 almost_matched_members.Clear ();
680 MemberInfo [] mi = TypeManager.MemberLookup (container_type, qualifier_type,
681 queried_type, mt, bf, name, almost_matched_members);
687 bool is_interface = qualifier_type != null && qualifier_type.IsInterface;
688 ArrayList methods = new ArrayList (2);
689 ArrayList non_methods = null;
691 foreach (MemberInfo m in mi) {
692 if (m is MethodBase) {
697 if (non_methods == null) {
698 non_methods = new ArrayList (2);
703 foreach (MemberInfo n_m in non_methods) {
704 if (m.DeclaringType.IsInterface && TypeManager.ImplementsInterface (m.DeclaringType, n_m.DeclaringType))
707 Report.SymbolRelatedToPreviousError (m);
708 Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
709 TypeManager.GetFullNameSignature (m), TypeManager.GetFullNameSignature (n_m));
714 if (methods.Count == 0)
715 return ExprClassFromMemberInfo (container_type, (MemberInfo)non_methods [0], loc);
717 if (non_methods != null) {
718 MethodBase method = (MethodBase) methods [0];
719 MemberInfo non_method = (MemberInfo) non_methods [0];
720 if (method.DeclaringType == non_method.DeclaringType) {
721 // Cannot happen with C# code, but is valid in IL
722 Report.SymbolRelatedToPreviousError (method);
723 Report.SymbolRelatedToPreviousError (non_method);
724 Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
725 TypeManager.GetFullNameSignature (non_method),
726 TypeManager.CSharpSignature (method));
731 Report.SymbolRelatedToPreviousError (method);
732 Report.SymbolRelatedToPreviousError (non_method);
733 Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and non-method `{1}'. Using method `{0}'",
734 TypeManager.CSharpSignature (method), TypeManager.GetFullNameSignature (non_method));
738 return new MethodGroupExpr (methods, queried_type, loc);
741 if (mi [0] is MethodBase)
742 return new MethodGroupExpr (mi, queried_type, loc);
744 return ExprClassFromMemberInfo (container_type, mi [0], loc);
747 public const MemberTypes AllMemberTypes =
748 MemberTypes.Constructor |
752 MemberTypes.NestedType |
753 MemberTypes.Property;
755 public const BindingFlags AllBindingFlags =
756 BindingFlags.Public |
757 BindingFlags.Static |
758 BindingFlags.Instance;
760 public static Expression MemberLookup (Type container_type, Type queried_type,
761 string name, Location loc)
763 return MemberLookup (container_type, null, queried_type, name,
764 AllMemberTypes, AllBindingFlags, loc);
767 public static Expression MemberLookup (Type container_type, Type qualifier_type,
768 Type queried_type, string name, Location loc)
770 return MemberLookup (container_type, qualifier_type, queried_type,
771 name, AllMemberTypes, AllBindingFlags, loc);
774 public static MethodGroupExpr MethodLookup (Type container_type, Type queried_type,
775 string name, Location loc)
777 return (MethodGroupExpr)MemberLookup (container_type, null, queried_type, name,
778 MemberTypes.Method, AllBindingFlags, loc);
782 /// This is a wrapper for MemberLookup that is not used to "probe", but
783 /// to find a final definition. If the final definition is not found, we
784 /// look for private members and display a useful debugging message if we
787 protected Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
788 Type queried_type, string name,
789 MemberTypes mt, BindingFlags bf,
794 int errors = Report.Errors;
796 e = MemberLookup (ec.ContainerType, qualifier_type, queried_type, name, mt, bf, loc);
798 if (e != null || errors != Report.Errors)
801 // No errors were reported by MemberLookup, but there was an error.
802 return Error_MemberLookupFailed (ec.ContainerType, qualifier_type, queried_type,
806 protected virtual Expression Error_MemberLookupFailed (Type container_type, Type qualifier_type,
807 Type queried_type, string name, string class_name,
808 MemberTypes mt, BindingFlags bf)
810 if (almost_matched_members.Count != 0) {
811 for (int i = 0; i < almost_matched_members.Count; ++i) {
812 MemberInfo m = (MemberInfo) almost_matched_members [i];
813 for (int j = 0; j < i; ++j) {
814 if (m == almost_matched_members [j]) {
822 Type declaring_type = m.DeclaringType;
824 Report.SymbolRelatedToPreviousError (m);
825 if (qualifier_type == null) {
826 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
827 TypeManager.CSharpName (m.DeclaringType),
828 TypeManager.CSharpName (container_type));
830 } else if (qualifier_type != container_type &&
831 TypeManager.IsNestedFamilyAccessible (container_type, declaring_type)) {
832 // Although a derived class can access protected members of
833 // its base class it cannot do so through an instance of the
834 // base class (CS1540). If the qualifier_type is a base of the
835 // ec.ContainerType and the lookup succeeds with the latter one,
836 // then we are in this situation.
837 Error_CannotAccessProtected (loc, m, qualifier_type, container_type);
839 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (m));
842 almost_matched_members.Clear ();
846 MemberInfo[] lookup = null;
847 if (queried_type == null) {
848 class_name = "global::";
850 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
851 mt, (bf & ~BindingFlags.Public) | BindingFlags.NonPublic,
854 if (lookup != null) {
855 Report.SymbolRelatedToPreviousError (lookup [0]);
856 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (lookup [0]));
857 return Error_MemberLookupFailed (lookup);
860 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
861 AllMemberTypes, AllBindingFlags | BindingFlags.NonPublic,
865 if (lookup == null) {
866 if (class_name != null) {
867 Report.Error (103, loc, "The name `{0}' does not exist in the current context",
870 Error_TypeDoesNotContainDefinition (queried_type, name);
875 if (TypeManager.MemberLookup (queried_type, null, queried_type,
876 AllMemberTypes, AllBindingFlags |
877 BindingFlags.NonPublic, name, null) == null) {
878 if ((lookup.Length == 1) && (lookup [0] is Type)) {
879 Type t = (Type) lookup [0];
881 Report.Error (305, loc,
882 "Using the generic type `{0}' " +
883 "requires {1} type arguments",
884 TypeManager.CSharpName (t),
885 TypeManager.GetNumberOfTypeArguments (t).ToString ());
890 return Error_MemberLookupFailed (lookup);
893 protected virtual Expression Error_MemberLookupFailed (MemberInfo[] members)
895 for (int i = 0; i < members.Length; ++i) {
896 if (!(members [i] is MethodBase))
900 // By default propagate the closest candidates upwards
901 return new MethodGroupExpr (members, type, loc);
904 protected virtual void Error_NegativeArrayIndex (Location loc)
906 throw new NotImplementedException ();
910 /// Returns an expression that can be used to invoke operator true
911 /// on the expression if it exists.
913 static public Expression GetOperatorTrue (EmitContext ec, Expression e, Location loc)
915 return GetOperatorTrueOrFalse (ec, e, true, loc);
919 /// Returns an expression that can be used to invoke operator false
920 /// on the expression if it exists.
922 static public Expression GetOperatorFalse (EmitContext ec, Expression e, Location loc)
924 return GetOperatorTrueOrFalse (ec, e, false, loc);
927 static Expression GetOperatorTrueOrFalse (EmitContext ec, Expression e, bool is_true, Location loc)
929 MethodGroupExpr operator_group;
930 operator_group = MethodLookup (ec.ContainerType, e.Type, is_true ? "op_True" : "op_False", loc) as MethodGroupExpr;
931 if (operator_group == null)
934 ArrayList arguments = new ArrayList (1);
935 arguments.Add (new Argument (e, Argument.AType.Expression));
936 operator_group = operator_group.OverloadResolve (
937 ec, ref arguments, false, loc);
939 if (operator_group == null)
942 return new UserOperatorCall (operator_group, arguments, null, loc);
946 /// Resolves the expression `e' into a boolean expression: either through
947 /// an implicit conversion, or through an `operator true' invocation
949 public static Expression ResolveBoolean (EmitContext ec, Expression e, Location loc)
955 if (e.Type == TypeManager.bool_type)
958 Expression converted = Convert.ImplicitConversion (ec, e, TypeManager.bool_type, Location.Null);
960 if (converted != null)
964 // If no implicit conversion to bool exists, try using `operator true'
966 converted = Expression.GetOperatorTrue (ec, e, loc);
967 if (converted == null){
968 e.Error_ValueCannotBeConverted (ec, loc, TypeManager.bool_type, false);
974 public virtual string ExprClassName
978 case ExprClass.Invalid:
980 case ExprClass.Value:
982 case ExprClass.Variable:
984 case ExprClass.Namespace:
988 case ExprClass.MethodGroup:
989 return "method group";
990 case ExprClass.PropertyAccess:
991 return "property access";
992 case ExprClass.EventAccess:
993 return "event access";
994 case ExprClass.IndexerAccess:
995 return "indexer access";
996 case ExprClass.Nothing:
999 throw new Exception ("Should not happen");
1004 /// Reports that we were expecting `expr' to be of class `expected'
1006 public void Error_UnexpectedKind (DeclSpace ds, string expected, Location loc)
1008 Error_UnexpectedKind (ds, expected, ExprClassName, loc);
1011 public void Error_UnexpectedKind (DeclSpace ds, string expected, string was, Location loc)
1013 string name = GetSignatureForError ();
1015 name = ds.GetSignatureForError () + '.' + name;
1017 Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
1018 name, was, expected);
1021 public void Error_UnexpectedKind (ResolveFlags flags, Location loc)
1023 string [] valid = new string [4];
1026 if ((flags & ResolveFlags.VariableOrValue) != 0) {
1027 valid [count++] = "variable";
1028 valid [count++] = "value";
1031 if ((flags & ResolveFlags.Type) != 0)
1032 valid [count++] = "type";
1034 if ((flags & ResolveFlags.MethodGroup) != 0)
1035 valid [count++] = "method group";
1038 valid [count++] = "unknown";
1040 StringBuilder sb = new StringBuilder (valid [0]);
1041 for (int i = 1; i < count - 1; i++) {
1043 sb.Append (valid [i]);
1046 sb.Append ("' or `");
1047 sb.Append (valid [count - 1]);
1050 Report.Error (119, loc,
1051 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1054 public static void UnsafeError (Location loc)
1056 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1060 // Load the object from the pointer.
1062 public static void LoadFromPtr (ILGenerator ig, Type t)
1064 if (t == TypeManager.int32_type)
1065 ig.Emit (OpCodes.Ldind_I4);
1066 else if (t == TypeManager.uint32_type)
1067 ig.Emit (OpCodes.Ldind_U4);
1068 else if (t == TypeManager.short_type)
1069 ig.Emit (OpCodes.Ldind_I2);
1070 else if (t == TypeManager.ushort_type)
1071 ig.Emit (OpCodes.Ldind_U2);
1072 else if (t == TypeManager.char_type)
1073 ig.Emit (OpCodes.Ldind_U2);
1074 else if (t == TypeManager.byte_type)
1075 ig.Emit (OpCodes.Ldind_U1);
1076 else if (t == TypeManager.sbyte_type)
1077 ig.Emit (OpCodes.Ldind_I1);
1078 else if (t == TypeManager.uint64_type)
1079 ig.Emit (OpCodes.Ldind_I8);
1080 else if (t == TypeManager.int64_type)
1081 ig.Emit (OpCodes.Ldind_I8);
1082 else if (t == TypeManager.float_type)
1083 ig.Emit (OpCodes.Ldind_R4);
1084 else if (t == TypeManager.double_type)
1085 ig.Emit (OpCodes.Ldind_R8);
1086 else if (t == TypeManager.bool_type)
1087 ig.Emit (OpCodes.Ldind_I1);
1088 else if (t == TypeManager.intptr_type)
1089 ig.Emit (OpCodes.Ldind_I);
1090 else if (TypeManager.IsEnumType (t)) {
1091 if (t == TypeManager.enum_type)
1092 ig.Emit (OpCodes.Ldind_Ref);
1094 LoadFromPtr (ig, TypeManager.GetEnumUnderlyingType (t));
1095 } else if (t.IsValueType || TypeManager.IsGenericParameter (t))
1096 ig.Emit (OpCodes.Ldobj, t);
1097 else if (t.IsPointer)
1098 ig.Emit (OpCodes.Ldind_I);
1100 ig.Emit (OpCodes.Ldind_Ref);
1104 // The stack contains the pointer and the value of type `type'
1106 public static void StoreFromPtr (ILGenerator ig, Type type)
1108 if (TypeManager.IsEnumType (type))
1109 type = TypeManager.GetEnumUnderlyingType (type);
1110 if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
1111 ig.Emit (OpCodes.Stind_I4);
1112 else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
1113 ig.Emit (OpCodes.Stind_I8);
1114 else if (type == TypeManager.char_type || type == TypeManager.short_type ||
1115 type == TypeManager.ushort_type)
1116 ig.Emit (OpCodes.Stind_I2);
1117 else if (type == TypeManager.float_type)
1118 ig.Emit (OpCodes.Stind_R4);
1119 else if (type == TypeManager.double_type)
1120 ig.Emit (OpCodes.Stind_R8);
1121 else if (type == TypeManager.byte_type || type == TypeManager.sbyte_type ||
1122 type == TypeManager.bool_type)
1123 ig.Emit (OpCodes.Stind_I1);
1124 else if (type == TypeManager.intptr_type)
1125 ig.Emit (OpCodes.Stind_I);
1126 else if (type.IsValueType || TypeManager.IsGenericParameter (type))
1127 ig.Emit (OpCodes.Stobj, type);
1129 ig.Emit (OpCodes.Stind_Ref);
1133 // Returns the size of type `t' if known, otherwise, 0
1135 public static int GetTypeSize (Type t)
1137 t = TypeManager.TypeToCoreType (t);
1138 if (t == TypeManager.int32_type ||
1139 t == TypeManager.uint32_type ||
1140 t == TypeManager.float_type)
1142 else if (t == TypeManager.int64_type ||
1143 t == TypeManager.uint64_type ||
1144 t == TypeManager.double_type)
1146 else if (t == TypeManager.byte_type ||
1147 t == TypeManager.sbyte_type ||
1148 t == TypeManager.bool_type)
1150 else if (t == TypeManager.short_type ||
1151 t == TypeManager.char_type ||
1152 t == TypeManager.ushort_type)
1154 else if (t == TypeManager.decimal_type)
1160 protected void Error_CannotCallAbstractBase (string name)
1162 Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
1165 protected void Error_CannotModifyIntermediateExpressionValue (EmitContext ec)
1167 Report.SymbolRelatedToPreviousError (type);
1168 if (ec.CurrentInitializerVariable != null) {
1169 Report.Error (1918, loc, "Members of a value type property `{0}' cannot be assigned with an object initializer",
1170 GetSignatureForError ());
1172 Report.Error (1612, loc, "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
1173 GetSignatureForError ());
1178 // Converts `source' to an int, uint, long or ulong.
1180 public Expression ConvertExpressionToArrayIndex (EmitContext ec, Expression source)
1182 Expression converted;
1184 using (ec.With (EmitContext.Flags.CheckState, true)) {
1185 converted = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, source.loc);
1186 if (converted == null)
1187 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, source.loc);
1188 if (converted == null)
1189 converted = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, source.loc);
1190 if (converted == null)
1191 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, source.loc);
1193 if (converted == null) {
1194 source.Error_ValueCannotBeConverted (ec, source.loc, TypeManager.int32_type, false);
1200 // Only positive constants are allowed at compile time
1202 Constant c = converted as Constant;
1205 Error_NegativeArrayIndex (source.loc);
1210 return new ArrayIndexCast (converted).Resolve (ec);
1214 // Derived classes implement this method by cloning the fields that
1215 // could become altered during the Resolve stage
1217 // Only expressions that are created for the parser need to implement
1220 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1222 throw new NotImplementedException (
1224 "CloneTo not implemented for expression {0}", this.GetType ()));
1228 // Clones an expression created by the parser.
1230 // We only support expressions created by the parser so far, not
1231 // expressions that have been resolved (many more classes would need
1232 // to implement CloneTo).
1234 // This infrastructure is here merely for Lambda expressions which
1235 // compile the same code using different type values for the same
1236 // arguments to find the correct overload
1238 public Expression Clone (CloneContext clonectx)
1240 Expression cloned = (Expression) MemberwiseClone ();
1241 CloneTo (clonectx, cloned);
1246 public virtual Expression CreateExpressionTree (EmitContext ec)
1248 throw new NotImplementedException (
1249 "Expression tree conversion not implemented for " + GetType ());
1252 protected Expression CreateExpressionFactoryCall (string name, ArrayList args)
1254 return CreateExpressionFactoryCall (name, null, args, loc);
1257 protected Expression CreateExpressionFactoryCall (string name, TypeArguments typeArguments, ArrayList args)
1259 return CreateExpressionFactoryCall (name, typeArguments, args, loc);
1262 public static Expression CreateExpressionFactoryCall (string name, TypeArguments typeArguments, ArrayList args, Location loc)
1264 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (loc), name, typeArguments, loc), args);
1267 protected static TypeExpr CreateExpressionTypeExpression (Location loc)
1269 TypeExpr texpr = TypeManager.expression_type_expr;
1270 if (texpr == null) {
1271 Type t = TypeManager.CoreLookupType ("System.Linq.Expressions", "Expression", Kind.Class, true);
1275 TypeManager.expression_type_expr = texpr = new TypeExpression (t, Location.Null);
1283 /// This is just a base class for expressions that can
1284 /// appear on statements (invocations, object creation,
1285 /// assignments, post/pre increment and decrement). The idea
1286 /// being that they would support an extra Emition interface that
1287 /// does not leave a result on the stack.
1289 public abstract class ExpressionStatement : Expression {
1291 public virtual ExpressionStatement ResolveStatement (EmitContext ec)
1293 Expression e = Resolve (ec);
1297 ExpressionStatement es = e as ExpressionStatement;
1299 Error_InvalidExpressionStatement ();
1305 /// Requests the expression to be emitted in a `statement'
1306 /// context. This means that no new value is left on the
1307 /// stack after invoking this method (constrasted with
1308 /// Emit that will always leave a value on the stack).
1310 public abstract void EmitStatement (EmitContext ec);
1312 public override void EmitSideEffect (EmitContext ec)
1319 /// This kind of cast is used to encapsulate the child
1320 /// whose type is child.Type into an expression that is
1321 /// reported to return "return_type". This is used to encapsulate
1322 /// expressions which have compatible types, but need to be dealt
1323 /// at higher levels with.
1325 /// For example, a "byte" expression could be encapsulated in one
1326 /// of these as an "unsigned int". The type for the expression
1327 /// would be "unsigned int".
1330 public abstract class TypeCast : Expression
1332 protected Expression child;
1334 protected TypeCast (Expression child, Type return_type)
1336 eclass = child.eclass;
1337 loc = child.Location;
1342 public override Expression CreateExpressionTree (EmitContext ec)
1344 ArrayList args = new ArrayList (2);
1345 args.Add (new Argument (child.CreateExpressionTree (ec)));
1346 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1347 return CreateExpressionFactoryCall (ec.CheckState ? "ConvertChecked" : "Convert", args);
1350 public override Expression DoResolve (EmitContext ec)
1352 // This should never be invoked, we are born in fully
1353 // initialized state.
1358 public override void Emit (EmitContext ec)
1363 public override bool GetAttributableValue (Type value_type, out object value)
1365 return child.GetAttributableValue (value_type, out value);
1368 protected override void CloneTo (CloneContext clonectx, Expression t)
1370 TypeCast target = (TypeCast) t;
1372 target.child = child.Clone (clonectx);
1376 public class EmptyCast : TypeCast {
1377 EmptyCast (Expression child, Type target_type)
1378 : base (child, target_type)
1382 public static Expression Create (Expression child, Type type)
1384 Constant c = child as Constant;
1386 return new EmptyConstantCast (c, type);
1388 return new EmptyCast (child, type);
1391 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1393 child.EmitBranchable (ec, label, on_true);
1396 public override void EmitSideEffect (EmitContext ec)
1398 child.EmitSideEffect (ec);
1404 /// Performs a cast using an operator (op_Explicit or op_Implicit)
1406 public class OperatorCast : TypeCast {
1407 MethodInfo conversion_operator;
1410 public OperatorCast (Expression child, Type target_type) : this (child, target_type, false) {}
1412 public OperatorCast (Expression child, Type target_type, bool find_explicit)
1413 : base (child, target_type)
1415 this.find_explicit = find_explicit;
1418 // Returns the implicit operator that converts from
1419 // 'child.Type' to our target type (type)
1420 MethodInfo GetConversionOperator (bool find_explicit)
1422 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1426 mi = TypeManager.MemberLookup (child.Type, child.Type, child.Type, MemberTypes.Method,
1427 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1430 mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1431 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1434 foreach (MethodInfo oper in mi) {
1435 ParameterData pd = TypeManager.GetParameterData (oper);
1437 if (pd.ParameterType (0) == child.Type && TypeManager.TypeToCoreType (oper.ReturnType) == type)
1445 public override void Emit (EmitContext ec)
1447 ILGenerator ig = ec.ig;
1450 conversion_operator = GetConversionOperator (find_explicit);
1452 if (conversion_operator == null)
1453 throw new InternalErrorException ("Outer conversion routine is out of sync");
1455 ig.Emit (OpCodes.Call, conversion_operator);
1461 /// This is a numeric cast to a Decimal
1463 public class CastToDecimal : TypeCast {
1464 MethodInfo conversion_operator;
1466 public CastToDecimal (Expression child)
1467 : this (child, false)
1471 public CastToDecimal (Expression child, bool find_explicit)
1472 : base (child, TypeManager.decimal_type)
1474 conversion_operator = GetConversionOperator (find_explicit);
1476 if (conversion_operator == null)
1477 throw new InternalErrorException ("Outer conversion routine is out of sync");
1480 // Returns the implicit operator that converts from
1481 // 'child.Type' to System.Decimal.
1482 MethodInfo GetConversionOperator (bool find_explicit)
1484 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1486 MemberInfo [] mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1487 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1489 foreach (MethodInfo oper in mi) {
1490 ParameterData pd = TypeManager.GetParameterData (oper);
1492 if (pd.ParameterType (0) == child.Type && TypeManager.TypeToCoreType (oper.ReturnType) == type)
1498 public override void Emit (EmitContext ec)
1500 ILGenerator ig = ec.ig;
1503 ig.Emit (OpCodes.Call, conversion_operator);
1508 /// This is an explicit numeric cast from a Decimal
1510 public class CastFromDecimal : TypeCast
1512 static IDictionary operators;
1514 public CastFromDecimal (Expression child, Type return_type)
1515 : base (child, return_type)
1517 if (child.Type != TypeManager.decimal_type)
1518 throw new InternalErrorException (
1519 "The expected type is Decimal, instead it is " + child.Type.FullName);
1522 // Returns the explicit operator that converts from an
1523 // express of type System.Decimal to 'type'.
1524 public Expression Resolve ()
1526 if (operators == null) {
1527 MemberInfo[] all_oper = TypeManager.MemberLookup (TypeManager.decimal_type,
1528 TypeManager.decimal_type, TypeManager.decimal_type, MemberTypes.Method,
1529 BindingFlags.Static | BindingFlags.Public, "op_Explicit", null);
1531 operators = new System.Collections.Specialized.HybridDictionary ();
1532 foreach (MethodInfo oper in all_oper) {
1533 ParameterData pd = TypeManager.GetParameterData (oper);
1534 if (pd.ParameterType (0) == TypeManager.decimal_type)
1535 operators.Add (TypeManager.TypeToCoreType (oper.ReturnType), oper);
1539 return operators.Contains (type) ? this : null;
1542 public override void Emit (EmitContext ec)
1544 ILGenerator ig = ec.ig;
1547 ig.Emit (OpCodes.Call, (MethodInfo)operators [type]);
1553 // Constant specialization of EmptyCast.
1554 // We need to special case this since an empty cast of
1555 // a constant is still a constant.
1557 public class EmptyConstantCast : Constant
1559 public readonly Constant child;
1561 public EmptyConstantCast(Constant child, Type type)
1562 : base (child.Location)
1564 eclass = child.eclass;
1569 public override string AsString ()
1571 return child.AsString ();
1574 public override object GetValue ()
1576 return child.GetValue ();
1579 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
1581 // FIXME: check that 'type' can be converted to 'target_type' first
1582 return child.ConvertExplicitly (in_checked_context, target_type);
1585 public override Expression CreateExpressionTree (EmitContext ec)
1587 ArrayList args = new ArrayList (2);
1588 args.Add (new Argument (child.CreateExpressionTree (ec)));
1589 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1590 return CreateExpressionFactoryCall ("Convert", args);
1593 public override Constant Increment ()
1595 return child.Increment ();
1598 public override bool IsDefaultValue {
1599 get { return child.IsDefaultValue; }
1602 public override bool IsNegative {
1603 get { return child.IsNegative; }
1606 public override bool IsNull {
1607 get { return child.IsNull; }
1610 public override bool IsZeroInteger {
1611 get { return child.IsZeroInteger; }
1614 public override void Emit (EmitContext ec)
1619 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1621 child.EmitBranchable (ec, label, on_true);
1624 public override void EmitSideEffect (EmitContext ec)
1626 child.EmitSideEffect (ec);
1629 public override Constant ConvertImplicitly (Type target_type)
1631 // FIXME: Do we need to check user conversions?
1632 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1634 return child.ConvertImplicitly (target_type);
1640 /// This class is used to wrap literals which belong inside Enums
1642 public class EnumConstant : Constant {
1643 public Constant Child;
1645 public EnumConstant (Constant child, Type enum_type):
1646 base (child.Location)
1648 eclass = child.eclass;
1653 public override Expression DoResolve (EmitContext ec)
1655 // This should never be invoked, we are born in fully
1656 // initialized state.
1661 public override void Emit (EmitContext ec)
1666 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1668 Child.EmitBranchable (ec, label, on_true);
1671 public override void EmitSideEffect (EmitContext ec)
1673 Child.EmitSideEffect (ec);
1676 public override bool GetAttributableValue (Type value_type, out object value)
1678 value = GetTypedValue ();
1682 public override string GetSignatureForError()
1684 return TypeManager.CSharpName (Type);
1687 public override object GetValue ()
1689 return Child.GetValue ();
1692 public override object GetTypedValue ()
1694 // FIXME: runtime is not ready to work with just emited enums
1695 if (!RootContext.StdLib) {
1696 return Child.GetValue ();
1699 return System.Enum.ToObject (type, Child.GetValue ());
1702 public override string AsString ()
1704 return TypeManager.CSharpEnumValue (type, Child.GetValue ());
1707 public override Constant Increment()
1709 return new EnumConstant (Child.Increment (), type);
1712 public override bool IsDefaultValue {
1714 return Child.IsDefaultValue;
1718 public override bool IsZeroInteger {
1719 get { return Child.IsZeroInteger; }
1722 public override bool IsNegative {
1724 return Child.IsNegative;
1728 public override Constant ConvertExplicitly(bool in_checked_context, Type target_type)
1730 if (Child.Type == target_type)
1733 return Child.ConvertExplicitly (in_checked_context, target_type);
1736 public override Constant ConvertImplicitly (Type type)
1738 Type this_type = TypeManager.DropGenericTypeArguments (Type);
1739 type = TypeManager.DropGenericTypeArguments (type);
1741 if (this_type == type) {
1742 // This is workaround of mono bug. It can be removed when the latest corlib spreads enough
1743 if (TypeManager.IsEnumType (type.UnderlyingSystemType))
1746 Type child_type = TypeManager.DropGenericTypeArguments (Child.Type);
1747 if (type.UnderlyingSystemType != child_type)
1748 Child = Child.ConvertImplicitly (type.UnderlyingSystemType);
1752 if (!Convert.ImplicitStandardConversionExists (this, type)){
1756 return Child.ConvertImplicitly(type);
1762 /// This kind of cast is used to encapsulate Value Types in objects.
1764 /// The effect of it is to box the value type emitted by the previous
1767 public class BoxedCast : TypeCast {
1769 public BoxedCast (Expression expr, Type target_type)
1770 : base (expr, target_type)
1772 eclass = ExprClass.Value;
1775 public override Expression DoResolve (EmitContext ec)
1777 // This should never be invoked, we are born in fully
1778 // initialized state.
1783 public override void Emit (EmitContext ec)
1787 ec.ig.Emit (OpCodes.Box, child.Type);
1790 public override void EmitSideEffect (EmitContext ec)
1792 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1793 // so, we need to emit the box+pop instructions in most cases
1794 if (child.Type.IsValueType &&
1795 (type == TypeManager.object_type || type == TypeManager.value_type))
1796 child.EmitSideEffect (ec);
1798 base.EmitSideEffect (ec);
1802 public class UnboxCast : TypeCast {
1803 public UnboxCast (Expression expr, Type return_type)
1804 : base (expr, return_type)
1808 public override Expression DoResolve (EmitContext ec)
1810 // This should never be invoked, we are born in fully
1811 // initialized state.
1816 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1818 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
1819 Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
1820 return base.DoResolveLValue (ec, right_side);
1823 public override void Emit (EmitContext ec)
1826 ILGenerator ig = ec.ig;
1830 if (t.IsGenericParameter || t.IsGenericType && t.IsValueType)
1831 ig.Emit (OpCodes.Unbox_Any, t);
1835 ig.Emit (OpCodes.Unbox, t);
1837 LoadFromPtr (ig, t);
1843 /// This is used to perform explicit numeric conversions.
1845 /// Explicit numeric conversions might trigger exceptions in a checked
1846 /// context, so they should generate the conv.ovf opcodes instead of
1849 public class ConvCast : TypeCast {
1850 public enum Mode : byte {
1851 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1853 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1854 U2_I1, U2_U1, U2_I2, U2_CH,
1855 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1856 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1857 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH,
1858 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH,
1859 CH_I1, CH_U1, CH_I2,
1860 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1861 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4
1866 public ConvCast (Expression child, Type return_type, Mode m)
1867 : base (child, return_type)
1872 public override Expression DoResolve (EmitContext ec)
1874 // This should never be invoked, we are born in fully
1875 // initialized state.
1880 public override string ToString ()
1882 return String.Format ("ConvCast ({0}, {1})", mode, child);
1885 public override void Emit (EmitContext ec)
1887 ILGenerator ig = ec.ig;
1893 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1894 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1895 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1896 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1897 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1899 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1900 case Mode.U1_CH: /* nothing */ break;
1902 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1903 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1904 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1905 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1906 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1907 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1909 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1910 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1911 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1912 case Mode.U2_CH: /* nothing */ break;
1914 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1915 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1916 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1917 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1918 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1919 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1920 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1922 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1923 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1924 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1925 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1926 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1927 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1929 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1930 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1931 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1932 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1933 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1934 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1935 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1936 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1938 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1939 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1940 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1941 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1942 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1943 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1944 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1945 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1947 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1948 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1949 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1951 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1952 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1953 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1954 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1955 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1956 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1957 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1958 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1959 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1961 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1962 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1963 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1964 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1965 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1966 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1967 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1968 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1969 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1970 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1974 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
1975 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
1976 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
1977 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
1978 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
1980 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
1981 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
1983 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
1984 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
1985 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
1986 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
1987 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
1988 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
1990 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
1991 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
1992 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
1993 case Mode.U2_CH: /* nothing */ break;
1995 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
1996 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
1997 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
1998 case Mode.I4_U4: /* nothing */ break;
1999 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
2000 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
2001 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
2003 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
2004 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
2005 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
2006 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
2007 case Mode.U4_I4: /* nothing */ break;
2008 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
2010 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
2011 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
2012 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
2013 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
2014 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
2015 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
2016 case Mode.I8_U8: /* nothing */ break;
2017 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
2019 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
2020 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
2021 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
2022 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
2023 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
2024 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
2025 case Mode.U8_I8: /* nothing */ break;
2026 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
2028 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
2029 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
2030 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
2032 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
2033 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
2034 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
2035 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
2036 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
2037 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
2038 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
2039 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
2040 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
2042 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
2043 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
2044 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
2045 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
2046 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
2047 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
2048 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
2049 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
2050 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
2051 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
2057 public class OpcodeCast : TypeCast {
2061 public OpcodeCast (Expression child, Type return_type, OpCode op)
2062 : base (child, return_type)
2066 second_valid = false;
2069 public OpcodeCast (Expression child, Type return_type, OpCode op, OpCode op2)
2070 : base (child, return_type)
2075 second_valid = true;
2078 public override Expression DoResolve (EmitContext ec)
2080 // This should never be invoked, we are born in fully
2081 // initialized state.
2086 public override void Emit (EmitContext ec)
2095 public Type UnderlyingType {
2096 get { return child.Type; }
2101 /// This kind of cast is used to encapsulate a child and cast it
2102 /// to the class requested
2104 public class ClassCast : TypeCast {
2105 public ClassCast (Expression child, Type return_type)
2106 : base (child, return_type)
2111 public override Expression DoResolve (EmitContext ec)
2113 // This should never be invoked, we are born in fully
2114 // initialized state.
2119 public override void Emit (EmitContext ec)
2123 if (TypeManager.IsGenericParameter (child.Type))
2124 ec.ig.Emit (OpCodes.Box, child.Type);
2127 if (type.IsGenericParameter)
2128 ec.ig.Emit (OpCodes.Unbox_Any, type);
2131 ec.ig.Emit (OpCodes.Castclass, type);
2136 // Used when resolved expression has different representations for
2137 // expression trees and emit phase
2139 public class ReducedExpression : Expression
2141 class ReducedConstantExpression : Constant
2143 readonly Constant expr;
2144 readonly Expression orig_expr;
2146 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2147 : base (expr.Location)
2150 this.orig_expr = orig_expr;
2151 eclass = expr.eclass;
2155 public override string AsString ()
2157 return expr.AsString ();
2160 public override Expression CreateExpressionTree (EmitContext ec)
2162 return orig_expr.CreateExpressionTree (ec);
2165 public override object GetValue ()
2167 return expr.GetValue ();
2170 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
2172 throw new NotImplementedException ();
2175 public override Expression DoResolve (EmitContext ec)
2180 public override Constant Increment ()
2182 throw new NotImplementedException ();
2185 public override bool IsDefaultValue {
2187 return expr.IsDefaultValue;
2191 public override bool IsNegative {
2193 return expr.IsNegative;
2197 public override void Emit (EmitContext ec)
2203 readonly Expression expr, orig_expr;
2205 private ReducedExpression (Expression expr, Expression orig_expr)
2208 this.orig_expr = orig_expr;
2209 this.loc = orig_expr.Location;
2212 public static Expression Create (Constant expr, Expression original_expr)
2214 return new ReducedConstantExpression (expr, original_expr);
2217 public static Expression Create (Expression expr, Expression original_expr)
2219 Constant c = expr as Constant;
2221 return Create (c, original_expr);
2223 return new ReducedExpression (expr, original_expr);
2226 public override Expression CreateExpressionTree (EmitContext ec)
2228 return orig_expr.CreateExpressionTree (ec);
2231 public override Expression DoResolve (EmitContext ec)
2233 eclass = expr.eclass;
2238 public override void Emit (EmitContext ec)
2243 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2245 expr.EmitBranchable (ec, target, on_true);
2250 /// SimpleName expressions are formed of a single word and only happen at the beginning
2251 /// of a dotted-name.
2253 public class SimpleName : Expression {
2254 public readonly string Name;
2255 public readonly TypeArguments Arguments;
2258 public SimpleName (string name, Location l)
2264 public SimpleName (string name, TypeArguments args, Location l)
2271 public SimpleName (string name, TypeParameter[] type_params, Location l)
2276 Arguments = new TypeArguments (l);
2277 foreach (TypeParameter type_param in type_params)
2278 Arguments.Add (new TypeParameterExpr (type_param, l));
2281 public static string RemoveGenericArity (string name)
2284 StringBuilder sb = null;
2286 int pos = name.IndexOf ('`', start);
2291 sb.Append (name.Substring (start));
2296 sb = new StringBuilder ();
2297 sb.Append (name.Substring (start, pos-start));
2300 while ((pos < name.Length) && Char.IsNumber (name [pos]))
2304 } while (start < name.Length);
2306 return sb.ToString ();
2309 public SimpleName GetMethodGroup ()
2311 return new SimpleName (RemoveGenericArity (Name), Arguments, loc);
2314 public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
2316 if (ec.IsInFieldInitializer)
2317 Report.Error (236, l,
2318 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2322 120, l, "`{0}': An object reference is required for the nonstatic field, method or property",
2326 public bool IdenticalNameAndTypeName (EmitContext ec, Expression resolved_to, Location loc)
2328 return resolved_to != null && resolved_to.Type != null &&
2329 resolved_to.Type.Name == Name &&
2330 (ec.DeclContainer.LookupNamespaceOrType (Name, loc, /* ignore_cs0104 = */ true) != null);
2333 public override Expression DoResolve (EmitContext ec)
2335 return SimpleNameResolve (ec, null, false);
2338 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
2340 return SimpleNameResolve (ec, right_side, false);
2344 public Expression DoResolve (EmitContext ec, bool intermediate)
2346 return SimpleNameResolve (ec, null, intermediate);
2349 static bool IsNestedChild (Type t, Type parent)
2351 while (parent != null) {
2352 if (TypeManager.IsNestedChildOf (t, TypeManager.DropGenericTypeArguments (parent)))
2355 parent = parent.BaseType;
2361 FullNamedExpression ResolveNested (IResolveContext ec, Type t)
2363 if (!TypeManager.IsGenericTypeDefinition (t) && !TypeManager.IsGenericType (t))
2366 DeclSpace ds = ec.DeclContainer;
2367 while (ds != null && !IsNestedChild (t, ds.TypeBuilder))
2373 Type[] gen_params = TypeManager.GetTypeArguments (t);
2375 int arg_count = Arguments != null ? Arguments.Count : 0;
2377 for (; (ds != null) && ds.IsGeneric; ds = ds.Parent) {
2378 if (arg_count + ds.CountTypeParameters == gen_params.Length) {
2379 TypeArguments new_args = new TypeArguments (loc);
2380 foreach (TypeParameter param in ds.TypeParameters)
2381 new_args.Add (new TypeParameterExpr (param, loc));
2383 if (Arguments != null)
2384 new_args.Add (Arguments);
2386 return new ConstructedType (t, new_args, loc);
2393 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2395 FullNamedExpression fne = ec.GenericDeclContainer.LookupGeneric (Name, loc);
2397 return fne.ResolveAsTypeStep (ec, silent);
2399 int errors = Report.Errors;
2400 fne = ec.DeclContainer.LookupNamespaceOrType (Name, loc, /*ignore_cs0104=*/ false);
2403 if (fne.Type == null)
2406 FullNamedExpression nested = ResolveNested (ec, fne.Type);
2408 return nested.ResolveAsTypeStep (ec, false);
2410 if (Arguments != null) {
2411 ConstructedType ct = new ConstructedType (fne, Arguments, loc);
2412 return ct.ResolveAsTypeStep (ec, false);
2418 if (silent || errors != Report.Errors)
2421 Error_TypeOrNamespaceNotFound (ec);
2425 protected virtual void Error_TypeOrNamespaceNotFound (IResolveContext ec)
2427 MemberCore mc = ec.DeclContainer.GetDefinition (Name);
2429 Error_UnexpectedKind (ec.DeclContainer, "type", GetMemberType (mc), loc);
2433 string ns = ec.DeclContainer.NamespaceEntry.NS.Name;
2434 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2435 foreach (Assembly a in RootNamespace.Global.Assemblies) {
2436 Type type = a.GetType (fullname);
2438 Report.SymbolRelatedToPreviousError (type);
2439 Expression.ErrorIsInaccesible (loc, TypeManager.CSharpName (type));
2444 Type t = ec.DeclContainer.LookupAnyGeneric (Name);
2446 Namespace.Error_InvalidNumberOfTypeArguments (t, loc);
2450 if (Arguments != null) {
2451 FullNamedExpression retval = ec.DeclContainer.LookupNamespaceOrType (SimpleName.RemoveGenericArity (Name), loc, true);
2452 if (retval != null) {
2453 Namespace.Error_TypeArgumentsCannotBeUsed (retval.Type, loc);
2458 NamespaceEntry.Error_NamespaceNotFound (loc, Name);
2461 // TODO: I am still not convinced about this. If someone else will need it
2462 // implement this as virtual property in MemberCore hierarchy
2463 public static string GetMemberType (MemberCore mc)
2469 if (mc is FieldBase)
2471 if (mc is MethodCore)
2473 if (mc is EnumMember)
2481 Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2487 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2493 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2500 /// 7.5.2: Simple Names.
2502 /// Local Variables and Parameters are handled at
2503 /// parse time, so they never occur as SimpleNames.
2505 /// The `intermediate' flag is used by MemberAccess only
2506 /// and it is used to inform us that it is ok for us to
2507 /// avoid the static check, because MemberAccess might end
2508 /// up resolving the Name as a Type name and the access as
2509 /// a static type access.
2511 /// ie: Type Type; .... { Type.GetType (""); }
2513 /// Type is both an instance variable and a Type; Type.GetType
2514 /// is the static method not an instance method of type.
2516 Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2518 Expression e = null;
2521 // Stage 1: Performed by the parser (binding to locals or parameters).
2523 Block current_block = ec.CurrentBlock;
2524 if (current_block != null){
2525 LocalInfo vi = current_block.GetLocalInfo (Name);
2527 if (Arguments != null) {
2528 Report.Error (307, loc,
2529 "The variable `{0}' cannot be used with type arguments",
2534 LocalVariableReference var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2535 if (right_side != null) {
2536 return var.ResolveLValue (ec, right_side, loc);
2538 ResolveFlags rf = ResolveFlags.VariableOrValue;
2540 rf |= ResolveFlags.DisableFlowAnalysis;
2541 return var.Resolve (ec, rf);
2545 ParameterReference pref = current_block.Toplevel.GetParameterReference (Name, loc);
2547 if (Arguments != null) {
2548 Report.Error (307, loc,
2549 "The variable `{0}' cannot be used with type arguments",
2554 if (right_side != null)
2555 return pref.ResolveLValue (ec, right_side, loc);
2557 return pref.Resolve (ec);
2560 Expression expr = current_block.Toplevel.GetTransparentIdentifier (Name);
2562 if (right_side != null)
2563 return expr.ResolveLValue (ec, right_side, loc);
2564 return expr.Resolve (ec);
2569 // Stage 2: Lookup members
2572 Type almost_matched_type = null;
2573 ArrayList almost_matched = null;
2574 for (DeclSpace lookup_ds = ec.DeclContainer; lookup_ds != null; lookup_ds = lookup_ds.Parent) {
2575 // either RootDeclSpace or GenericMethod
2576 if (lookup_ds.TypeBuilder == null)
2579 e = MemberLookup (ec.ContainerType, lookup_ds.TypeBuilder, Name, loc);
2581 if (e is PropertyExpr) {
2582 // since TypeManager.MemberLookup doesn't know if we're doing a lvalue access or not,
2583 // it doesn't know which accessor to check permissions against
2584 if (((PropertyExpr) e).IsAccessibleFrom (ec.ContainerType, right_side != null))
2586 } else if (e is EventExpr) {
2587 if (((EventExpr) e).IsAccessibleFrom (ec.ContainerType))
2595 if (almost_matched == null && almost_matched_members.Count > 0) {
2596 almost_matched_type = lookup_ds.TypeBuilder;
2597 almost_matched = (ArrayList) almost_matched_members.Clone ();
2602 if (almost_matched == null && almost_matched_members.Count > 0) {
2603 almost_matched_type = ec.ContainerType;
2604 almost_matched = (ArrayList) almost_matched_members.Clone ();
2606 e = ResolveAsTypeStep (ec, true);
2610 if (current_block != null) {
2611 IKnownVariable ikv = current_block.Explicit.GetKnownVariable (Name);
2613 LocalInfo li = ikv as LocalInfo;
2614 // Supress CS0219 warning
2618 Error_VariableIsUsedBeforeItIsDeclared (Name);
2623 if (almost_matched != null)
2624 almost_matched_members = almost_matched;
2625 if (almost_matched_type == null)
2626 almost_matched_type = ec.ContainerType;
2627 Error_MemberLookupFailed (ec.ContainerType, null, almost_matched_type, Name,
2628 ec.DeclContainer.Name, AllMemberTypes, AllBindingFlags);
2632 if (e is TypeExpr) {
2633 if (Arguments == null)
2636 ConstructedType ct = new ConstructedType (
2637 (FullNamedExpression) e, Arguments, loc);
2638 return ct.ResolveAsTypeStep (ec, false);
2641 if (e is MemberExpr) {
2642 MemberExpr me = (MemberExpr) e;
2645 if (me.IsInstance) {
2646 if (ec.IsStatic || ec.IsInFieldInitializer) {
2648 // Note that an MemberExpr can be both IsInstance and IsStatic.
2649 // An unresolved MethodGroupExpr can contain both kinds of methods
2650 // and each predicate is true if the MethodGroupExpr contains
2651 // at least one of that kind of method.
2655 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2656 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2661 // Pass the buck to MemberAccess and Invocation.
2663 left = EmptyExpression.Null;
2665 left = ec.GetThis (loc);
2668 left = new TypeExpression (ec.ContainerType, loc);
2671 me = me.ResolveMemberAccess (ec, left, loc, null);
2675 if (Arguments != null) {
2676 Arguments.Resolve (ec);
2677 me.SetTypeArguments (Arguments);
2680 if (!me.IsStatic && (me.InstanceExpression != null) &&
2681 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2682 me.InstanceExpression.Type != me.DeclaringType &&
2683 !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2684 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2685 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2686 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2690 return (right_side != null)
2691 ? me.DoResolveLValue (ec, right_side)
2692 : me.DoResolve (ec);
2698 public override void Emit (EmitContext ec)
2700 throw new InternalErrorException ("The resolve phase was not executed");
2703 public override string ToString ()
2708 public override string GetSignatureForError ()
2710 if (Arguments != null) {
2711 return TypeManager.RemoveGenericArity (Name) + "<" +
2712 Arguments.GetSignatureForError () + ">";
2718 protected override void CloneTo (CloneContext clonectx, Expression target)
2720 // CloneTo: Nothing, we do not keep any state on this expression
2725 /// Represents a namespace or a type. The name of the class was inspired by
2726 /// section 10.8.1 (Fully Qualified Names).
2728 public abstract class FullNamedExpression : Expression {
2729 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2734 public abstract string FullName {
2740 /// Expression that evaluates to a type
2742 public abstract class TypeExpr : FullNamedExpression {
2743 override public FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2745 TypeExpr t = DoResolveAsTypeStep (ec);
2749 eclass = ExprClass.Type;
2753 override public Expression DoResolve (EmitContext ec)
2755 return ResolveAsTypeTerminal (ec, false);
2758 override public void Emit (EmitContext ec)
2760 throw new Exception ("Should never be called");
2763 public virtual bool CheckAccessLevel (DeclSpace ds)
2765 return ds.CheckAccessLevel (Type);
2768 public virtual bool AsAccessible (DeclSpace ds)
2770 return ds.IsAccessibleAs (Type);
2773 public virtual bool IsClass {
2774 get { return Type.IsClass; }
2777 public virtual bool IsValueType {
2778 get { return Type.IsValueType; }
2781 public virtual bool IsInterface {
2782 get { return Type.IsInterface; }
2785 public virtual bool IsSealed {
2786 get { return Type.IsSealed; }
2789 public virtual bool CanInheritFrom ()
2791 if (Type == TypeManager.enum_type ||
2792 (Type == TypeManager.value_type && RootContext.StdLib) ||
2793 Type == TypeManager.multicast_delegate_type ||
2794 Type == TypeManager.delegate_type ||
2795 Type == TypeManager.array_type)
2801 protected abstract TypeExpr DoResolveAsTypeStep (IResolveContext ec);
2803 public abstract string Name {
2807 public override bool Equals (object obj)
2809 TypeExpr tobj = obj as TypeExpr;
2813 return Type == tobj.Type;
2816 public override int GetHashCode ()
2818 return Type.GetHashCode ();
2821 public override string ToString ()
2828 /// Fully resolved Expression that already evaluated to a type
2830 public class TypeExpression : TypeExpr {
2831 public TypeExpression (Type t, Location l)
2834 eclass = ExprClass.Type;
2838 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2843 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2848 public override string Name {
2849 get { return Type.ToString (); }
2852 public override string FullName {
2853 get { return Type.FullName; }
2858 /// Used to create types from a fully qualified name. These are just used
2859 /// by the parser to setup the core types. A TypeLookupExpression is always
2860 /// classified as a type.
2862 public sealed class TypeLookupExpression : TypeExpr {
2863 readonly string name;
2865 public TypeLookupExpression (string name)
2868 eclass = ExprClass.Type;
2871 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2873 // It's null for corlib compilation only
2875 return DoResolveAsTypeStep (ec);
2880 private class UnexpectedType
2884 // This performes recursive type lookup, providing support for generic types.
2885 // For example, given the type:
2887 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]]
2889 // The types will be checked in the following order:
2892 // System.Collections |
2893 // System.Collections.Generic |
2895 // System | recursive call 1 |
2896 // System.Int32 _| | main method call
2898 // System | recursive call 2 |
2899 // System.String _| |
2901 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]] _|
2903 private Type TypeLookup (IResolveContext ec, string name)
2908 FullNamedExpression resolved = null;
2910 Type recursive_type = null;
2911 while (index < name.Length) {
2912 if (name[index] == '[') {
2917 if (name[index] == '[')
2919 else if (name[index] == ']')
2921 } while (braces > 0);
2922 recursive_type = TypeLookup (ec, name.Substring (open + 1, index - open - 1));
2923 if (recursive_type == null || (recursive_type == typeof(UnexpectedType)))
2924 return recursive_type;
2927 if (name[index] == ',')
2929 else if ((name[index] == '.' && !done) || (index == name.Length && name[0] != '[')) {
2930 string substring = name.Substring(dot, index - dot);
2932 if (resolved == null)
2933 resolved = RootNamespace.Global.Lookup (ec.DeclContainer, substring, Location.Null);
2934 else if (resolved is Namespace)
2935 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
2936 else if (type != null)
2937 type = TypeManager.GetNestedType (type, substring);
2941 if (resolved == null)
2943 else if (type == null && resolved is TypeExpr)
2944 type = resolved.Type;
2951 if (name[0] != '[') {
2952 string substring = name.Substring(dot, index - dot);
2955 return TypeManager.GetNestedType (type, substring);
2957 if (resolved != null) {
2958 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
2959 if (resolved is TypeExpr)
2960 return resolved.Type;
2962 if (resolved == null)
2965 resolved.Error_UnexpectedKind (ec.DeclContainer, "type", loc);
2966 return typeof (UnexpectedType);
2972 return recursive_type;
2975 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2977 Type t = TypeLookup (ec, name);
2979 NamespaceEntry.Error_NamespaceNotFound (loc, name);
2982 if (t == typeof(UnexpectedType))
2988 public override string Name {
2989 get { return name; }
2992 public override string FullName {
2993 get { return name; }
2996 protected override void CloneTo (CloneContext clonectx, Expression target)
2998 // CloneTo: Nothing, we do not keep any state on this expression
3001 public override string GetSignatureForError ()
3004 return TypeManager.CSharpName (name);
3006 return base.GetSignatureForError ();
3011 /// Represents an "unbound generic type", ie. typeof (Foo<>).
3014 public class UnboundTypeExpression : TypeExpr
3018 public UnboundTypeExpression (MemberName name, Location l)
3024 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
3027 if (name.Left != null) {
3028 Expression lexpr = name.Left.GetTypeExpression ();
3029 expr = new MemberAccess (lexpr, name.Basename);
3031 expr = new SimpleName (name.Basename, loc);
3034 FullNamedExpression fne = expr.ResolveAsTypeStep (ec, false);
3039 return new TypeExpression (type, loc);
3042 public override string Name {
3043 get { return name.PrettyName; }
3046 public override string FullName {
3047 get { return name.FullyQualifiedName; }
3051 public class TypeAliasExpression : TypeExpr {
3052 FullNamedExpression alias;
3057 public TypeAliasExpression (FullNamedExpression alias, TypeArguments args, Location l)
3063 eclass = ExprClass.Type;
3065 name = alias.FullName + "<" + args.ToString () + ">";
3067 name = alias.FullName;
3070 public override string Name {
3071 get { return alias.FullName; }
3074 public override string FullName {
3075 get { return name; }
3078 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
3080 texpr = alias.ResolveAsTypeTerminal (ec, false);
3084 Type type = texpr.Type;
3085 int num_args = TypeManager.GetNumberOfTypeArguments (type);
3088 if (num_args == 0) {
3089 Report.Error (308, loc,
3090 "The non-generic type `{0}' cannot " +
3091 "be used with type arguments.",
3092 TypeManager.CSharpName (type));
3096 ConstructedType ctype = new ConstructedType (type, args, loc);
3097 return ctype.ResolveAsTypeTerminal (ec, false);
3098 } else if (num_args > 0) {
3099 Report.Error (305, loc,
3100 "Using the generic type `{0}' " +
3101 "requires {1} type arguments",
3102 TypeManager.CSharpName (type), num_args.ToString ());
3109 public override bool CheckAccessLevel (DeclSpace ds)
3111 return texpr.CheckAccessLevel (ds);
3114 public override bool AsAccessible (DeclSpace ds)
3116 return texpr.AsAccessible (ds);
3119 public override bool IsClass {
3120 get { return texpr.IsClass; }
3123 public override bool IsValueType {
3124 get { return texpr.IsValueType; }
3127 public override bool IsInterface {
3128 get { return texpr.IsInterface; }
3131 public override bool IsSealed {
3132 get { return texpr.IsSealed; }
3137 /// This class denotes an expression which evaluates to a member
3138 /// of a struct or a class.
3140 public abstract class MemberExpr : Expression
3142 protected bool is_base;
3145 /// The name of this member.
3147 public abstract string Name {
3152 // When base.member is used
3154 public bool IsBase {
3155 get { return is_base; }
3156 set { is_base = value; }
3160 /// Whether this is an instance member.
3162 public abstract bool IsInstance {
3167 /// Whether this is a static member.
3169 public abstract bool IsStatic {
3174 /// The type which declares this member.
3176 public abstract Type DeclaringType {
3181 /// The instance expression associated with this member, if it's a
3182 /// non-static member.
3184 public Expression InstanceExpression;
3186 public static void error176 (Location loc, string name)
3188 Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
3189 "with an instance reference, qualify it with a type name instead", name);
3192 // TODO: possible optimalization
3193 // Cache resolved constant result in FieldBuilder <-> expression map
3194 public virtual MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3195 SimpleName original)
3199 // original == null || original.Resolve (...) ==> left
3202 if (left is TypeExpr) {
3203 left = left.ResolveAsTypeTerminal (ec, true);
3208 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3216 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3219 return ResolveExtensionMemberAccess (left);
3222 InstanceExpression = left;
3226 protected virtual MemberExpr ResolveExtensionMemberAccess (Expression left)
3228 error176 (loc, GetSignatureForError ());
3232 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3237 if (InstanceExpression == EmptyExpression.Null) {
3238 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3242 if (InstanceExpression.Type.IsValueType) {
3243 if (InstanceExpression is IMemoryLocation) {
3244 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
3246 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
3247 InstanceExpression.Emit (ec);
3249 t.AddressOf (ec, AddressOp.Store);
3252 InstanceExpression.Emit (ec);
3254 if (prepare_for_load)
3255 ec.ig.Emit (OpCodes.Dup);
3258 public virtual void SetTypeArguments (TypeArguments ta)
3260 // TODO: need to get correct member type
3261 Report.Error (307, loc, "The property `{0}' cannot be used with type arguments",
3262 GetSignatureForError ());
3267 /// Represents group of extension methods
3269 public class ExtensionMethodGroupExpr : MethodGroupExpr
3271 readonly NamespaceEntry namespace_entry;
3272 public Expression ExtensionExpression;
3273 Argument extension_argument;
3275 public ExtensionMethodGroupExpr (ArrayList list, NamespaceEntry n, Type extensionType, Location l)
3276 : base (list, extensionType, l)
3278 this.namespace_entry = n;
3281 public override bool IsStatic {
3282 get { return true; }
3285 public bool IsTopLevel {
3286 get { return namespace_entry == null; }
3289 public override void EmitArguments (EmitContext ec, ArrayList arguments)
3291 if (arguments == null)
3292 arguments = new ArrayList (1);
3293 arguments.Insert (0, extension_argument);
3294 base.EmitArguments (ec, arguments);
3297 public override void EmitCall (EmitContext ec, ArrayList arguments)
3299 if (arguments == null)
3300 arguments = new ArrayList (1);
3301 arguments.Insert (0, extension_argument);
3302 base.EmitCall (ec, arguments);
3305 public override MethodGroupExpr OverloadResolve (EmitContext ec, ref ArrayList arguments, bool may_fail, Location loc)
3307 if (arguments == null)
3308 arguments = new ArrayList (1);
3310 arguments.Insert (0, new Argument (ExtensionExpression));
3311 MethodGroupExpr mg = ResolveOverloadExtensions (ec, arguments, namespace_entry, loc);
3313 // Store resolved argument and restore original arguments
3315 ((ExtensionMethodGroupExpr)mg).extension_argument = (Argument)arguments [0];
3316 arguments.RemoveAt (0);
3321 MethodGroupExpr ResolveOverloadExtensions (EmitContext ec, ArrayList arguments, NamespaceEntry ns, Location loc)
3323 // Use normal resolve rules
3324 MethodGroupExpr mg = base.OverloadResolve (ec, ref arguments, ns != null, loc);
3332 ExtensionMethodGroupExpr e = ns.LookupExtensionMethod (type, null, Name, loc);
3334 return base.OverloadResolve (ec, ref arguments, false, loc);
3336 e.ExtensionExpression = ExtensionExpression;
3337 return e.ResolveOverloadExtensions (ec, arguments, e.namespace_entry, loc);
3342 /// MethodGroupExpr represents a group of method candidates which
3343 /// can be resolved to the best method overload
3345 public class MethodGroupExpr : MemberExpr
3347 public interface IErrorHandler
3349 bool NoExactMatch (EmitContext ec, MethodBase method);
3352 public IErrorHandler CustomErrorHandler;
3353 public MethodBase [] Methods;
3354 MethodBase best_candidate;
3355 // TODO: make private
3356 public TypeArguments type_arguments;
3357 bool identical_type_name;
3360 public MethodGroupExpr (MemberInfo [] mi, Type type, Location l)
3363 Methods = new MethodBase [mi.Length];
3364 mi.CopyTo (Methods, 0);
3367 public MethodGroupExpr (ArrayList list, Type type, Location l)
3371 Methods = (MethodBase[])list.ToArray (typeof (MethodBase));
3373 foreach (MemberInfo m in list){
3374 if (!(m is MethodBase)){
3375 Console.WriteLine ("Name " + m.Name);
3376 Console.WriteLine ("Found a: " + m.GetType ().FullName);
3385 protected MethodGroupExpr (Type type, Location loc)
3388 eclass = ExprClass.MethodGroup;
3392 public override Type DeclaringType {
3395 // We assume that the top-level type is in the end
3397 return Methods [Methods.Length - 1].DeclaringType;
3398 //return Methods [0].DeclaringType;
3402 public Type DelegateType {
3404 delegate_type = value;
3408 public bool IdenticalTypeName {
3410 return identical_type_name;
3414 identical_type_name = value;
3418 public override string GetSignatureForError ()
3420 if (best_candidate != null)
3421 return TypeManager.CSharpSignature (best_candidate);
3423 return TypeManager.CSharpSignature (Methods [0]);
3426 public override string Name {
3428 return Methods [0].Name;
3432 public override bool IsInstance {
3434 if (best_candidate != null)
3435 return !best_candidate.IsStatic;
3437 foreach (MethodBase mb in Methods)
3445 public override bool IsStatic {
3447 if (best_candidate != null)
3448 return best_candidate.IsStatic;
3450 foreach (MethodBase mb in Methods)
3458 public static explicit operator ConstructorInfo (MethodGroupExpr mg)
3460 return (ConstructorInfo)mg.best_candidate;
3463 public static explicit operator MethodInfo (MethodGroupExpr mg)
3465 return (MethodInfo)mg.best_candidate;
3469 // 7.4.3.3 Better conversion from expression
3470 // Returns : 1 if a->p is better,
3471 // 2 if a->q is better,
3472 // 0 if neither is better
3474 static int BetterExpressionConversion (EmitContext ec, Argument a, Type p, Type q)
3476 Type argument_type = TypeManager.TypeToCoreType (a.Type);
3477 if (argument_type == TypeManager.anonymous_method_type && RootContext.Version > LanguageVersion.ISO_2) {
3479 // Uwrap delegate from Expression<T>
3481 if (TypeManager.DropGenericTypeArguments (p) == TypeManager.expression_type) {
3482 p = TypeManager.GetTypeArguments (p) [0];
3483 q = TypeManager.GetTypeArguments (q) [0];
3485 p = Delegate.GetInvokeMethod (null, p).ReturnType;
3486 q = Delegate.GetInvokeMethod (null, q).ReturnType;
3488 if (argument_type == p)
3491 if (argument_type == q)
3495 return BetterTypeConversion (ec, p, q);
3499 // 7.4.3.4 Better conversion from type
3501 public static int BetterTypeConversion (EmitContext ec, Type p, Type q)
3503 if (p == null || q == null)
3504 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3506 if (p == TypeManager.int32_type) {
3507 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3509 } else if (p == TypeManager.int64_type) {
3510 if (q == TypeManager.uint64_type)
3512 } else if (p == TypeManager.sbyte_type) {
3513 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3514 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3516 } else if (p == TypeManager.short_type) {
3517 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3518 q == TypeManager.uint64_type)
3522 if (q == TypeManager.int32_type) {
3523 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3525 } if (q == TypeManager.int64_type) {
3526 if (p == TypeManager.uint64_type)
3528 } else if (q == TypeManager.sbyte_type) {
3529 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3530 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3532 } if (q == TypeManager.short_type) {
3533 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3534 p == TypeManager.uint64_type)
3538 // TODO: this is expensive
3539 Expression p_tmp = new EmptyExpression (p);
3540 Expression q_tmp = new EmptyExpression (q);
3542 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3543 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3545 if (p_to_q && !q_to_p)
3548 if (q_to_p && !p_to_q)
3555 /// Determines "Better function" between candidate
3556 /// and the current best match
3559 /// Returns a boolean indicating :
3560 /// false if candidate ain't better
3561 /// true if candidate is better than the current best match
3563 static bool BetterFunction (EmitContext ec, ArrayList args, int argument_count,
3564 MethodBase candidate, bool candidate_params,
3565 MethodBase best, bool best_params)
3567 ParameterData candidate_pd = TypeManager.GetParameterData (candidate);
3568 ParameterData best_pd = TypeManager.GetParameterData (best);
3570 bool better_at_least_one = false;
3572 for (int j = 0, c_idx = 0, b_idx = 0; j < argument_count; ++j, ++c_idx, ++b_idx)
3574 Argument a = (Argument) args [j];
3576 Type ct = TypeManager.TypeToCoreType (candidate_pd.ParameterType (c_idx));
3577 Type bt = TypeManager.TypeToCoreType (best_pd.ParameterType (b_idx));
3579 if (candidate_params && candidate_pd.ParameterModifier (c_idx) == Parameter.Modifier.PARAMS)
3581 ct = TypeManager.GetElementType (ct);
3585 if (best_params && best_pd.ParameterModifier (b_idx) == Parameter.Modifier.PARAMS)
3587 bt = TypeManager.GetElementType (bt);
3595 int result = BetterExpressionConversion (ec, a, ct, bt);
3597 // for each argument, the conversion to 'ct' should be no worse than
3598 // the conversion to 'bt'.
3602 // for at least one argument, the conversion to 'ct' should be better than
3603 // the conversion to 'bt'.
3605 better_at_least_one = true;
3608 if (better_at_least_one)
3612 // This handles the case
3614 // Add (float f1, float f2, float f3);
3615 // Add (params decimal [] foo);
3617 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3618 // first candidate would've chosen as better.
3624 // The two methods have equal parameter types. Now apply tie-breaking rules
3626 if (TypeManager.IsGenericMethod (best) && !TypeManager.IsGenericMethod (candidate))
3628 if (!TypeManager.IsGenericMethod (best) && TypeManager.IsGenericMethod (candidate))
3632 // This handles the following cases:
3634 // Trim () is better than Trim (params char[] chars)
3635 // Concat (string s1, string s2, string s3) is better than
3636 // Concat (string s1, params string [] srest)
3637 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3639 if (!candidate_params && best_params)
3641 if (candidate_params && !best_params)
3644 int candidate_param_count = candidate_pd.Count;
3645 int best_param_count = best_pd.Count;
3647 if (candidate_param_count != best_param_count)
3648 // can only happen if (candidate_params && best_params)
3649 return candidate_param_count > best_param_count;
3652 // now, both methods have the same number of parameters, and the parameters have the same types
3653 // Pick the "more specific" signature
3656 MethodBase orig_candidate = TypeManager.DropGenericMethodArguments (candidate);
3657 MethodBase orig_best = TypeManager.DropGenericMethodArguments (best);
3659 ParameterData orig_candidate_pd = TypeManager.GetParameterData (orig_candidate);
3660 ParameterData orig_best_pd = TypeManager.GetParameterData (orig_best);
3662 bool specific_at_least_once = false;
3663 for (int j = 0; j < candidate_param_count; ++j)
3665 Type ct = TypeManager.TypeToCoreType (orig_candidate_pd.ParameterType (j));
3666 Type bt = TypeManager.TypeToCoreType (orig_best_pd.ParameterType (j));
3669 Type specific = MoreSpecific (ct, bt);
3673 specific_at_least_once = true;
3676 if (specific_at_least_once)
3679 // FIXME: handle lifted operators
3685 protected override MemberExpr ResolveExtensionMemberAccess (Expression left)
3688 return base.ResolveExtensionMemberAccess (left);
3691 // When left side is an expression and at least one candidate method is
3692 // static, it can be extension method
3694 InstanceExpression = left;
3698 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3699 SimpleName original)
3701 if (!(left is TypeExpr) &&
3702 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3703 IdenticalTypeName = true;
3705 return base.ResolveMemberAccess (ec, left, loc, original);
3708 public override Expression CreateExpressionTree (EmitContext ec)
3710 Type t = best_candidate.IsConstructor ?
3711 typeof (ConstructorInfo) : typeof (MethodInfo);
3713 return new Cast (new TypeExpression (t, loc), new TypeOfMethod (best_candidate, loc));
3716 override public Expression DoResolve (EmitContext ec)
3718 if (InstanceExpression != null) {
3719 InstanceExpression = InstanceExpression.DoResolve (ec);
3720 if (InstanceExpression == null)
3727 public void ReportUsageError ()
3729 Report.Error (654, loc, "Method `" + DeclaringType + "." +
3730 Name + "()' is referenced without parentheses");
3733 override public void Emit (EmitContext ec)
3735 ReportUsageError ();
3738 public virtual void EmitArguments (EmitContext ec, ArrayList arguments)
3740 Invocation.EmitArguments (ec, arguments, false, null);
3743 public virtual void EmitCall (EmitContext ec, ArrayList arguments)
3745 Invocation.EmitCall (ec, IsBase, InstanceExpression, best_candidate, arguments, loc);
3748 protected virtual void Error_InvalidArguments (EmitContext ec, Location loc, int idx, MethodBase method,
3749 Argument a, ParameterData expected_par, Type paramType)
3751 if (a is CollectionElementInitializer.ElementInitializerArgument) {
3752 Report.SymbolRelatedToPreviousError (method);
3753 if ((expected_par.ParameterModifier (idx) & Parameter.Modifier.ISBYREF) != 0) {
3754 Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
3755 TypeManager.CSharpSignature (method));
3758 Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
3759 TypeManager.CSharpSignature (method));
3760 } else if (delegate_type == null) {
3761 Report.SymbolRelatedToPreviousError (method);
3762 Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
3763 TypeManager.CSharpSignature (method));
3765 Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
3766 TypeManager.CSharpName (delegate_type));
3768 Parameter.Modifier mod = expected_par.ParameterModifier (idx);
3770 string index = (idx + 1).ToString ();
3771 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
3772 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
3773 if ((mod & Parameter.Modifier.ISBYREF) == 0)
3774 Report.Error (1615, loc, "Argument `{0}' should not be passed with the `{1}' keyword",
3775 index, Parameter.GetModifierSignature (a.Modifier));
3777 Report.Error (1620, loc, "Argument `{0}' must be passed with the `{1}' keyword",
3778 index, Parameter.GetModifierSignature (mod));
3780 string p1 = a.GetSignatureForError ();
3781 string p2 = TypeManager.CSharpName (paramType);
3784 Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
3785 Report.SymbolRelatedToPreviousError (a.Expr.Type);
3786 Report.SymbolRelatedToPreviousError (paramType);
3788 Report.Error (1503, loc, "Argument {0}: Cannot convert type `{1}' to `{2}'", index, p1, p2);
3792 public override void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl)
3794 Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3795 Name, TypeManager.CSharpName (target));
3798 protected virtual int GetApplicableParametersCount (MethodBase method, ParameterData parameters)
3800 return parameters.Count;
3803 public static bool IsAncestralType (Type first_type, Type second_type)
3805 return first_type != second_type &&
3806 (TypeManager.IsSubclassOf (second_type, first_type) ||
3807 TypeManager.ImplementsInterface (second_type, first_type));
3811 /// Determines if the candidate method is applicable (section 14.4.2.1)
3812 /// to the given set of arguments
3813 /// A return value rates candidate method compatibility,
3814 /// 0 = the best, int.MaxValue = the worst
3816 public int IsApplicable (EmitContext ec,
3817 ArrayList arguments, int arg_count, ref MethodBase method, ref bool params_expanded_form)
3819 MethodBase candidate = method;
3821 ParameterData pd = TypeManager.GetParameterData (candidate);
3822 int param_count = GetApplicableParametersCount (candidate, pd);
3824 if (arg_count != param_count) {
3826 return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
3827 if (arg_count < param_count - 1)
3828 return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
3833 // 1. Handle generic method using type arguments when specified or type inference
3835 if (TypeManager.IsGenericMethod (candidate)) {
3836 if (type_arguments != null) {
3837 Type [] g_args = candidate.GetGenericArguments ();
3838 if (g_args.Length != type_arguments.Count)
3839 return int.MaxValue - 20000 + Math.Abs (type_arguments.Count - g_args.Length);
3841 // TODO: Don't create new method, create Parameters only
3842 method = ((MethodInfo) candidate).MakeGenericMethod (type_arguments.Arguments);
3844 pd = TypeManager.GetParameterData (candidate);
3846 int score = TypeManager.InferTypeArguments (ec, arguments, ref candidate);
3848 return score - 20000;
3850 if (TypeManager.IsGenericMethodDefinition (candidate))
3851 throw new InternalErrorException ("A generic method `{0}' definition took part in overload resolution",
3852 TypeManager.CSharpSignature (candidate));
3854 pd = TypeManager.GetParameterData (candidate);
3857 if (type_arguments != null)
3858 return int.MaxValue - 15000;
3863 // 2. Each argument has to be implicitly convertible to method parameter
3866 Parameter.Modifier p_mod = 0;
3868 for (int i = 0; i < arg_count; i++) {
3869 Argument a = (Argument) arguments [i];
3870 Parameter.Modifier a_mod = a.Modifier &
3871 ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3873 if (p_mod != Parameter.Modifier.PARAMS) {
3874 p_mod = pd.ParameterModifier (i) & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3876 if (p_mod == Parameter.Modifier.ARGLIST) {
3877 if (a.Type == TypeManager.runtime_argument_handle_type)
3883 pt = pd.ParameterType (i);
3885 params_expanded_form = true;
3889 if (!params_expanded_form)
3890 score = IsArgumentCompatible (ec, a_mod, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
3892 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0) {
3893 // It can be applicable in expanded form
3894 score = IsArgumentCompatible (ec, a_mod, a, 0, pt.GetElementType ());
3896 params_expanded_form = true;
3900 if (params_expanded_form)
3902 return (arg_count - i) * 2 + score;
3906 if (arg_count != param_count)
3907 params_expanded_form = true;
3912 int IsArgumentCompatible (EmitContext ec, Parameter.Modifier arg_mod, Argument argument, Parameter.Modifier param_mod, Type parameter)
3915 // Types have to be identical when ref or out modifer is used
3917 if (arg_mod != 0 || param_mod != 0) {
3918 if (TypeManager.HasElementType (parameter))
3919 parameter = parameter.GetElementType ();
3921 Type a_type = argument.Type;
3922 if (TypeManager.HasElementType (a_type))
3923 a_type = a_type.GetElementType ();
3925 if (a_type != parameter)
3931 // FIXME: Kill this abomination (EmitContext.TempEc)
3932 EmitContext prevec = EmitContext.TempEc;
3933 EmitContext.TempEc = ec;
3935 if (delegate_type != null ?
3936 !Delegate.IsTypeCovariant (argument.Expr, parameter) :
3937 !Convert.ImplicitConversionExists (ec, argument.Expr, parameter))
3940 if (arg_mod != param_mod)
3944 EmitContext.TempEc = prevec;
3950 public static bool IsOverride (MethodBase cand_method, MethodBase base_method)
3952 if (!IsAncestralType (base_method.DeclaringType, cand_method.DeclaringType))
3955 ParameterData cand_pd = TypeManager.GetParameterData (cand_method);
3956 ParameterData base_pd = TypeManager.GetParameterData (base_method);
3958 if (cand_pd.Count != base_pd.Count)
3961 for (int j = 0; j < cand_pd.Count; ++j)
3963 Parameter.Modifier cm = cand_pd.ParameterModifier (j);
3964 Parameter.Modifier bm = base_pd.ParameterModifier (j);
3965 Type ct = TypeManager.TypeToCoreType (cand_pd.ParameterType (j));
3966 Type bt = TypeManager.TypeToCoreType (base_pd.ParameterType (j));
3968 if (cm != bm || ct != bt)
3975 public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2, Location loc)
3977 MemberInfo [] miset;
3978 MethodGroupExpr union;
3983 return (MethodGroupExpr) mg2;
3986 return (MethodGroupExpr) mg1;
3989 MethodGroupExpr left_set = null, right_set = null;
3990 int length1 = 0, length2 = 0;
3992 left_set = (MethodGroupExpr) mg1;
3993 length1 = left_set.Methods.Length;
3995 right_set = (MethodGroupExpr) mg2;
3996 length2 = right_set.Methods.Length;
3998 ArrayList common = new ArrayList ();
4000 foreach (MethodBase r in right_set.Methods){
4001 if (TypeManager.ArrayContainsMethod (left_set.Methods, r))
4005 miset = new MemberInfo [length1 + length2 - common.Count];
4006 left_set.Methods.CopyTo (miset, 0);
4010 foreach (MethodBase r in right_set.Methods) {
4011 if (!common.Contains (r))
4015 union = new MethodGroupExpr (miset, mg1.Type, loc);
4020 static Type MoreSpecific (Type p, Type q)
4022 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4024 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4027 if (TypeManager.HasElementType (p))
4029 Type pe = TypeManager.GetElementType (p);
4030 Type qe = TypeManager.GetElementType (q);
4031 Type specific = MoreSpecific (pe, qe);
4037 else if (TypeManager.IsGenericType (p))
4039 Type[] pargs = TypeManager.GetTypeArguments (p);
4040 Type[] qargs = TypeManager.GetTypeArguments (q);
4042 bool p_specific_at_least_once = false;
4043 bool q_specific_at_least_once = false;
4045 for (int i = 0; i < pargs.Length; i++)
4047 Type specific = MoreSpecific (pargs [i], qargs [i]);
4048 if (specific == pargs [i])
4049 p_specific_at_least_once = true;
4050 if (specific == qargs [i])
4051 q_specific_at_least_once = true;
4054 if (p_specific_at_least_once && !q_specific_at_least_once)
4056 if (!p_specific_at_least_once && q_specific_at_least_once)
4064 /// Find the Applicable Function Members (7.4.2.1)
4066 /// me: Method Group expression with the members to select.
4067 /// it might contain constructors or methods (or anything
4068 /// that maps to a method).
4070 /// Arguments: ArrayList containing resolved Argument objects.
4072 /// loc: The location if we want an error to be reported, or a Null
4073 /// location for "probing" purposes.
4075 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4076 /// that is the best match of me on Arguments.
4079 public virtual MethodGroupExpr OverloadResolve (EmitContext ec, ref ArrayList Arguments,
4080 bool may_fail, Location loc)
4082 bool method_params = false;
4083 Type applicable_type = null;
4085 ArrayList candidates = new ArrayList (2);
4086 ArrayList candidate_overrides = null;
4089 // Used to keep a map between the candidate
4090 // and whether it is being considered in its
4091 // normal or expanded form
4093 // false is normal form, true is expanded form
4095 Hashtable candidate_to_form = null;
4097 if (Arguments != null)
4098 arg_count = Arguments.Count;
4100 if (RootContext.Version == LanguageVersion.ISO_1 && Name == "Invoke" && TypeManager.IsDelegateType (DeclaringType)) {
4102 Report.Error (1533, loc, "Invoke cannot be called directly on a delegate");
4106 int nmethods = Methods.Length;
4110 // Methods marked 'override' don't take part in 'applicable_type'
4111 // computation, nor in the actual overload resolution.
4112 // However, they still need to be emitted instead of a base virtual method.
4113 // So, we salt them away into the 'candidate_overrides' array.
4115 // In case of reflected methods, we replace each overriding method with
4116 // its corresponding base virtual method. This is to improve compatibility
4117 // with non-C# libraries which change the visibility of overrides (#75636)
4120 for (int i = 0; i < Methods.Length; ++i) {
4121 MethodBase m = Methods [i];
4122 if (TypeManager.IsOverride (m)) {
4123 if (candidate_overrides == null)
4124 candidate_overrides = new ArrayList ();
4125 candidate_overrides.Add (m);
4126 m = TypeManager.TryGetBaseDefinition (m);
4135 // Enable message recording, it's used mainly by lambda expressions
4137 Report.IMessageRecorder msg_recorder = new Report.MessageRecorder ();
4138 Report.IMessageRecorder prev_recorder = Report.SetMessageRecorder (msg_recorder);
4141 // First we construct the set of applicable methods
4143 bool is_sorted = true;
4144 int best_candidate_rate = int.MaxValue;
4145 for (int i = 0; i < nmethods; i++) {
4146 Type decl_type = Methods [i].DeclaringType;
4149 // If we have already found an applicable method
4150 // we eliminate all base types (Section 14.5.5.1)
4152 if (applicable_type != null && IsAncestralType (decl_type, applicable_type))
4156 // Check if candidate is applicable (section 14.4.2.1)
4158 bool params_expanded_form = false;
4159 int candidate_rate = IsApplicable (ec, Arguments, arg_count, ref Methods [i], ref params_expanded_form);
4161 if (candidate_rate < best_candidate_rate) {
4162 best_candidate_rate = candidate_rate;
4163 best_candidate = Methods [i];
4166 if (params_expanded_form) {
4167 if (candidate_to_form == null)
4168 candidate_to_form = new PtrHashtable ();
4169 MethodBase candidate = Methods [i];
4170 candidate_to_form [candidate] = candidate;
4173 if (candidate_rate != 0) {
4174 if (msg_recorder != null)
4175 msg_recorder.EndSession ();
4179 msg_recorder = null;
4180 candidates.Add (Methods [i]);
4182 if (applicable_type == null)
4183 applicable_type = decl_type;
4184 else if (applicable_type != decl_type) {
4186 if (IsAncestralType (applicable_type, decl_type))
4187 applicable_type = decl_type;
4191 Report.SetMessageRecorder (prev_recorder);
4192 if (msg_recorder != null && msg_recorder.PrintMessages ())
4195 int candidate_top = candidates.Count;
4197 if (applicable_type == null) {
4199 // When we found a top level method which does not match and it's
4200 // not an extension method. We start extension methods lookup from here
4202 if (InstanceExpression != null) {
4203 ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (type, Name, loc);
4204 if (ex_method_lookup != null) {
4205 ex_method_lookup.ExtensionExpression = InstanceExpression;
4206 ex_method_lookup.SetTypeArguments (type_arguments);
4207 return ex_method_lookup.OverloadResolve (ec, ref Arguments, may_fail, loc);
4215 // Okay so we have failed to find exact match so we
4216 // return error info about the closest match
4218 if (best_candidate != null) {
4219 if (CustomErrorHandler != null) {
4220 if (CustomErrorHandler.NoExactMatch (ec, best_candidate))
4224 ParameterData pd = TypeManager.GetParameterData (best_candidate);
4225 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4226 if (arg_count == pd.Count || pd.HasParams) {
4227 if (TypeManager.IsGenericMethodDefinition (best_candidate)) {
4228 if (type_arguments == null) {
4229 Report.Error (411, loc,
4230 "The type arguments for method `{0}' cannot be inferred from " +
4231 "the usage. Try specifying the type arguments explicitly",
4232 TypeManager.CSharpSignature (best_candidate));
4236 Type [] g_args = TypeManager.GetGenericArguments (best_candidate);
4237 if (type_arguments.Count != g_args.Length) {
4238 Report.SymbolRelatedToPreviousError (best_candidate);
4239 Report.Error (305, loc, "Using the generic method `{0}' requires `{1}' type argument(s)",
4240 TypeManager.CSharpSignature (best_candidate),
4241 g_args.Length.ToString ());
4245 if (type_arguments != null && !TypeManager.IsGenericMethod (best_candidate)) {
4246 Namespace.Error_TypeArgumentsCannotBeUsed (best_candidate, loc);
4251 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate, cand_params, may_fail, loc))
4256 if (almost_matched_members.Count != 0) {
4257 Error_MemberLookupFailed (ec.ContainerType, type, type, ".ctor",
4258 null, MemberTypes.Constructor, AllBindingFlags);
4263 // We failed to find any method with correct argument count
4265 if (Name == ConstructorInfo.ConstructorName) {
4266 Report.SymbolRelatedToPreviousError (type);
4267 Report.Error (1729, loc,
4268 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4269 TypeManager.CSharpName (type), arg_count);
4271 Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4272 Name, arg_count.ToString ());
4280 // At this point, applicable_type is _one_ of the most derived types
4281 // in the set of types containing the methods in this MethodGroup.
4282 // Filter the candidates so that they only contain methods from the
4283 // most derived types.
4286 int finalized = 0; // Number of finalized candidates
4289 // Invariant: applicable_type is a most derived type
4291 // We'll try to complete Section 14.5.5.1 for 'applicable_type' by
4292 // eliminating all it's base types. At the same time, we'll also move
4293 // every unrelated type to the end of the array, and pick the next
4294 // 'applicable_type'.
4296 Type next_applicable_type = null;
4297 int j = finalized; // where to put the next finalized candidate
4298 int k = finalized; // where to put the next undiscarded candidate
4299 for (int i = finalized; i < candidate_top; ++i) {
4300 MethodBase candidate = (MethodBase) candidates [i];
4301 Type decl_type = candidate.DeclaringType;
4303 if (decl_type == applicable_type) {
4304 candidates [k++] = candidates [j];
4305 candidates [j++] = candidates [i];
4309 if (IsAncestralType (decl_type, applicable_type))
4312 if (next_applicable_type != null &&
4313 IsAncestralType (decl_type, next_applicable_type))
4316 candidates [k++] = candidates [i];
4318 if (next_applicable_type == null ||
4319 IsAncestralType (next_applicable_type, decl_type))
4320 next_applicable_type = decl_type;
4323 applicable_type = next_applicable_type;
4326 } while (applicable_type != null);
4330 // Now we actually find the best method
4333 best_candidate = (MethodBase) candidates [0];
4334 if (delegate_type == null)
4335 method_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4337 for (int ix = 1; ix < candidate_top; ix++) {
4338 MethodBase candidate = (MethodBase) candidates [ix];
4340 if (candidate == best_candidate)
4343 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4345 if (BetterFunction (ec, Arguments, arg_count,
4346 candidate, cand_params,
4347 best_candidate, method_params)) {
4348 best_candidate = candidate;
4349 method_params = cand_params;
4353 // Now check that there are no ambiguities i.e the selected method
4354 // should be better than all the others
4356 MethodBase ambiguous = null;
4357 for (int ix = 1; ix < candidate_top; ix++) {
4358 MethodBase candidate = (MethodBase) candidates [ix];
4360 if (candidate == best_candidate)
4363 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4364 if (!BetterFunction (ec, Arguments, arg_count,
4365 best_candidate, method_params,
4366 candidate, cand_params))
4369 Report.SymbolRelatedToPreviousError (candidate);
4370 ambiguous = candidate;
4374 if (ambiguous != null) {
4375 Report.SymbolRelatedToPreviousError (best_candidate);
4376 Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4377 TypeManager.CSharpSignature (ambiguous), TypeManager.CSharpSignature (best_candidate));
4382 // If the method is a virtual function, pick an override closer to the LHS type.
4384 if (!IsBase && best_candidate.IsVirtual) {
4385 if (TypeManager.IsOverride (best_candidate))
4386 throw new InternalErrorException (
4387 "Should not happen. An 'override' method took part in overload resolution: " + best_candidate);
4389 if (candidate_overrides != null) {
4390 Type[] gen_args = null;
4391 bool gen_override = false;
4392 if (TypeManager.IsGenericMethod (best_candidate))
4393 gen_args = TypeManager.GetGenericArguments (best_candidate);
4395 foreach (MethodBase candidate in candidate_overrides) {
4396 if (TypeManager.IsGenericMethod (candidate)) {
4397 if (gen_args == null)
4400 if (gen_args.Length != TypeManager.GetGenericArguments (candidate).Length)
4403 if (gen_args != null)
4407 if (IsOverride (candidate, best_candidate)) {
4408 gen_override = true;
4409 best_candidate = candidate;
4413 if (gen_override && gen_args != null) {
4415 best_candidate = ((MethodInfo) best_candidate).MakeGenericMethod (gen_args);
4422 // And now check if the arguments are all
4423 // compatible, perform conversions if
4424 // necessary etc. and return if everything is
4427 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate,
4428 method_params, may_fail, loc))
4431 if (best_candidate == null)
4434 MethodBase the_method = TypeManager.DropGenericMethodArguments (best_candidate);
4436 if (the_method.IsGenericMethodDefinition &&
4437 !ConstraintChecker.CheckConstraints (ec, the_method, best_candidate, loc))
4441 IMethodData data = TypeManager.GetMethod (the_method);
4443 data.SetMemberIsUsed ();
4448 public override void SetTypeArguments (TypeArguments ta)
4450 type_arguments = ta;
4453 public bool VerifyArgumentsCompat (EmitContext ec, ref ArrayList arguments,
4454 int arg_count, MethodBase method,
4455 bool chose_params_expanded,
4456 bool may_fail, Location loc)
4458 ParameterData pd = TypeManager.GetParameterData (method);
4460 int errors = Report.Errors;
4461 Parameter.Modifier p_mod = 0;
4463 int a_idx = 0, a_pos = 0;
4465 ArrayList params_initializers = null;
4467 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4468 a = (Argument) arguments [a_idx];
4469 if (p_mod != Parameter.Modifier.PARAMS) {
4470 p_mod = pd.ParameterModifier (a_idx);
4471 pt = pd.ParameterType (a_idx);
4473 if (p_mod == Parameter.Modifier.ARGLIST) {
4474 if (a.Type != TypeManager.runtime_argument_handle_type)
4479 if (pt.IsPointer && !ec.InUnsafe) {
4486 if (p_mod == Parameter.Modifier.PARAMS) {
4487 if (chose_params_expanded) {
4488 params_initializers = new ArrayList (arg_count - a_idx);
4489 pt = TypeManager.GetElementType (pt);
4491 } else if (p_mod != 0) {
4492 pt = TypeManager.GetElementType (pt);
4497 // Types have to be identical when ref or out modifer is used
4499 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4500 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4503 if (!TypeManager.IsEqual (a.Expr.Type, pt))
4510 if (TypeManager.IsEqual (a.Type, pt)) {
4513 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4519 // Convert params arguments to an array initializer
4521 if (params_initializers != null) {
4522 params_initializers.Add (conv);
4523 arguments.RemoveAt (a_idx--);
4528 // Update the argument with the implicit conversion
4533 // Fill not provided arguments required by params modifier
4535 if (params_initializers == null && pd.HasParams && arg_count < pd.Count && a_idx + 1 == pd.Count) {
4536 if (arguments == null)
4537 arguments = new ArrayList (1);
4539 pt = pd.Types [GetApplicableParametersCount (method, pd) - 1];
4540 pt = TypeManager.GetElementType (pt);
4541 params_initializers = new ArrayList (0);
4544 if (a_idx == arg_count) {
4546 // Append an array argument with all params arguments
4548 if (params_initializers != null) {
4549 arguments.Add (new Argument (
4550 new ArrayCreation (new TypeExpression (pt, loc), "[]",
4551 params_initializers, loc).Resolve (ec)));
4556 if (!may_fail && Report.Errors == errors) {
4557 if (CustomErrorHandler != null)
4558 CustomErrorHandler.NoExactMatch (ec, best_candidate);
4560 Error_InvalidArguments (ec, loc, a_pos, method, a, pd, pt);
4566 public class ConstantExpr : MemberExpr
4570 public ConstantExpr (FieldInfo constant, Location loc)
4572 this.constant = constant;
4576 public override string Name {
4577 get { throw new NotImplementedException (); }
4580 public override bool IsInstance {
4581 get { return !IsStatic; }
4584 public override bool IsStatic {
4585 get { return constant.IsStatic; }
4588 public override Type DeclaringType {
4589 get { return constant.DeclaringType; }
4592 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc, SimpleName original)
4594 constant = TypeManager.GetGenericFieldDefinition (constant);
4596 IConstant ic = TypeManager.GetConstant (constant);
4598 if (constant.IsLiteral) {
4599 ic = new ExternalConstant (constant);
4601 ic = ExternalConstant.CreateDecimal (constant);
4602 // HACK: decimal field was not resolved as constant
4604 return new FieldExpr (constant, loc).ResolveMemberAccess (ec, left, loc, original);
4606 TypeManager.RegisterConstant (constant, ic);
4609 return base.ResolveMemberAccess (ec, left, loc, original);
4612 public override Expression CreateExpressionTree (EmitContext ec)
4614 throw new NotSupportedException ();
4617 public override Expression DoResolve (EmitContext ec)
4619 IConstant ic = TypeManager.GetConstant (constant);
4620 if (ic.ResolveValue ()) {
4621 if (!ec.IsInObsoleteScope)
4622 ic.CheckObsoleteness (loc);
4625 return ic.CreateConstantReference (loc);
4628 public override void Emit (EmitContext ec)
4630 throw new NotSupportedException ();
4633 public override string GetSignatureForError ()
4635 return TypeManager.GetFullNameSignature (constant);
4640 /// Fully resolved expression that evaluates to a Field
4642 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariable {
4643 public readonly FieldInfo FieldInfo;
4644 VariableInfo variable_info;
4646 LocalTemporary temp;
4648 bool in_initializer;
4650 public FieldExpr (FieldInfo fi, Location l, bool in_initializer):
4653 this.in_initializer = in_initializer;
4656 public FieldExpr (FieldInfo fi, Location l)
4659 eclass = ExprClass.Variable;
4660 type = TypeManager.TypeToCoreType (fi.FieldType);
4664 public override string Name {
4666 return FieldInfo.Name;
4670 public override bool IsInstance {
4672 return !FieldInfo.IsStatic;
4676 public override bool IsStatic {
4678 return FieldInfo.IsStatic;
4682 public override Type DeclaringType {
4684 return FieldInfo.DeclaringType;
4688 public override string GetSignatureForError ()
4690 return TypeManager.GetFullNameSignature (FieldInfo);
4693 public VariableInfo VariableInfo {
4695 return variable_info;
4699 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
4700 SimpleName original)
4702 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
4703 Type t = fi.FieldType;
4705 if (t.IsPointer && !ec.InUnsafe) {
4709 return base.ResolveMemberAccess (ec, left, loc, original);
4712 public override Expression CreateExpressionTree (EmitContext ec)
4714 Expression instance;
4715 if (InstanceExpression == null) {
4716 instance = new NullLiteral (loc);
4718 instance = InstanceExpression.CreateExpressionTree (ec);
4721 ArrayList args = new ArrayList (2);
4722 args.Add (new Argument (instance));
4723 args.Add (new Argument (CreateTypeOfExpression ()));
4724 return CreateExpressionFactoryCall ("Field", args);
4727 public Expression CreateTypeOfExpression ()
4729 return new TypeOfField (FieldInfo, loc);
4732 override public Expression DoResolve (EmitContext ec)
4734 return DoResolve (ec, false, false);
4737 Expression DoResolve (EmitContext ec, bool lvalue_instance, bool out_access)
4739 if (!FieldInfo.IsStatic){
4740 if (InstanceExpression == null){
4742 // This can happen when referencing an instance field using
4743 // a fully qualified type expression: TypeName.InstanceField = xxx
4745 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4749 // Resolve the field's instance expression while flow analysis is turned
4750 // off: when accessing a field "a.b", we must check whether the field
4751 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4753 if (lvalue_instance) {
4754 using (ec.With (EmitContext.Flags.DoFlowAnalysis, false)) {
4755 Expression right_side =
4756 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4757 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side, loc);
4760 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
4761 InstanceExpression = InstanceExpression.Resolve (ec, rf);
4764 if (InstanceExpression == null)
4767 using (ec.Set (EmitContext.Flags.OmitStructFlowAnalysis)) {
4768 InstanceExpression.CheckMarshalByRefAccess (ec);
4772 if (!in_initializer && !ec.IsInFieldInitializer) {
4773 ObsoleteAttribute oa;
4774 FieldBase f = TypeManager.GetField (FieldInfo);
4776 if (!ec.IsInObsoleteScope)
4777 f.CheckObsoleteness (loc);
4779 // To be sure that type is external because we do not register generated fields
4780 } else if (!(FieldInfo.DeclaringType is TypeBuilder)) {
4781 oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
4783 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
4787 AnonymousContainer am = ec.CurrentAnonymousMethod;
4789 if (!FieldInfo.IsStatic){
4790 if (!am.IsIterator && (ec.TypeContainer is Struct)){
4791 Report.Error (1673, loc,
4792 "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",
4799 IFixedBuffer fb = AttributeTester.GetFixedBuffer (FieldInfo);
4801 if (!ec.InFixedInitializer && ec.ContainerType.IsValueType) {
4802 Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4805 if (InstanceExpression.eclass != ExprClass.Variable) {
4806 Report.SymbolRelatedToPreviousError (FieldInfo);
4807 Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4808 TypeManager.GetFullNameSignature (FieldInfo));
4811 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4814 // If the instance expression is a local variable or parameter.
4815 IVariable var = InstanceExpression as IVariable;
4816 if ((var == null) || (var.VariableInfo == null))
4819 VariableInfo vi = var.VariableInfo;
4820 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
4823 variable_info = vi.GetSubStruct (FieldInfo.Name);
4827 static readonly int [] codes = {
4828 191, // instance, write access
4829 192, // instance, out access
4830 198, // static, write access
4831 199, // static, out access
4832 1648, // member of value instance, write access
4833 1649, // member of value instance, out access
4834 1650, // member of value static, write access
4835 1651 // member of value static, out access
4838 static readonly string [] msgs = {
4839 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4840 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4841 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4842 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4843 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4844 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4845 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4846 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4849 // The return value is always null. Returning a value simplifies calling code.
4850 Expression Report_AssignToReadonly (Expression right_side)
4853 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4857 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4859 Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4864 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4866 IVariable var = InstanceExpression as IVariable;
4867 if ((var != null) && (var.VariableInfo != null))
4868 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
4870 bool lvalue_instance = !FieldInfo.IsStatic && FieldInfo.DeclaringType.IsValueType;
4871 bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
4873 Expression e = DoResolve (ec, lvalue_instance, out_access);
4878 FieldBase fb = TypeManager.GetField (FieldInfo);
4882 if (FieldInfo.IsInitOnly) {
4883 // InitOnly fields can only be assigned in constructors or initializers
4884 if (!ec.IsInFieldInitializer && !ec.IsConstructor)
4885 return Report_AssignToReadonly (right_side);
4887 if (ec.IsConstructor) {
4888 Type ctype = ec.TypeContainer.CurrentType;
4890 ctype = ec.ContainerType;
4892 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4893 if (!TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
4894 return Report_AssignToReadonly (right_side);
4895 // static InitOnly fields cannot be assigned-to in an instance constructor
4896 if (IsStatic && !ec.IsStatic)
4897 return Report_AssignToReadonly (right_side);
4898 // instance constructors can't modify InitOnly fields of other instances of the same type
4899 if (!IsStatic && !(InstanceExpression is This))
4900 return Report_AssignToReadonly (right_side);
4904 if (right_side == EmptyExpression.OutAccess &&
4905 !IsStatic && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type)) {
4906 Report.SymbolRelatedToPreviousError (DeclaringType);
4907 Report.Warning (197, 1, loc,
4908 "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",
4909 GetSignatureForError ());
4915 bool is_marshal_by_ref ()
4917 return !IsStatic && Type.IsValueType && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type);
4920 public override void CheckMarshalByRefAccess (EmitContext ec)
4922 if (is_marshal_by_ref () && !(InstanceExpression is This)) {
4923 Report.SymbolRelatedToPreviousError (DeclaringType);
4924 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",
4925 GetSignatureForError ());
4929 public bool VerifyFixed ()
4931 IVariable variable = InstanceExpression as IVariable;
4932 // A variable of the form V.I is fixed when V is a fixed variable of a struct type.
4933 // We defer the InstanceExpression check after the variable check to avoid a
4934 // separate null check on InstanceExpression.
4935 return variable != null && InstanceExpression.Type.IsValueType && variable.VerifyFixed ();
4938 public override int GetHashCode ()
4940 return FieldInfo.GetHashCode ();
4943 public override bool Equals (object obj)
4945 FieldExpr fe = obj as FieldExpr;
4949 if (FieldInfo != fe.FieldInfo)
4952 if (InstanceExpression == null || fe.InstanceExpression == null)
4955 return InstanceExpression.Equals (fe.InstanceExpression);
4958 public void Emit (EmitContext ec, bool leave_copy)
4960 ILGenerator ig = ec.ig;
4961 bool is_volatile = false;
4963 FieldBase f = TypeManager.GetField (FieldInfo);
4965 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4968 f.SetMemberIsUsed ();
4971 if (FieldInfo.IsStatic){
4973 ig.Emit (OpCodes.Volatile);
4975 ig.Emit (OpCodes.Ldsfld, FieldInfo);
4978 EmitInstance (ec, false);
4980 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
4982 ig.Emit (OpCodes.Ldflda, FieldInfo);
4983 ig.Emit (OpCodes.Ldflda, ff.Element);
4986 ig.Emit (OpCodes.Volatile);
4988 ig.Emit (OpCodes.Ldfld, FieldInfo);
4993 ec.ig.Emit (OpCodes.Dup);
4994 if (!FieldInfo.IsStatic) {
4995 temp = new LocalTemporary (this.Type);
5001 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5003 FieldAttributes fa = FieldInfo.Attributes;
5004 bool is_static = (fa & FieldAttributes.Static) != 0;
5005 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
5006 ILGenerator ig = ec.ig;
5008 if (is_readonly && !ec.IsConstructor){
5009 Report_AssignToReadonly (source);
5014 // String concatenation creates a new string instance
5016 prepared = prepare_for_load && !(source is StringConcat);
5017 EmitInstance (ec, prepared);
5021 ec.ig.Emit (OpCodes.Dup);
5022 if (!FieldInfo.IsStatic) {
5023 temp = new LocalTemporary (this.Type);
5028 FieldBase f = TypeManager.GetField (FieldInfo);
5030 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
5031 ig.Emit (OpCodes.Volatile);
5037 ig.Emit (OpCodes.Stsfld, FieldInfo);
5039 ig.Emit (OpCodes.Stfld, FieldInfo);
5047 public override void Emit (EmitContext ec)
5052 public override void EmitSideEffect (EmitContext ec)
5054 FieldBase f = TypeManager.GetField (FieldInfo);
5055 bool is_volatile = f != null && (f.ModFlags & Modifiers.VOLATILE) != 0;
5057 if (is_volatile || is_marshal_by_ref ())
5058 base.EmitSideEffect (ec);
5061 public void AddressOf (EmitContext ec, AddressOp mode)
5063 ILGenerator ig = ec.ig;
5065 FieldBase f = TypeManager.GetField (FieldInfo);
5067 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
5068 Report.Warning (420, 1, loc, "`{0}': A volatile field references will not be treated as volatile",
5069 f.GetSignatureForError ());
5072 if ((mode & AddressOp.Store) != 0)
5074 if ((mode & AddressOp.Load) != 0)
5075 f.SetMemberIsUsed ();
5079 // Handle initonly fields specially: make a copy and then
5080 // get the address of the copy.
5083 if (FieldInfo.IsInitOnly){
5085 if (ec.IsConstructor){
5086 if (FieldInfo.IsStatic){
5098 local = ig.DeclareLocal (type);
5099 ig.Emit (OpCodes.Stloc, local);
5100 ig.Emit (OpCodes.Ldloca, local);
5105 if (FieldInfo.IsStatic){
5106 ig.Emit (OpCodes.Ldsflda, FieldInfo);
5109 EmitInstance (ec, false);
5110 ig.Emit (OpCodes.Ldflda, FieldInfo);
5117 /// Expression that evaluates to a Property. The Assign class
5118 /// might set the `Value' expression if we are in an assignment.
5120 /// This is not an LValue because we need to re-write the expression, we
5121 /// can not take data from the stack and store it.
5123 public class PropertyExpr : MemberExpr, IAssignMethod {
5124 public readonly PropertyInfo PropertyInfo;
5125 MethodInfo getter, setter;
5130 LocalTemporary temp;
5133 public PropertyExpr (Type container_type, PropertyInfo pi, Location l)
5136 eclass = ExprClass.PropertyAccess;
5140 type = TypeManager.TypeToCoreType (pi.PropertyType);
5142 ResolveAccessors (container_type);
5145 public override string Name {
5147 return PropertyInfo.Name;
5151 public override bool IsInstance {
5157 public override bool IsStatic {
5163 public override Expression CreateExpressionTree (EmitContext ec)
5165 if (IsSingleDimensionalArrayLength ()) {
5166 ArrayList args = new ArrayList (1);
5167 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5168 return CreateExpressionFactoryCall ("ArrayLength", args);
5171 // TODO: it's waiting for PropertyExpr refactoring
5172 //ArrayList args = new ArrayList (2);
5173 //args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5174 //args.Add (getter expression);
5175 //return CreateExpressionFactoryCall ("Property", args);
5176 return base.CreateExpressionTree (ec);
5179 public Expression CreateSetterTypeOfExpression ()
5181 return new Cast (new TypeExpression (typeof (MethodInfo), loc), new TypeOfMethod (setter, loc));
5184 public override Type DeclaringType {
5186 return PropertyInfo.DeclaringType;
5190 public override string GetSignatureForError ()
5192 return TypeManager.GetFullNameSignature (PropertyInfo);
5195 void FindAccessors (Type invocation_type)
5197 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
5198 BindingFlags.Static | BindingFlags.Instance |
5199 BindingFlags.DeclaredOnly;
5201 Type current = PropertyInfo.DeclaringType;
5202 for (; current != null; current = current.BaseType) {
5203 MemberInfo[] group = TypeManager.MemberLookup (
5204 invocation_type, invocation_type, current,
5205 MemberTypes.Property, flags, PropertyInfo.Name, null);
5210 if (group.Length != 1)
5211 // Oooops, can this ever happen ?
5214 PropertyInfo pi = (PropertyInfo) group [0];
5217 getter = pi.GetGetMethod (true);
5220 setter = pi.GetSetMethod (true);
5222 MethodInfo accessor = getter != null ? getter : setter;
5224 if (!accessor.IsVirtual)
5230 // We also perform the permission checking here, as the PropertyInfo does not
5231 // hold the information for the accessibility of its setter/getter
5233 // TODO: Refactor to use some kind of cache together with GetPropertyFromAccessor
5234 void ResolveAccessors (Type container_type)
5236 FindAccessors (container_type);
5238 if (getter != null) {
5239 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
5240 IMethodData md = TypeManager.GetMethod (the_getter);
5242 md.SetMemberIsUsed ();
5244 is_static = getter.IsStatic;
5247 if (setter != null) {
5248 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
5249 IMethodData md = TypeManager.GetMethod (the_setter);
5251 md.SetMemberIsUsed ();
5253 is_static = setter.IsStatic;
5257 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
5260 InstanceExpression = null;
5264 if (InstanceExpression == null) {
5265 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5269 InstanceExpression = InstanceExpression.DoResolve (ec);
5270 if (lvalue_instance && InstanceExpression != null)
5271 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
5273 if (InstanceExpression == null)
5276 InstanceExpression.CheckMarshalByRefAccess (ec);
5278 if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) &&
5279 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
5280 !TypeManager.IsNestedChildOf (ec.ContainerType, InstanceExpression.Type) &&
5281 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.ContainerType)) {
5282 Report.SymbolRelatedToPreviousError (PropertyInfo);
5283 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
5290 void Error_PropertyNotFound (MethodInfo mi, bool getter)
5292 // TODO: correctly we should compare arguments but it will lead to bigger changes
5293 if (mi is MethodBuilder) {
5294 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
5298 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
5300 ParameterData iparams = TypeManager.GetParameterData (mi);
5301 sig.Append (getter ? "get_" : "set_");
5303 sig.Append (iparams.GetSignatureForError ());
5305 Report.SymbolRelatedToPreviousError (mi);
5306 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
5307 Name, sig.ToString ());
5310 public bool IsAccessibleFrom (Type invocation_type, bool lvalue)
5313 MethodInfo accessor = lvalue ? setter : getter;
5314 if (accessor == null && lvalue)
5316 return accessor != null && IsAccessorAccessible (invocation_type, accessor, out dummy);
5319 bool IsSingleDimensionalArrayLength ()
5321 if (DeclaringType != TypeManager.array_type || getter == null || Name != "Length")
5324 string t_name = InstanceExpression.Type.Name;
5325 int t_name_len = t_name.Length;
5326 return t_name_len > 2 && t_name [t_name_len - 2] == '[' && t_name [t_name_len - 3] != ']';
5329 override public Expression DoResolve (EmitContext ec)
5334 if (getter != null){
5335 if (TypeManager.GetParameterData (getter).Count != 0){
5336 Error_PropertyNotFound (getter, true);
5341 if (getter == null){
5343 // The following condition happens if the PropertyExpr was
5344 // created, but is invalid (ie, the property is inaccessible),
5345 // and we did not want to embed the knowledge about this in
5346 // the caller routine. This only avoids double error reporting.
5351 if (InstanceExpression != EmptyExpression.Null) {
5352 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5353 TypeManager.GetFullNameSignature (PropertyInfo));
5358 bool must_do_cs1540_check = false;
5359 if (getter != null &&
5360 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
5361 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
5362 if (pm != null && pm.HasCustomAccessModifier) {
5363 Report.SymbolRelatedToPreviousError (pm);
5364 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5365 TypeManager.CSharpSignature (getter));
5368 Report.SymbolRelatedToPreviousError (getter);
5369 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
5374 if (!InstanceResolve (ec, false, must_do_cs1540_check))
5378 // Only base will allow this invocation to happen.
5380 if (IsBase && getter.IsAbstract) {
5381 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5385 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
5395 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
5397 if (right_side == EmptyExpression.OutAccess) {
5398 if (ec.CurrentBlock.Toplevel.GetTransparentIdentifier (PropertyInfo.Name) != null) {
5399 Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5402 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as `ref' or `out' parameter",
5403 GetSignatureForError ());
5408 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5409 Error_CannotModifyIntermediateExpressionValue (ec);
5412 if (setter == null){
5414 // The following condition happens if the PropertyExpr was
5415 // created, but is invalid (ie, the property is inaccessible),
5416 // and we did not want to embed the knowledge about this in
5417 // the caller routine. This only avoids double error reporting.
5421 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
5422 GetSignatureForError ());
5426 if (TypeManager.GetParameterData (setter).Count != 1){
5427 Error_PropertyNotFound (setter, false);
5431 bool must_do_cs1540_check;
5432 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
5433 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
5434 if (pm != null && pm.HasCustomAccessModifier) {
5435 Report.SymbolRelatedToPreviousError (pm);
5436 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5437 TypeManager.CSharpSignature (setter));
5440 Report.SymbolRelatedToPreviousError (setter);
5441 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
5446 if (!InstanceResolve (ec, PropertyInfo.DeclaringType.IsValueType, must_do_cs1540_check))
5450 // Only base will allow this invocation to happen.
5452 if (IsBase && setter.IsAbstract){
5453 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5460 public override void Emit (EmitContext ec)
5465 public void Emit (EmitContext ec, bool leave_copy)
5468 // Special case: length of single dimension array property is turned into ldlen
5470 if (IsSingleDimensionalArrayLength ()) {
5472 EmitInstance (ec, false);
5473 ec.ig.Emit (OpCodes.Ldlen);
5474 ec.ig.Emit (OpCodes.Conv_I4);
5478 Invocation.EmitCall (ec, IsBase, InstanceExpression, getter, null, loc, prepared, false);
5481 ec.ig.Emit (OpCodes.Dup);
5483 temp = new LocalTemporary (this.Type);
5490 // Implements the IAssignMethod interface for assignments
5492 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5494 Expression my_source = source;
5496 if (prepare_for_load) {
5497 if (source is StringConcat)
5498 EmitInstance (ec, false);
5506 ec.ig.Emit (OpCodes.Dup);
5508 temp = new LocalTemporary (this.Type);
5512 } else if (leave_copy) {
5514 temp = new LocalTemporary (this.Type);
5519 ArrayList args = new ArrayList (1);
5520 args.Add (new Argument (my_source, Argument.AType.Expression));
5522 Invocation.EmitCall (ec, IsBase, InstanceExpression, setter, args, loc, false, prepared);
5532 /// Fully resolved expression that evaluates to an Event
5534 public class EventExpr : MemberExpr {
5535 public readonly EventInfo EventInfo;
5538 MethodInfo add_accessor, remove_accessor;
5540 public EventExpr (EventInfo ei, Location loc)
5544 eclass = ExprClass.EventAccess;
5546 add_accessor = TypeManager.GetAddMethod (ei);
5547 remove_accessor = TypeManager.GetRemoveMethod (ei);
5548 if (add_accessor.IsStatic || remove_accessor.IsStatic)
5551 if (EventInfo is MyEventBuilder){
5552 MyEventBuilder eb = (MyEventBuilder) EventInfo;
5553 type = eb.EventType;
5556 type = EventInfo.EventHandlerType;
5559 public override string Name {
5561 return EventInfo.Name;
5565 public override bool IsInstance {
5571 public override bool IsStatic {
5577 public override Type DeclaringType {
5579 return EventInfo.DeclaringType;
5583 void Error_AssignmentEventOnly ()
5585 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5586 GetSignatureForError ());
5589 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
5590 SimpleName original)
5593 // If the event is local to this class, we transform ourselves into a FieldExpr
5596 if (EventInfo.DeclaringType == ec.ContainerType ||
5597 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
5598 EventField mi = TypeManager.GetEventField (EventInfo);
5601 if (!ec.IsInObsoleteScope)
5602 mi.CheckObsoleteness (loc);
5604 if ((mi.ModFlags & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0 && !ec.IsInCompoundAssignment)
5605 Error_AssignmentEventOnly ();
5607 FieldExpr ml = new FieldExpr (mi.FieldBuilder, loc);
5609 InstanceExpression = null;
5611 return ml.ResolveMemberAccess (ec, left, loc, original);
5615 if (left is This && !ec.IsInCompoundAssignment)
5616 Error_AssignmentEventOnly ();
5618 return base.ResolveMemberAccess (ec, left, loc, original);
5622 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
5625 InstanceExpression = null;
5629 if (InstanceExpression == null) {
5630 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5634 InstanceExpression = InstanceExpression.DoResolve (ec);
5635 if (InstanceExpression == null)
5638 if (IsBase && add_accessor.IsAbstract) {
5639 Error_CannotCallAbstractBase(TypeManager.CSharpSignature(add_accessor));
5644 // This is using the same mechanism as the CS1540 check in PropertyExpr.
5645 // However, in the Event case, we reported a CS0122 instead.
5647 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
5648 InstanceExpression.Type != ec.ContainerType &&
5649 TypeManager.IsSubclassOf (ec.ContainerType, InstanceExpression.Type)) {
5650 Report.SymbolRelatedToPreviousError (EventInfo);
5651 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5658 public bool IsAccessibleFrom (Type invocation_type)
5661 return IsAccessorAccessible (invocation_type, add_accessor, out dummy) &&
5662 IsAccessorAccessible (invocation_type, remove_accessor, out dummy);
5665 public override Expression CreateExpressionTree (EmitContext ec)
5667 throw new NotSupportedException ();
5670 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5672 return DoResolve (ec);
5675 public override Expression DoResolve (EmitContext ec)
5677 bool must_do_cs1540_check;
5678 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
5679 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
5680 Report.SymbolRelatedToPreviousError (EventInfo);
5681 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5685 if (!InstanceResolve (ec, must_do_cs1540_check))
5691 public override void Emit (EmitContext ec)
5693 Report.Error (70, loc, "The event `{0}' can only appear on the left hand side of += or -= "+
5694 "(except on the defining type)", GetSignatureForError ());
5697 public override string GetSignatureForError ()
5699 return TypeManager.CSharpSignature (EventInfo);
5702 public void EmitAddOrRemove (EmitContext ec, Expression source)
5704 BinaryDelegate source_del = source as BinaryDelegate;
5705 if (source_del == null) {
5709 Expression handler = source_del.Right;
5711 Argument arg = new Argument (handler, Argument.AType.Expression);
5712 ArrayList args = new ArrayList ();
5716 if (source_del.IsAddition)
5717 Invocation.EmitCall (
5718 ec, IsBase, InstanceExpression, add_accessor, args, loc);
5720 Invocation.EmitCall (
5721 ec, IsBase, InstanceExpression, remove_accessor, args, loc);
5725 public class TemporaryVariable : Expression, IMemoryLocation
5730 public TemporaryVariable (Type type, Location loc)
5734 eclass = ExprClass.Value;
5737 public override Expression DoResolve (EmitContext ec)
5742 TypeExpr te = new TypeExpression (type, loc);
5743 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
5744 if (!li.Resolve (ec))
5747 if (ec.MustCaptureVariable (li)) {
5748 ScopeInfo scope = li.Block.CreateScopeInfo ();
5749 var = scope.AddLocal (li);
5756 public Variable Variable {
5757 get { return var != null ? var : li.Variable; }
5760 public override void Emit (EmitContext ec)
5762 Variable.EmitInstance (ec);
5766 public void EmitLoadAddress (EmitContext ec)
5768 Variable.EmitInstance (ec);
5769 Variable.EmitAddressOf (ec);
5772 public void Store (EmitContext ec, Expression right_side)
5774 Variable.EmitInstance (ec);
5775 right_side.Emit (ec);
5776 Variable.EmitAssign (ec);
5779 public void EmitThis (EmitContext ec)
5781 Variable.EmitInstance (ec);
5784 public void EmitStore (EmitContext ec)
5786 Variable.EmitAssign (ec);
5789 public void AddressOf (EmitContext ec, AddressOp mode)
5791 EmitLoadAddress (ec);
5796 /// Handles `var' contextual keyword; var becomes a keyword only
5797 /// if no type called var exists in a variable scope
5799 public class VarExpr : SimpleName
5801 // Used for error reporting only
5802 ArrayList initializer;
5804 public VarExpr (Location loc)
5809 public ArrayList VariableInitializer {
5811 this.initializer = value;
5815 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5818 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
5820 type = right_side.Type;
5821 if (type == TypeManager.null_type || type == TypeManager.void_type || type == TypeManager.anonymous_method_type) {
5822 Report.Error (815, loc, "An implicitly typed local variable declaration cannot be initialized with `{0}'",
5823 right_side.GetSignatureForError ());
5827 eclass = ExprClass.Variable;
5831 protected override void Error_TypeOrNamespaceNotFound (IResolveContext ec)
5833 Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");
5836 public override TypeExpr ResolveAsContextualType (IResolveContext rc, bool silent)
5838 TypeExpr te = base.ResolveAsContextualType (rc, true);
5842 if (initializer == null)
5845 if (initializer.Count > 1) {
5846 Location loc = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [1]).Location;
5847 Report.Error (819, loc, "An implicitly typed local variable declaration cannot include multiple declarators");
5852 Expression variable_initializer = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [0]).expression_or_array_initializer;
5853 if (variable_initializer == null) {
5854 Report.Error (818, loc, "An implicitly typed local variable declarator must include an initializer");