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 // Unresolved type name expressions
2252 public abstract class ATypeNameExpression : Expression
2254 public readonly string Name;
2255 protected TypeArguments targs;
2257 protected ATypeNameExpression (string name, Location l)
2263 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2270 public override void Emit (EmitContext ec)
2272 throw new InternalErrorException ("ATypeNameExpression found in resolved tree");
2275 public override string GetSignatureForError ()
2277 if (targs != null) {
2278 return TypeManager.RemoveGenericArity (Name) + "<" +
2279 targs.GetSignatureForError () + ">";
2287 /// SimpleName expressions are formed of a single word and only happen at the beginning
2288 /// of a dotted-name.
2290 public class SimpleName : ATypeNameExpression {
2293 public SimpleName (string name, Location l)
2298 public SimpleName (string name, TypeArguments args, Location l)
2299 : base (name, args, l)
2303 public SimpleName (string name, TypeParameter[] type_params, Location l)
2306 targs = new TypeArguments (l);
2307 foreach (TypeParameter type_param in type_params)
2308 targs.Add (new TypeParameterExpr (type_param, l));
2311 public static string RemoveGenericArity (string name)
2314 StringBuilder sb = null;
2316 int pos = name.IndexOf ('`', start);
2321 sb.Append (name.Substring (start));
2326 sb = new StringBuilder ();
2327 sb.Append (name.Substring (start, pos-start));
2330 while ((pos < name.Length) && Char.IsNumber (name [pos]))
2334 } while (start < name.Length);
2336 return sb.ToString ();
2339 public SimpleName GetMethodGroup ()
2341 return new SimpleName (RemoveGenericArity (Name), targs, loc);
2344 public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
2346 if (ec.IsInFieldInitializer)
2347 Report.Error (236, l,
2348 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2352 120, l, "`{0}': An object reference is required for the nonstatic field, method or property",
2356 public bool IdenticalNameAndTypeName (EmitContext ec, Expression resolved_to, Location loc)
2358 return resolved_to != null && resolved_to.Type != null &&
2359 resolved_to.Type.Name == Name &&
2360 (ec.DeclContainer.LookupNamespaceOrType (Name, loc, /* ignore_cs0104 = */ true) != null);
2363 public override Expression DoResolve (EmitContext ec)
2365 return SimpleNameResolve (ec, null, false);
2368 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
2370 return SimpleNameResolve (ec, right_side, false);
2374 public Expression DoResolve (EmitContext ec, bool intermediate)
2376 return SimpleNameResolve (ec, null, intermediate);
2379 static bool IsNestedChild (Type t, Type parent)
2381 while (parent != null) {
2382 if (TypeManager.IsNestedChildOf (t, TypeManager.DropGenericTypeArguments (parent)))
2385 parent = parent.BaseType;
2391 FullNamedExpression ResolveNested (IResolveContext ec, Type t)
2393 if (!TypeManager.IsGenericTypeDefinition (t) && !TypeManager.IsGenericType (t))
2396 DeclSpace ds = ec.DeclContainer;
2397 while (ds != null && !IsNestedChild (t, ds.TypeBuilder))
2403 Type[] gen_params = TypeManager.GetTypeArguments (t);
2405 int arg_count = targs != null ? targs.Count : 0;
2407 for (; (ds != null) && ds.IsGeneric; ds = ds.Parent) {
2408 if (arg_count + ds.CountTypeParameters == gen_params.Length) {
2409 TypeArguments new_args = new TypeArguments (loc);
2410 foreach (TypeParameter param in ds.TypeParameters)
2411 new_args.Add (new TypeParameterExpr (param, loc));
2414 new_args.Add (targs);
2416 return new ConstructedType (t, new_args, loc);
2423 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2425 FullNamedExpression fne = ec.GenericDeclContainer.LookupGeneric (Name, loc);
2427 return fne.ResolveAsTypeStep (ec, silent);
2429 int errors = Report.Errors;
2430 fne = ec.DeclContainer.LookupNamespaceOrType (Name, loc, /*ignore_cs0104=*/ false);
2433 if (fne.Type == null)
2436 FullNamedExpression nested = ResolveNested (ec, fne.Type);
2438 return nested.ResolveAsTypeStep (ec, false);
2440 if (targs != null) {
2441 ConstructedType ct = new ConstructedType (fne, targs, loc);
2442 return ct.ResolveAsTypeStep (ec, false);
2448 if (silent || errors != Report.Errors)
2451 Error_TypeOrNamespaceNotFound (ec);
2455 protected virtual void Error_TypeOrNamespaceNotFound (IResolveContext ec)
2457 MemberCore mc = ec.DeclContainer.GetDefinition (Name);
2459 Error_UnexpectedKind (ec.DeclContainer, "type", GetMemberType (mc), loc);
2463 string ns = ec.DeclContainer.NamespaceEntry.NS.Name;
2464 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2465 foreach (Assembly a in RootNamespace.Global.Assemblies) {
2466 Type type = a.GetType (fullname);
2468 Report.SymbolRelatedToPreviousError (type);
2469 Expression.ErrorIsInaccesible (loc, TypeManager.CSharpName (type));
2474 Type t = ec.DeclContainer.LookupAnyGeneric (Name);
2476 Namespace.Error_InvalidNumberOfTypeArguments (t, loc);
2480 if (targs != null) {
2481 FullNamedExpression retval = ec.DeclContainer.LookupNamespaceOrType (SimpleName.RemoveGenericArity (Name), loc, true);
2482 if (retval != null) {
2483 Namespace.Error_TypeArgumentsCannotBeUsed (retval.Type, loc);
2488 NamespaceEntry.Error_NamespaceNotFound (loc, Name);
2491 // TODO: I am still not convinced about this. If someone else will need it
2492 // implement this as virtual property in MemberCore hierarchy
2493 public static string GetMemberType (MemberCore mc)
2499 if (mc is FieldBase)
2501 if (mc is MethodCore)
2503 if (mc is EnumMember)
2511 Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2517 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2523 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2530 /// 7.5.2: Simple Names.
2532 /// Local Variables and Parameters are handled at
2533 /// parse time, so they never occur as SimpleNames.
2535 /// The `intermediate' flag is used by MemberAccess only
2536 /// and it is used to inform us that it is ok for us to
2537 /// avoid the static check, because MemberAccess might end
2538 /// up resolving the Name as a Type name and the access as
2539 /// a static type access.
2541 /// ie: Type Type; .... { Type.GetType (""); }
2543 /// Type is both an instance variable and a Type; Type.GetType
2544 /// is the static method not an instance method of type.
2546 Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2548 Expression e = null;
2551 // Stage 1: Performed by the parser (binding to locals or parameters).
2553 Block current_block = ec.CurrentBlock;
2554 if (current_block != null){
2555 LocalInfo vi = current_block.GetLocalInfo (Name);
2557 if (targs != null) {
2558 Report.Error (307, loc,
2559 "The variable `{0}' cannot be used with type arguments",
2564 LocalVariableReference var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2565 if (right_side != null) {
2566 return var.ResolveLValue (ec, right_side, loc);
2568 ResolveFlags rf = ResolveFlags.VariableOrValue;
2570 rf |= ResolveFlags.DisableFlowAnalysis;
2571 return var.Resolve (ec, rf);
2575 ParameterReference pref = current_block.Toplevel.GetParameterReference (Name, loc);
2577 if (targs != null) {
2578 Report.Error (307, loc,
2579 "The variable `{0}' cannot be used with type arguments",
2584 if (right_side != null)
2585 return pref.ResolveLValue (ec, right_side, loc);
2587 return pref.Resolve (ec);
2590 Expression expr = current_block.Toplevel.GetTransparentIdentifier (Name);
2592 if (right_side != null)
2593 return expr.ResolveLValue (ec, right_side, loc);
2594 return expr.Resolve (ec);
2599 // Stage 2: Lookup members
2602 Type almost_matched_type = null;
2603 ArrayList almost_matched = null;
2604 for (DeclSpace lookup_ds = ec.DeclContainer; lookup_ds != null; lookup_ds = lookup_ds.Parent) {
2605 // either RootDeclSpace or GenericMethod
2606 if (lookup_ds.TypeBuilder == null)
2609 e = MemberLookup (ec.ContainerType, lookup_ds.TypeBuilder, Name, loc);
2611 if (e is PropertyExpr) {
2612 // since TypeManager.MemberLookup doesn't know if we're doing a lvalue access or not,
2613 // it doesn't know which accessor to check permissions against
2614 if (((PropertyExpr) e).IsAccessibleFrom (ec.ContainerType, right_side != null))
2616 } else if (e is EventExpr) {
2617 if (((EventExpr) e).IsAccessibleFrom (ec.ContainerType))
2625 if (almost_matched == null && almost_matched_members.Count > 0) {
2626 almost_matched_type = lookup_ds.TypeBuilder;
2627 almost_matched = (ArrayList) almost_matched_members.Clone ();
2632 if (almost_matched == null && almost_matched_members.Count > 0) {
2633 almost_matched_type = ec.ContainerType;
2634 almost_matched = (ArrayList) almost_matched_members.Clone ();
2636 e = ResolveAsTypeStep (ec, true);
2640 if (current_block != null) {
2641 IKnownVariable ikv = current_block.Explicit.GetKnownVariable (Name);
2643 LocalInfo li = ikv as LocalInfo;
2644 // Supress CS0219 warning
2648 Error_VariableIsUsedBeforeItIsDeclared (Name);
2653 if (almost_matched != null)
2654 almost_matched_members = almost_matched;
2655 if (almost_matched_type == null)
2656 almost_matched_type = ec.ContainerType;
2657 Error_MemberLookupFailed (ec.ContainerType, null, almost_matched_type, Name,
2658 ec.DeclContainer.Name, AllMemberTypes, AllBindingFlags);
2662 if (e is TypeExpr) {
2666 ConstructedType ct = new ConstructedType (
2667 (FullNamedExpression) e, targs, loc);
2668 return ct.ResolveAsTypeStep (ec, false);
2671 if (e is MemberExpr) {
2672 MemberExpr me = (MemberExpr) e;
2675 if (me.IsInstance) {
2676 if (ec.IsStatic || ec.IsInFieldInitializer) {
2678 // Note that an MemberExpr can be both IsInstance and IsStatic.
2679 // An unresolved MethodGroupExpr can contain both kinds of methods
2680 // and each predicate is true if the MethodGroupExpr contains
2681 // at least one of that kind of method.
2685 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2686 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2691 // Pass the buck to MemberAccess and Invocation.
2693 left = EmptyExpression.Null;
2695 left = ec.GetThis (loc);
2698 left = new TypeExpression (ec.ContainerType, loc);
2701 me = me.ResolveMemberAccess (ec, left, loc, null);
2705 if (targs != null) {
2707 me.SetTypeArguments (targs);
2710 if (!me.IsStatic && (me.InstanceExpression != null) &&
2711 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2712 me.InstanceExpression.Type != me.DeclaringType &&
2713 !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2714 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2715 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2716 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2720 return (right_side != null)
2721 ? me.DoResolveLValue (ec, right_side)
2722 : me.DoResolve (ec);
2728 protected override void CloneTo (CloneContext clonectx, Expression target)
2730 // CloneTo: Nothing, we do not keep any state on this expression
2735 /// Represents a namespace or a type. The name of the class was inspired by
2736 /// section 10.8.1 (Fully Qualified Names).
2738 public abstract class FullNamedExpression : Expression {
2739 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2744 public abstract string FullName {
2750 /// Expression that evaluates to a type
2752 public abstract class TypeExpr : FullNamedExpression {
2753 override public FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2755 TypeExpr t = DoResolveAsTypeStep (ec);
2759 eclass = ExprClass.Type;
2763 override public Expression DoResolve (EmitContext ec)
2765 return ResolveAsTypeTerminal (ec, false);
2768 override public void Emit (EmitContext ec)
2770 throw new Exception ("Should never be called");
2773 public virtual bool CheckAccessLevel (DeclSpace ds)
2775 return ds.CheckAccessLevel (Type);
2778 public virtual bool AsAccessible (DeclSpace ds)
2780 return ds.IsAccessibleAs (Type);
2783 public virtual bool IsClass {
2784 get { return Type.IsClass; }
2787 public virtual bool IsValueType {
2788 get { return Type.IsValueType; }
2791 public virtual bool IsInterface {
2792 get { return Type.IsInterface; }
2795 public virtual bool IsSealed {
2796 get { return Type.IsSealed; }
2799 public virtual bool CanInheritFrom ()
2801 if (Type == TypeManager.enum_type ||
2802 (Type == TypeManager.value_type && RootContext.StdLib) ||
2803 Type == TypeManager.multicast_delegate_type ||
2804 Type == TypeManager.delegate_type ||
2805 Type == TypeManager.array_type)
2811 protected abstract TypeExpr DoResolveAsTypeStep (IResolveContext ec);
2813 public abstract string Name {
2817 public override bool Equals (object obj)
2819 TypeExpr tobj = obj as TypeExpr;
2823 return Type == tobj.Type;
2826 public override int GetHashCode ()
2828 return Type.GetHashCode ();
2831 public override string ToString ()
2838 /// Fully resolved Expression that already evaluated to a type
2840 public class TypeExpression : TypeExpr {
2841 public TypeExpression (Type t, Location l)
2844 eclass = ExprClass.Type;
2848 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2853 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2858 public override string Name {
2859 get { return Type.ToString (); }
2862 public override string FullName {
2863 get { return Type.FullName; }
2868 /// Used to create types from a fully qualified name. These are just used
2869 /// by the parser to setup the core types. A TypeLookupExpression is always
2870 /// classified as a type.
2872 public sealed class TypeLookupExpression : TypeExpr {
2873 readonly string name;
2875 public TypeLookupExpression (string name)
2878 eclass = ExprClass.Type;
2881 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2883 // It's null for corlib compilation only
2885 return DoResolveAsTypeStep (ec);
2890 private class UnexpectedType
2894 // This performes recursive type lookup, providing support for generic types.
2895 // For example, given the type:
2897 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]]
2899 // The types will be checked in the following order:
2902 // System.Collections |
2903 // System.Collections.Generic |
2905 // System | recursive call 1 |
2906 // System.Int32 _| | main method call
2908 // System | recursive call 2 |
2909 // System.String _| |
2911 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]] _|
2913 private Type TypeLookup (IResolveContext ec, string name)
2918 FullNamedExpression resolved = null;
2920 Type recursive_type = null;
2921 while (index < name.Length) {
2922 if (name[index] == '[') {
2927 if (name[index] == '[')
2929 else if (name[index] == ']')
2931 } while (braces > 0);
2932 recursive_type = TypeLookup (ec, name.Substring (open + 1, index - open - 1));
2933 if (recursive_type == null || (recursive_type == typeof(UnexpectedType)))
2934 return recursive_type;
2937 if (name[index] == ',')
2939 else if ((name[index] == '.' && !done) || (index == name.Length && name[0] != '[')) {
2940 string substring = name.Substring(dot, index - dot);
2942 if (resolved == null)
2943 resolved = RootNamespace.Global.Lookup (ec.DeclContainer, substring, Location.Null);
2944 else if (resolved is Namespace)
2945 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
2946 else if (type != null)
2947 type = TypeManager.GetNestedType (type, substring);
2951 if (resolved == null)
2953 else if (type == null && resolved is TypeExpr)
2954 type = resolved.Type;
2961 if (name[0] != '[') {
2962 string substring = name.Substring(dot, index - dot);
2965 return TypeManager.GetNestedType (type, substring);
2967 if (resolved != null) {
2968 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
2969 if (resolved is TypeExpr)
2970 return resolved.Type;
2972 if (resolved == null)
2975 resolved.Error_UnexpectedKind (ec.DeclContainer, "type", loc);
2976 return typeof (UnexpectedType);
2982 return recursive_type;
2985 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2987 Type t = TypeLookup (ec, name);
2989 NamespaceEntry.Error_NamespaceNotFound (loc, name);
2992 if (t == typeof(UnexpectedType))
2998 public override string Name {
2999 get { return name; }
3002 public override string FullName {
3003 get { return name; }
3006 protected override void CloneTo (CloneContext clonectx, Expression target)
3008 // CloneTo: Nothing, we do not keep any state on this expression
3011 public override string GetSignatureForError ()
3014 return TypeManager.CSharpName (name);
3016 return base.GetSignatureForError ();
3021 /// Represents an "unbound generic type", ie. typeof (Foo<>).
3024 public class UnboundTypeExpression : TypeExpr
3028 public UnboundTypeExpression (MemberName name, Location l)
3034 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
3037 if (name.Left != null) {
3038 Expression lexpr = name.Left.GetTypeExpression ();
3039 expr = new MemberAccess (lexpr, name.Basename);
3041 expr = new SimpleName (name.Basename, loc);
3044 FullNamedExpression fne = expr.ResolveAsTypeStep (ec, false);
3049 return new TypeExpression (type, loc);
3052 public override string Name {
3053 get { return name.PrettyName; }
3056 public override string FullName {
3057 get { return name.FullyQualifiedName; }
3061 public class TypeAliasExpression : TypeExpr {
3062 FullNamedExpression alias;
3067 public TypeAliasExpression (FullNamedExpression alias, TypeArguments args, Location l)
3073 eclass = ExprClass.Type;
3075 name = alias.FullName + "<" + args.ToString () + ">";
3077 name = alias.FullName;
3080 public override string Name {
3081 get { return alias.FullName; }
3084 public override string FullName {
3085 get { return name; }
3088 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
3090 texpr = alias.ResolveAsTypeTerminal (ec, false);
3094 Type type = texpr.Type;
3095 int num_args = TypeManager.GetNumberOfTypeArguments (type);
3098 if (num_args == 0) {
3099 Report.Error (308, loc,
3100 "The non-generic type `{0}' cannot " +
3101 "be used with type arguments.",
3102 TypeManager.CSharpName (type));
3106 ConstructedType ctype = new ConstructedType (type, args, loc);
3107 return ctype.ResolveAsTypeTerminal (ec, false);
3108 } else if (num_args > 0) {
3109 Report.Error (305, loc,
3110 "Using the generic type `{0}' " +
3111 "requires {1} type arguments",
3112 TypeManager.CSharpName (type), num_args.ToString ());
3119 public override bool CheckAccessLevel (DeclSpace ds)
3121 return texpr.CheckAccessLevel (ds);
3124 public override bool AsAccessible (DeclSpace ds)
3126 return texpr.AsAccessible (ds);
3129 public override bool IsClass {
3130 get { return texpr.IsClass; }
3133 public override bool IsValueType {
3134 get { return texpr.IsValueType; }
3137 public override bool IsInterface {
3138 get { return texpr.IsInterface; }
3141 public override bool IsSealed {
3142 get { return texpr.IsSealed; }
3147 /// This class denotes an expression which evaluates to a member
3148 /// of a struct or a class.
3150 public abstract class MemberExpr : Expression
3152 protected bool is_base;
3155 /// The name of this member.
3157 public abstract string Name {
3162 // When base.member is used
3164 public bool IsBase {
3165 get { return is_base; }
3166 set { is_base = value; }
3170 /// Whether this is an instance member.
3172 public abstract bool IsInstance {
3177 /// Whether this is a static member.
3179 public abstract bool IsStatic {
3184 /// The type which declares this member.
3186 public abstract Type DeclaringType {
3191 /// The instance expression associated with this member, if it's a
3192 /// non-static member.
3194 public Expression InstanceExpression;
3196 public static void error176 (Location loc, string name)
3198 Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
3199 "with an instance reference, qualify it with a type name instead", name);
3202 // TODO: possible optimalization
3203 // Cache resolved constant result in FieldBuilder <-> expression map
3204 public virtual MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3205 SimpleName original)
3209 // original == null || original.Resolve (...) ==> left
3212 if (left is TypeExpr) {
3213 left = left.ResolveAsTypeTerminal (ec, true);
3218 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3226 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3229 return ResolveExtensionMemberAccess (left);
3232 InstanceExpression = left;
3236 protected virtual MemberExpr ResolveExtensionMemberAccess (Expression left)
3238 error176 (loc, GetSignatureForError ());
3242 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3247 if (InstanceExpression == EmptyExpression.Null) {
3248 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3252 if (InstanceExpression.Type.IsValueType) {
3253 if (InstanceExpression is IMemoryLocation) {
3254 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
3256 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
3257 InstanceExpression.Emit (ec);
3259 t.AddressOf (ec, AddressOp.Store);
3262 InstanceExpression.Emit (ec);
3264 if (prepare_for_load)
3265 ec.ig.Emit (OpCodes.Dup);
3268 public virtual void SetTypeArguments (TypeArguments ta)
3270 // TODO: need to get correct member type
3271 Report.Error (307, loc, "The property `{0}' cannot be used with type arguments",
3272 GetSignatureForError ());
3277 /// Represents group of extension methods
3279 public class ExtensionMethodGroupExpr : MethodGroupExpr
3281 readonly NamespaceEntry namespace_entry;
3282 public Expression ExtensionExpression;
3283 Argument extension_argument;
3285 public ExtensionMethodGroupExpr (ArrayList list, NamespaceEntry n, Type extensionType, Location l)
3286 : base (list, extensionType, l)
3288 this.namespace_entry = n;
3291 public override bool IsStatic {
3292 get { return true; }
3295 public bool IsTopLevel {
3296 get { return namespace_entry == null; }
3299 public override void EmitArguments (EmitContext ec, ArrayList arguments)
3301 if (arguments == null)
3302 arguments = new ArrayList (1);
3303 arguments.Insert (0, extension_argument);
3304 base.EmitArguments (ec, arguments);
3307 public override void EmitCall (EmitContext ec, ArrayList arguments)
3309 if (arguments == null)
3310 arguments = new ArrayList (1);
3311 arguments.Insert (0, extension_argument);
3312 base.EmitCall (ec, arguments);
3315 public override MethodGroupExpr OverloadResolve (EmitContext ec, ref ArrayList arguments, bool may_fail, Location loc)
3317 if (arguments == null)
3318 arguments = new ArrayList (1);
3320 arguments.Insert (0, new Argument (ExtensionExpression));
3321 MethodGroupExpr mg = ResolveOverloadExtensions (ec, arguments, namespace_entry, loc);
3323 // Store resolved argument and restore original arguments
3325 ((ExtensionMethodGroupExpr)mg).extension_argument = (Argument)arguments [0];
3326 arguments.RemoveAt (0);
3331 MethodGroupExpr ResolveOverloadExtensions (EmitContext ec, ArrayList arguments, NamespaceEntry ns, Location loc)
3333 // Use normal resolve rules
3334 MethodGroupExpr mg = base.OverloadResolve (ec, ref arguments, ns != null, loc);
3342 ExtensionMethodGroupExpr e = ns.LookupExtensionMethod (type, null, Name, loc);
3344 return base.OverloadResolve (ec, ref arguments, false, loc);
3346 e.ExtensionExpression = ExtensionExpression;
3347 return e.ResolveOverloadExtensions (ec, arguments, e.namespace_entry, loc);
3352 /// MethodGroupExpr represents a group of method candidates which
3353 /// can be resolved to the best method overload
3355 public class MethodGroupExpr : MemberExpr
3357 public interface IErrorHandler
3359 bool NoExactMatch (EmitContext ec, MethodBase method);
3362 public IErrorHandler CustomErrorHandler;
3363 public MethodBase [] Methods;
3364 MethodBase best_candidate;
3365 // TODO: make private
3366 public TypeArguments type_arguments;
3367 bool identical_type_name;
3370 public MethodGroupExpr (MemberInfo [] mi, Type type, Location l)
3373 Methods = new MethodBase [mi.Length];
3374 mi.CopyTo (Methods, 0);
3377 public MethodGroupExpr (ArrayList list, Type type, Location l)
3381 Methods = (MethodBase[])list.ToArray (typeof (MethodBase));
3383 foreach (MemberInfo m in list){
3384 if (!(m is MethodBase)){
3385 Console.WriteLine ("Name " + m.Name);
3386 Console.WriteLine ("Found a: " + m.GetType ().FullName);
3395 protected MethodGroupExpr (Type type, Location loc)
3398 eclass = ExprClass.MethodGroup;
3402 public override Type DeclaringType {
3405 // We assume that the top-level type is in the end
3407 return Methods [Methods.Length - 1].DeclaringType;
3408 //return Methods [0].DeclaringType;
3412 public Type DelegateType {
3414 delegate_type = value;
3418 public bool IdenticalTypeName {
3420 return identical_type_name;
3424 identical_type_name = value;
3428 public override string GetSignatureForError ()
3430 if (best_candidate != null)
3431 return TypeManager.CSharpSignature (best_candidate);
3433 return TypeManager.CSharpSignature (Methods [0]);
3436 public override string Name {
3438 return Methods [0].Name;
3442 public override bool IsInstance {
3444 if (best_candidate != null)
3445 return !best_candidate.IsStatic;
3447 foreach (MethodBase mb in Methods)
3455 public override bool IsStatic {
3457 if (best_candidate != null)
3458 return best_candidate.IsStatic;
3460 foreach (MethodBase mb in Methods)
3468 public static explicit operator ConstructorInfo (MethodGroupExpr mg)
3470 return (ConstructorInfo)mg.best_candidate;
3473 public static explicit operator MethodInfo (MethodGroupExpr mg)
3475 return (MethodInfo)mg.best_candidate;
3479 // 7.4.3.3 Better conversion from expression
3480 // Returns : 1 if a->p is better,
3481 // 2 if a->q is better,
3482 // 0 if neither is better
3484 static int BetterExpressionConversion (EmitContext ec, Argument a, Type p, Type q)
3486 Type argument_type = TypeManager.TypeToCoreType (a.Type);
3487 if (argument_type == TypeManager.anonymous_method_type && RootContext.Version > LanguageVersion.ISO_2) {
3489 // Uwrap delegate from Expression<T>
3491 if (TypeManager.DropGenericTypeArguments (p) == TypeManager.expression_type) {
3492 p = TypeManager.GetTypeArguments (p) [0];
3493 q = TypeManager.GetTypeArguments (q) [0];
3495 p = Delegate.GetInvokeMethod (null, p).ReturnType;
3496 q = Delegate.GetInvokeMethod (null, q).ReturnType;
3498 if (argument_type == p)
3501 if (argument_type == q)
3505 return BetterTypeConversion (ec, p, q);
3509 // 7.4.3.4 Better conversion from type
3511 public static int BetterTypeConversion (EmitContext ec, Type p, Type q)
3513 if (p == null || q == null)
3514 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3516 if (p == TypeManager.int32_type) {
3517 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3519 } else if (p == TypeManager.int64_type) {
3520 if (q == TypeManager.uint64_type)
3522 } else if (p == TypeManager.sbyte_type) {
3523 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3524 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3526 } else if (p == TypeManager.short_type) {
3527 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3528 q == TypeManager.uint64_type)
3532 if (q == TypeManager.int32_type) {
3533 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3535 } if (q == TypeManager.int64_type) {
3536 if (p == TypeManager.uint64_type)
3538 } else if (q == TypeManager.sbyte_type) {
3539 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3540 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3542 } if (q == TypeManager.short_type) {
3543 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3544 p == TypeManager.uint64_type)
3548 // TODO: this is expensive
3549 Expression p_tmp = new EmptyExpression (p);
3550 Expression q_tmp = new EmptyExpression (q);
3552 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3553 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3555 if (p_to_q && !q_to_p)
3558 if (q_to_p && !p_to_q)
3565 /// Determines "Better function" between candidate
3566 /// and the current best match
3569 /// Returns a boolean indicating :
3570 /// false if candidate ain't better
3571 /// true if candidate is better than the current best match
3573 static bool BetterFunction (EmitContext ec, ArrayList args, int argument_count,
3574 MethodBase candidate, bool candidate_params,
3575 MethodBase best, bool best_params)
3577 ParameterData candidate_pd = TypeManager.GetParameterData (candidate);
3578 ParameterData best_pd = TypeManager.GetParameterData (best);
3580 bool better_at_least_one = false;
3582 for (int j = 0, c_idx = 0, b_idx = 0; j < argument_count; ++j, ++c_idx, ++b_idx)
3584 Argument a = (Argument) args [j];
3586 Type ct = TypeManager.TypeToCoreType (candidate_pd.ParameterType (c_idx));
3587 Type bt = TypeManager.TypeToCoreType (best_pd.ParameterType (b_idx));
3589 if (candidate_params && candidate_pd.ParameterModifier (c_idx) == Parameter.Modifier.PARAMS)
3591 ct = TypeManager.GetElementType (ct);
3595 if (best_params && best_pd.ParameterModifier (b_idx) == Parameter.Modifier.PARAMS)
3597 bt = TypeManager.GetElementType (bt);
3605 int result = BetterExpressionConversion (ec, a, ct, bt);
3607 // for each argument, the conversion to 'ct' should be no worse than
3608 // the conversion to 'bt'.
3612 // for at least one argument, the conversion to 'ct' should be better than
3613 // the conversion to 'bt'.
3615 better_at_least_one = true;
3618 if (better_at_least_one)
3622 // This handles the case
3624 // Add (float f1, float f2, float f3);
3625 // Add (params decimal [] foo);
3627 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3628 // first candidate would've chosen as better.
3634 // The two methods have equal parameter types. Now apply tie-breaking rules
3636 if (TypeManager.IsGenericMethod (best) && !TypeManager.IsGenericMethod (candidate))
3638 if (!TypeManager.IsGenericMethod (best) && TypeManager.IsGenericMethod (candidate))
3642 // This handles the following cases:
3644 // Trim () is better than Trim (params char[] chars)
3645 // Concat (string s1, string s2, string s3) is better than
3646 // Concat (string s1, params string [] srest)
3647 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3649 if (!candidate_params && best_params)
3651 if (candidate_params && !best_params)
3654 int candidate_param_count = candidate_pd.Count;
3655 int best_param_count = best_pd.Count;
3657 if (candidate_param_count != best_param_count)
3658 // can only happen if (candidate_params && best_params)
3659 return candidate_param_count > best_param_count;
3662 // now, both methods have the same number of parameters, and the parameters have the same types
3663 // Pick the "more specific" signature
3666 MethodBase orig_candidate = TypeManager.DropGenericMethodArguments (candidate);
3667 MethodBase orig_best = TypeManager.DropGenericMethodArguments (best);
3669 ParameterData orig_candidate_pd = TypeManager.GetParameterData (orig_candidate);
3670 ParameterData orig_best_pd = TypeManager.GetParameterData (orig_best);
3672 bool specific_at_least_once = false;
3673 for (int j = 0; j < candidate_param_count; ++j)
3675 Type ct = TypeManager.TypeToCoreType (orig_candidate_pd.ParameterType (j));
3676 Type bt = TypeManager.TypeToCoreType (orig_best_pd.ParameterType (j));
3679 Type specific = MoreSpecific (ct, bt);
3683 specific_at_least_once = true;
3686 if (specific_at_least_once)
3689 // FIXME: handle lifted operators
3695 protected override MemberExpr ResolveExtensionMemberAccess (Expression left)
3698 return base.ResolveExtensionMemberAccess (left);
3701 // When left side is an expression and at least one candidate method is
3702 // static, it can be extension method
3704 InstanceExpression = left;
3708 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3709 SimpleName original)
3711 if (!(left is TypeExpr) &&
3712 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3713 IdenticalTypeName = true;
3715 return base.ResolveMemberAccess (ec, left, loc, original);
3718 public override Expression CreateExpressionTree (EmitContext ec)
3720 Type t = best_candidate.IsConstructor ?
3721 typeof (ConstructorInfo) : typeof (MethodInfo);
3723 return new Cast (new TypeExpression (t, loc), new TypeOfMethod (best_candidate, loc));
3726 override public Expression DoResolve (EmitContext ec)
3728 if (InstanceExpression != null) {
3729 InstanceExpression = InstanceExpression.DoResolve (ec);
3730 if (InstanceExpression == null)
3737 public void ReportUsageError ()
3739 Report.Error (654, loc, "Method `" + DeclaringType + "." +
3740 Name + "()' is referenced without parentheses");
3743 override public void Emit (EmitContext ec)
3745 ReportUsageError ();
3748 public virtual void EmitArguments (EmitContext ec, ArrayList arguments)
3750 Invocation.EmitArguments (ec, arguments, false, null);
3753 public virtual void EmitCall (EmitContext ec, ArrayList arguments)
3755 Invocation.EmitCall (ec, IsBase, InstanceExpression, best_candidate, arguments, loc);
3758 protected virtual void Error_InvalidArguments (EmitContext ec, Location loc, int idx, MethodBase method,
3759 Argument a, ParameterData expected_par, Type paramType)
3761 if (a is CollectionElementInitializer.ElementInitializerArgument) {
3762 Report.SymbolRelatedToPreviousError (method);
3763 if ((expected_par.ParameterModifier (idx) & Parameter.Modifier.ISBYREF) != 0) {
3764 Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
3765 TypeManager.CSharpSignature (method));
3768 Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
3769 TypeManager.CSharpSignature (method));
3770 } else if (delegate_type == null) {
3771 Report.SymbolRelatedToPreviousError (method);
3772 Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
3773 TypeManager.CSharpSignature (method));
3775 Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
3776 TypeManager.CSharpName (delegate_type));
3778 Parameter.Modifier mod = expected_par.ParameterModifier (idx);
3780 string index = (idx + 1).ToString ();
3781 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
3782 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
3783 if ((mod & Parameter.Modifier.ISBYREF) == 0)
3784 Report.Error (1615, loc, "Argument `{0}' should not be passed with the `{1}' keyword",
3785 index, Parameter.GetModifierSignature (a.Modifier));
3787 Report.Error (1620, loc, "Argument `{0}' must be passed with the `{1}' keyword",
3788 index, Parameter.GetModifierSignature (mod));
3790 string p1 = a.GetSignatureForError ();
3791 string p2 = TypeManager.CSharpName (paramType);
3794 Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
3795 Report.SymbolRelatedToPreviousError (a.Expr.Type);
3796 Report.SymbolRelatedToPreviousError (paramType);
3798 Report.Error (1503, loc, "Argument {0}: Cannot convert type `{1}' to `{2}'", index, p1, p2);
3802 public override void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl)
3804 Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3805 Name, TypeManager.CSharpName (target));
3808 protected virtual int GetApplicableParametersCount (MethodBase method, ParameterData parameters)
3810 return parameters.Count;
3813 public static bool IsAncestralType (Type first_type, Type second_type)
3815 return first_type != second_type &&
3816 (TypeManager.IsSubclassOf (second_type, first_type) ||
3817 TypeManager.ImplementsInterface (second_type, first_type));
3821 /// Determines if the candidate method is applicable (section 14.4.2.1)
3822 /// to the given set of arguments
3823 /// A return value rates candidate method compatibility,
3824 /// 0 = the best, int.MaxValue = the worst
3826 public int IsApplicable (EmitContext ec,
3827 ArrayList arguments, int arg_count, ref MethodBase method, ref bool params_expanded_form)
3829 MethodBase candidate = method;
3831 ParameterData pd = TypeManager.GetParameterData (candidate);
3832 int param_count = GetApplicableParametersCount (candidate, pd);
3834 if (arg_count != param_count) {
3836 return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
3837 if (arg_count < param_count - 1)
3838 return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
3843 // 1. Handle generic method using type arguments when specified or type inference
3845 if (TypeManager.IsGenericMethod (candidate)) {
3846 if (type_arguments != null) {
3847 Type [] g_args = candidate.GetGenericArguments ();
3848 if (g_args.Length != type_arguments.Count)
3849 return int.MaxValue - 20000 + Math.Abs (type_arguments.Count - g_args.Length);
3851 // TODO: Don't create new method, create Parameters only
3852 method = ((MethodInfo) candidate).MakeGenericMethod (type_arguments.Arguments);
3854 pd = TypeManager.GetParameterData (candidate);
3856 int score = TypeManager.InferTypeArguments (ec, arguments, ref candidate);
3858 return score - 20000;
3860 if (TypeManager.IsGenericMethodDefinition (candidate))
3861 throw new InternalErrorException ("A generic method `{0}' definition took part in overload resolution",
3862 TypeManager.CSharpSignature (candidate));
3864 pd = TypeManager.GetParameterData (candidate);
3867 if (type_arguments != null)
3868 return int.MaxValue - 15000;
3873 // 2. Each argument has to be implicitly convertible to method parameter
3876 Parameter.Modifier p_mod = 0;
3878 for (int i = 0; i < arg_count; i++) {
3879 Argument a = (Argument) arguments [i];
3880 Parameter.Modifier a_mod = a.Modifier &
3881 ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3883 if (p_mod != Parameter.Modifier.PARAMS) {
3884 p_mod = pd.ParameterModifier (i) & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3886 if (p_mod == Parameter.Modifier.ARGLIST) {
3887 if (a.Type == TypeManager.runtime_argument_handle_type)
3893 pt = pd.ParameterType (i);
3895 params_expanded_form = true;
3899 if (!params_expanded_form)
3900 score = IsArgumentCompatible (ec, a_mod, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
3902 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0) {
3903 // It can be applicable in expanded form
3904 score = IsArgumentCompatible (ec, a_mod, a, 0, pt.GetElementType ());
3906 params_expanded_form = true;
3910 if (params_expanded_form)
3912 return (arg_count - i) * 2 + score;
3916 if (arg_count != param_count)
3917 params_expanded_form = true;
3922 int IsArgumentCompatible (EmitContext ec, Parameter.Modifier arg_mod, Argument argument, Parameter.Modifier param_mod, Type parameter)
3925 // Types have to be identical when ref or out modifer is used
3927 if (arg_mod != 0 || param_mod != 0) {
3928 if (TypeManager.HasElementType (parameter))
3929 parameter = parameter.GetElementType ();
3931 Type a_type = argument.Type;
3932 if (TypeManager.HasElementType (a_type))
3933 a_type = a_type.GetElementType ();
3935 if (a_type != parameter)
3941 // FIXME: Kill this abomination (EmitContext.TempEc)
3942 EmitContext prevec = EmitContext.TempEc;
3943 EmitContext.TempEc = ec;
3945 if (delegate_type != null ?
3946 !Delegate.IsTypeCovariant (argument.Expr, parameter) :
3947 !Convert.ImplicitConversionExists (ec, argument.Expr, parameter))
3950 if (arg_mod != param_mod)
3954 EmitContext.TempEc = prevec;
3960 public static bool IsOverride (MethodBase cand_method, MethodBase base_method)
3962 if (!IsAncestralType (base_method.DeclaringType, cand_method.DeclaringType))
3965 ParameterData cand_pd = TypeManager.GetParameterData (cand_method);
3966 ParameterData base_pd = TypeManager.GetParameterData (base_method);
3968 if (cand_pd.Count != base_pd.Count)
3971 for (int j = 0; j < cand_pd.Count; ++j)
3973 Parameter.Modifier cm = cand_pd.ParameterModifier (j);
3974 Parameter.Modifier bm = base_pd.ParameterModifier (j);
3975 Type ct = TypeManager.TypeToCoreType (cand_pd.ParameterType (j));
3976 Type bt = TypeManager.TypeToCoreType (base_pd.ParameterType (j));
3978 if (cm != bm || ct != bt)
3985 public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2, Location loc)
3987 MemberInfo [] miset;
3988 MethodGroupExpr union;
3993 return (MethodGroupExpr) mg2;
3996 return (MethodGroupExpr) mg1;
3999 MethodGroupExpr left_set = null, right_set = null;
4000 int length1 = 0, length2 = 0;
4002 left_set = (MethodGroupExpr) mg1;
4003 length1 = left_set.Methods.Length;
4005 right_set = (MethodGroupExpr) mg2;
4006 length2 = right_set.Methods.Length;
4008 ArrayList common = new ArrayList ();
4010 foreach (MethodBase r in right_set.Methods){
4011 if (TypeManager.ArrayContainsMethod (left_set.Methods, r))
4015 miset = new MemberInfo [length1 + length2 - common.Count];
4016 left_set.Methods.CopyTo (miset, 0);
4020 foreach (MethodBase r in right_set.Methods) {
4021 if (!common.Contains (r))
4025 union = new MethodGroupExpr (miset, mg1.Type, loc);
4030 static Type MoreSpecific (Type p, Type q)
4032 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4034 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4037 if (TypeManager.HasElementType (p))
4039 Type pe = TypeManager.GetElementType (p);
4040 Type qe = TypeManager.GetElementType (q);
4041 Type specific = MoreSpecific (pe, qe);
4047 else if (TypeManager.IsGenericType (p))
4049 Type[] pargs = TypeManager.GetTypeArguments (p);
4050 Type[] qargs = TypeManager.GetTypeArguments (q);
4052 bool p_specific_at_least_once = false;
4053 bool q_specific_at_least_once = false;
4055 for (int i = 0; i < pargs.Length; i++)
4057 Type specific = MoreSpecific (pargs [i], qargs [i]);
4058 if (specific == pargs [i])
4059 p_specific_at_least_once = true;
4060 if (specific == qargs [i])
4061 q_specific_at_least_once = true;
4064 if (p_specific_at_least_once && !q_specific_at_least_once)
4066 if (!p_specific_at_least_once && q_specific_at_least_once)
4074 /// Find the Applicable Function Members (7.4.2.1)
4076 /// me: Method Group expression with the members to select.
4077 /// it might contain constructors or methods (or anything
4078 /// that maps to a method).
4080 /// Arguments: ArrayList containing resolved Argument objects.
4082 /// loc: The location if we want an error to be reported, or a Null
4083 /// location for "probing" purposes.
4085 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4086 /// that is the best match of me on Arguments.
4089 public virtual MethodGroupExpr OverloadResolve (EmitContext ec, ref ArrayList Arguments,
4090 bool may_fail, Location loc)
4092 bool method_params = false;
4093 Type applicable_type = null;
4095 ArrayList candidates = new ArrayList (2);
4096 ArrayList candidate_overrides = null;
4099 // Used to keep a map between the candidate
4100 // and whether it is being considered in its
4101 // normal or expanded form
4103 // false is normal form, true is expanded form
4105 Hashtable candidate_to_form = null;
4107 if (Arguments != null)
4108 arg_count = Arguments.Count;
4110 if (RootContext.Version == LanguageVersion.ISO_1 && Name == "Invoke" && TypeManager.IsDelegateType (DeclaringType)) {
4112 Report.Error (1533, loc, "Invoke cannot be called directly on a delegate");
4116 int nmethods = Methods.Length;
4120 // Methods marked 'override' don't take part in 'applicable_type'
4121 // computation, nor in the actual overload resolution.
4122 // However, they still need to be emitted instead of a base virtual method.
4123 // So, we salt them away into the 'candidate_overrides' array.
4125 // In case of reflected methods, we replace each overriding method with
4126 // its corresponding base virtual method. This is to improve compatibility
4127 // with non-C# libraries which change the visibility of overrides (#75636)
4130 for (int i = 0; i < Methods.Length; ++i) {
4131 MethodBase m = Methods [i];
4132 if (TypeManager.IsOverride (m)) {
4133 if (candidate_overrides == null)
4134 candidate_overrides = new ArrayList ();
4135 candidate_overrides.Add (m);
4136 m = TypeManager.TryGetBaseDefinition (m);
4145 // Enable message recording, it's used mainly by lambda expressions
4147 Report.IMessageRecorder msg_recorder = new Report.MessageRecorder ();
4148 Report.IMessageRecorder prev_recorder = Report.SetMessageRecorder (msg_recorder);
4151 // First we construct the set of applicable methods
4153 bool is_sorted = true;
4154 int best_candidate_rate = int.MaxValue;
4155 for (int i = 0; i < nmethods; i++) {
4156 Type decl_type = Methods [i].DeclaringType;
4159 // If we have already found an applicable method
4160 // we eliminate all base types (Section 14.5.5.1)
4162 if (applicable_type != null && IsAncestralType (decl_type, applicable_type))
4166 // Check if candidate is applicable (section 14.4.2.1)
4168 bool params_expanded_form = false;
4169 int candidate_rate = IsApplicable (ec, Arguments, arg_count, ref Methods [i], ref params_expanded_form);
4171 if (candidate_rate < best_candidate_rate) {
4172 best_candidate_rate = candidate_rate;
4173 best_candidate = Methods [i];
4176 if (params_expanded_form) {
4177 if (candidate_to_form == null)
4178 candidate_to_form = new PtrHashtable ();
4179 MethodBase candidate = Methods [i];
4180 candidate_to_form [candidate] = candidate;
4183 if (candidate_rate != 0) {
4184 if (msg_recorder != null)
4185 msg_recorder.EndSession ();
4189 msg_recorder = null;
4190 candidates.Add (Methods [i]);
4192 if (applicable_type == null)
4193 applicable_type = decl_type;
4194 else if (applicable_type != decl_type) {
4196 if (IsAncestralType (applicable_type, decl_type))
4197 applicable_type = decl_type;
4201 Report.SetMessageRecorder (prev_recorder);
4202 if (msg_recorder != null && msg_recorder.PrintMessages ())
4205 int candidate_top = candidates.Count;
4207 if (applicable_type == null) {
4209 // When we found a top level method which does not match and it's
4210 // not an extension method. We start extension methods lookup from here
4212 if (InstanceExpression != null) {
4213 ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (type, Name, loc);
4214 if (ex_method_lookup != null) {
4215 ex_method_lookup.ExtensionExpression = InstanceExpression;
4216 ex_method_lookup.SetTypeArguments (type_arguments);
4217 return ex_method_lookup.OverloadResolve (ec, ref Arguments, may_fail, loc);
4225 // Okay so we have failed to find exact match so we
4226 // return error info about the closest match
4228 if (best_candidate != null) {
4229 if (CustomErrorHandler != null) {
4230 if (CustomErrorHandler.NoExactMatch (ec, best_candidate))
4234 ParameterData pd = TypeManager.GetParameterData (best_candidate);
4235 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4236 if (arg_count == pd.Count || pd.HasParams) {
4237 if (TypeManager.IsGenericMethodDefinition (best_candidate)) {
4238 if (type_arguments == null) {
4239 Report.Error (411, loc,
4240 "The type arguments for method `{0}' cannot be inferred from " +
4241 "the usage. Try specifying the type arguments explicitly",
4242 TypeManager.CSharpSignature (best_candidate));
4246 Type [] g_args = TypeManager.GetGenericArguments (best_candidate);
4247 if (type_arguments.Count != g_args.Length) {
4248 Report.SymbolRelatedToPreviousError (best_candidate);
4249 Report.Error (305, loc, "Using the generic method `{0}' requires `{1}' type argument(s)",
4250 TypeManager.CSharpSignature (best_candidate),
4251 g_args.Length.ToString ());
4255 if (type_arguments != null && !TypeManager.IsGenericMethod (best_candidate)) {
4256 Namespace.Error_TypeArgumentsCannotBeUsed (best_candidate, loc);
4261 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate, cand_params, may_fail, loc))
4266 if (almost_matched_members.Count != 0) {
4267 Error_MemberLookupFailed (ec.ContainerType, type, type, ".ctor",
4268 null, MemberTypes.Constructor, AllBindingFlags);
4273 // We failed to find any method with correct argument count
4275 if (Name == ConstructorInfo.ConstructorName) {
4276 Report.SymbolRelatedToPreviousError (type);
4277 Report.Error (1729, loc,
4278 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4279 TypeManager.CSharpName (type), arg_count);
4281 Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4282 Name, arg_count.ToString ());
4290 // At this point, applicable_type is _one_ of the most derived types
4291 // in the set of types containing the methods in this MethodGroup.
4292 // Filter the candidates so that they only contain methods from the
4293 // most derived types.
4296 int finalized = 0; // Number of finalized candidates
4299 // Invariant: applicable_type is a most derived type
4301 // We'll try to complete Section 14.5.5.1 for 'applicable_type' by
4302 // eliminating all it's base types. At the same time, we'll also move
4303 // every unrelated type to the end of the array, and pick the next
4304 // 'applicable_type'.
4306 Type next_applicable_type = null;
4307 int j = finalized; // where to put the next finalized candidate
4308 int k = finalized; // where to put the next undiscarded candidate
4309 for (int i = finalized; i < candidate_top; ++i) {
4310 MethodBase candidate = (MethodBase) candidates [i];
4311 Type decl_type = candidate.DeclaringType;
4313 if (decl_type == applicable_type) {
4314 candidates [k++] = candidates [j];
4315 candidates [j++] = candidates [i];
4319 if (IsAncestralType (decl_type, applicable_type))
4322 if (next_applicable_type != null &&
4323 IsAncestralType (decl_type, next_applicable_type))
4326 candidates [k++] = candidates [i];
4328 if (next_applicable_type == null ||
4329 IsAncestralType (next_applicable_type, decl_type))
4330 next_applicable_type = decl_type;
4333 applicable_type = next_applicable_type;
4336 } while (applicable_type != null);
4340 // Now we actually find the best method
4343 best_candidate = (MethodBase) candidates [0];
4344 if (delegate_type == null)
4345 method_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4347 for (int ix = 1; ix < candidate_top; ix++) {
4348 MethodBase candidate = (MethodBase) candidates [ix];
4350 if (candidate == best_candidate)
4353 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4355 if (BetterFunction (ec, Arguments, arg_count,
4356 candidate, cand_params,
4357 best_candidate, method_params)) {
4358 best_candidate = candidate;
4359 method_params = cand_params;
4363 // Now check that there are no ambiguities i.e the selected method
4364 // should be better than all the others
4366 MethodBase ambiguous = null;
4367 for (int ix = 1; ix < candidate_top; ix++) {
4368 MethodBase candidate = (MethodBase) candidates [ix];
4370 if (candidate == best_candidate)
4373 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4374 if (!BetterFunction (ec, Arguments, arg_count,
4375 best_candidate, method_params,
4376 candidate, cand_params))
4379 Report.SymbolRelatedToPreviousError (candidate);
4380 ambiguous = candidate;
4384 if (ambiguous != null) {
4385 Report.SymbolRelatedToPreviousError (best_candidate);
4386 Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4387 TypeManager.CSharpSignature (ambiguous), TypeManager.CSharpSignature (best_candidate));
4392 // If the method is a virtual function, pick an override closer to the LHS type.
4394 if (!IsBase && best_candidate.IsVirtual) {
4395 if (TypeManager.IsOverride (best_candidate))
4396 throw new InternalErrorException (
4397 "Should not happen. An 'override' method took part in overload resolution: " + best_candidate);
4399 if (candidate_overrides != null) {
4400 Type[] gen_args = null;
4401 bool gen_override = false;
4402 if (TypeManager.IsGenericMethod (best_candidate))
4403 gen_args = TypeManager.GetGenericArguments (best_candidate);
4405 foreach (MethodBase candidate in candidate_overrides) {
4406 if (TypeManager.IsGenericMethod (candidate)) {
4407 if (gen_args == null)
4410 if (gen_args.Length != TypeManager.GetGenericArguments (candidate).Length)
4413 if (gen_args != null)
4417 if (IsOverride (candidate, best_candidate)) {
4418 gen_override = true;
4419 best_candidate = candidate;
4423 if (gen_override && gen_args != null) {
4425 best_candidate = ((MethodInfo) best_candidate).MakeGenericMethod (gen_args);
4432 // And now check if the arguments are all
4433 // compatible, perform conversions if
4434 // necessary etc. and return if everything is
4437 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate,
4438 method_params, may_fail, loc))
4441 if (best_candidate == null)
4444 MethodBase the_method = TypeManager.DropGenericMethodArguments (best_candidate);
4446 if (the_method.IsGenericMethodDefinition &&
4447 !ConstraintChecker.CheckConstraints (ec, the_method, best_candidate, loc))
4451 IMethodData data = TypeManager.GetMethod (the_method);
4453 data.SetMemberIsUsed ();
4458 public override void SetTypeArguments (TypeArguments ta)
4460 type_arguments = ta;
4463 public bool VerifyArgumentsCompat (EmitContext ec, ref ArrayList arguments,
4464 int arg_count, MethodBase method,
4465 bool chose_params_expanded,
4466 bool may_fail, Location loc)
4468 ParameterData pd = TypeManager.GetParameterData (method);
4470 int errors = Report.Errors;
4471 Parameter.Modifier p_mod = 0;
4473 int a_idx = 0, a_pos = 0;
4475 ArrayList params_initializers = null;
4477 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4478 a = (Argument) arguments [a_idx];
4479 if (p_mod != Parameter.Modifier.PARAMS) {
4480 p_mod = pd.ParameterModifier (a_idx);
4481 pt = pd.ParameterType (a_idx);
4483 if (p_mod == Parameter.Modifier.ARGLIST) {
4484 if (a.Type != TypeManager.runtime_argument_handle_type)
4489 if (pt.IsPointer && !ec.InUnsafe) {
4496 if (p_mod == Parameter.Modifier.PARAMS) {
4497 if (chose_params_expanded) {
4498 params_initializers = new ArrayList (arg_count - a_idx);
4499 pt = TypeManager.GetElementType (pt);
4501 } else if (p_mod != 0) {
4502 pt = TypeManager.GetElementType (pt);
4507 // Types have to be identical when ref or out modifer is used
4509 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4510 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4513 if (!TypeManager.IsEqual (a.Expr.Type, pt))
4520 if (TypeManager.IsEqual (a.Type, pt)) {
4523 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4529 // Convert params arguments to an array initializer
4531 if (params_initializers != null) {
4532 params_initializers.Add (conv);
4533 arguments.RemoveAt (a_idx--);
4538 // Update the argument with the implicit conversion
4543 // Fill not provided arguments required by params modifier
4545 if (params_initializers == null && pd.HasParams && arg_count < pd.Count && a_idx + 1 == pd.Count) {
4546 if (arguments == null)
4547 arguments = new ArrayList (1);
4549 pt = pd.Types [GetApplicableParametersCount (method, pd) - 1];
4550 pt = TypeManager.GetElementType (pt);
4551 params_initializers = new ArrayList (0);
4554 if (a_idx == arg_count) {
4556 // Append an array argument with all params arguments
4558 if (params_initializers != null) {
4559 arguments.Add (new Argument (
4560 new ArrayCreation (new TypeExpression (pt, loc), "[]",
4561 params_initializers, loc).Resolve (ec)));
4566 if (!may_fail && Report.Errors == errors) {
4567 if (CustomErrorHandler != null)
4568 CustomErrorHandler.NoExactMatch (ec, best_candidate);
4570 Error_InvalidArguments (ec, loc, a_pos, method, a, pd, pt);
4576 public class ConstantExpr : MemberExpr
4580 public ConstantExpr (FieldInfo constant, Location loc)
4582 this.constant = constant;
4586 public override string Name {
4587 get { throw new NotImplementedException (); }
4590 public override bool IsInstance {
4591 get { return !IsStatic; }
4594 public override bool IsStatic {
4595 get { return constant.IsStatic; }
4598 public override Type DeclaringType {
4599 get { return constant.DeclaringType; }
4602 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc, SimpleName original)
4604 constant = TypeManager.GetGenericFieldDefinition (constant);
4606 IConstant ic = TypeManager.GetConstant (constant);
4608 if (constant.IsLiteral) {
4609 ic = new ExternalConstant (constant);
4611 ic = ExternalConstant.CreateDecimal (constant);
4612 // HACK: decimal field was not resolved as constant
4614 return new FieldExpr (constant, loc).ResolveMemberAccess (ec, left, loc, original);
4616 TypeManager.RegisterConstant (constant, ic);
4619 return base.ResolveMemberAccess (ec, left, loc, original);
4622 public override Expression CreateExpressionTree (EmitContext ec)
4624 throw new NotSupportedException ();
4627 public override Expression DoResolve (EmitContext ec)
4629 IConstant ic = TypeManager.GetConstant (constant);
4630 if (ic.ResolveValue ()) {
4631 if (!ec.IsInObsoleteScope)
4632 ic.CheckObsoleteness (loc);
4635 return ic.CreateConstantReference (loc);
4638 public override void Emit (EmitContext ec)
4640 throw new NotSupportedException ();
4643 public override string GetSignatureForError ()
4645 return TypeManager.GetFullNameSignature (constant);
4650 /// Fully resolved expression that evaluates to a Field
4652 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariable {
4653 public readonly FieldInfo FieldInfo;
4654 VariableInfo variable_info;
4656 LocalTemporary temp;
4658 bool in_initializer;
4660 public FieldExpr (FieldInfo fi, Location l, bool in_initializer):
4663 this.in_initializer = in_initializer;
4666 public FieldExpr (FieldInfo fi, Location l)
4669 eclass = ExprClass.Variable;
4670 type = TypeManager.TypeToCoreType (fi.FieldType);
4674 public override string Name {
4676 return FieldInfo.Name;
4680 public override bool IsInstance {
4682 return !FieldInfo.IsStatic;
4686 public override bool IsStatic {
4688 return FieldInfo.IsStatic;
4692 public override Type DeclaringType {
4694 return FieldInfo.DeclaringType;
4698 public override string GetSignatureForError ()
4700 return TypeManager.GetFullNameSignature (FieldInfo);
4703 public VariableInfo VariableInfo {
4705 return variable_info;
4709 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
4710 SimpleName original)
4712 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
4713 Type t = fi.FieldType;
4715 if (t.IsPointer && !ec.InUnsafe) {
4719 return base.ResolveMemberAccess (ec, left, loc, original);
4722 public override Expression CreateExpressionTree (EmitContext ec)
4724 Expression instance;
4725 if (InstanceExpression == null) {
4726 instance = new NullLiteral (loc);
4728 instance = InstanceExpression.CreateExpressionTree (ec);
4731 ArrayList args = new ArrayList (2);
4732 args.Add (new Argument (instance));
4733 args.Add (new Argument (CreateTypeOfExpression ()));
4734 return CreateExpressionFactoryCall ("Field", args);
4737 public Expression CreateTypeOfExpression ()
4739 return new TypeOfField (FieldInfo, loc);
4742 override public Expression DoResolve (EmitContext ec)
4744 return DoResolve (ec, false, false);
4747 Expression DoResolve (EmitContext ec, bool lvalue_instance, bool out_access)
4749 if (!FieldInfo.IsStatic){
4750 if (InstanceExpression == null){
4752 // This can happen when referencing an instance field using
4753 // a fully qualified type expression: TypeName.InstanceField = xxx
4755 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4759 // Resolve the field's instance expression while flow analysis is turned
4760 // off: when accessing a field "a.b", we must check whether the field
4761 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4763 if (lvalue_instance) {
4764 using (ec.With (EmitContext.Flags.DoFlowAnalysis, false)) {
4765 Expression right_side =
4766 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4767 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side, loc);
4770 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
4771 InstanceExpression = InstanceExpression.Resolve (ec, rf);
4774 if (InstanceExpression == null)
4777 using (ec.Set (EmitContext.Flags.OmitStructFlowAnalysis)) {
4778 InstanceExpression.CheckMarshalByRefAccess (ec);
4782 if (!in_initializer && !ec.IsInFieldInitializer) {
4783 ObsoleteAttribute oa;
4784 FieldBase f = TypeManager.GetField (FieldInfo);
4786 if (!ec.IsInObsoleteScope)
4787 f.CheckObsoleteness (loc);
4789 // To be sure that type is external because we do not register generated fields
4790 } else if (!(FieldInfo.DeclaringType is TypeBuilder)) {
4791 oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
4793 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
4797 AnonymousContainer am = ec.CurrentAnonymousMethod;
4799 if (!FieldInfo.IsStatic){
4800 if (!am.IsIterator && (ec.TypeContainer is Struct)){
4801 Report.Error (1673, loc,
4802 "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",
4809 IFixedBuffer fb = AttributeTester.GetFixedBuffer (FieldInfo);
4811 if (!ec.InFixedInitializer && ec.ContainerType.IsValueType) {
4812 Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4815 if (InstanceExpression.eclass != ExprClass.Variable) {
4816 Report.SymbolRelatedToPreviousError (FieldInfo);
4817 Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4818 TypeManager.GetFullNameSignature (FieldInfo));
4821 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4824 // If the instance expression is a local variable or parameter.
4825 IVariable var = InstanceExpression as IVariable;
4826 if ((var == null) || (var.VariableInfo == null))
4829 VariableInfo vi = var.VariableInfo;
4830 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
4833 variable_info = vi.GetSubStruct (FieldInfo.Name);
4837 static readonly int [] codes = {
4838 191, // instance, write access
4839 192, // instance, out access
4840 198, // static, write access
4841 199, // static, out access
4842 1648, // member of value instance, write access
4843 1649, // member of value instance, out access
4844 1650, // member of value static, write access
4845 1651 // member of value static, out access
4848 static readonly string [] msgs = {
4849 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4850 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4851 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4852 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4853 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4854 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4855 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4856 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4859 // The return value is always null. Returning a value simplifies calling code.
4860 Expression Report_AssignToReadonly (Expression right_side)
4863 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4867 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4869 Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4874 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4876 IVariable var = InstanceExpression as IVariable;
4877 if ((var != null) && (var.VariableInfo != null))
4878 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
4880 bool lvalue_instance = !FieldInfo.IsStatic && FieldInfo.DeclaringType.IsValueType;
4881 bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
4883 Expression e = DoResolve (ec, lvalue_instance, out_access);
4888 FieldBase fb = TypeManager.GetField (FieldInfo);
4892 if (FieldInfo.IsInitOnly) {
4893 // InitOnly fields can only be assigned in constructors or initializers
4894 if (!ec.IsInFieldInitializer && !ec.IsConstructor)
4895 return Report_AssignToReadonly (right_side);
4897 if (ec.IsConstructor) {
4898 Type ctype = ec.TypeContainer.CurrentType;
4900 ctype = ec.ContainerType;
4902 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4903 if (!TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
4904 return Report_AssignToReadonly (right_side);
4905 // static InitOnly fields cannot be assigned-to in an instance constructor
4906 if (IsStatic && !ec.IsStatic)
4907 return Report_AssignToReadonly (right_side);
4908 // instance constructors can't modify InitOnly fields of other instances of the same type
4909 if (!IsStatic && !(InstanceExpression is This))
4910 return Report_AssignToReadonly (right_side);
4914 if (right_side == EmptyExpression.OutAccess &&
4915 !IsStatic && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type)) {
4916 Report.SymbolRelatedToPreviousError (DeclaringType);
4917 Report.Warning (197, 1, loc,
4918 "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",
4919 GetSignatureForError ());
4925 bool is_marshal_by_ref ()
4927 return !IsStatic && Type.IsValueType && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type);
4930 public override void CheckMarshalByRefAccess (EmitContext ec)
4932 if (is_marshal_by_ref () && !(InstanceExpression is This)) {
4933 Report.SymbolRelatedToPreviousError (DeclaringType);
4934 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",
4935 GetSignatureForError ());
4939 public bool VerifyFixed ()
4941 IVariable variable = InstanceExpression as IVariable;
4942 // A variable of the form V.I is fixed when V is a fixed variable of a struct type.
4943 // We defer the InstanceExpression check after the variable check to avoid a
4944 // separate null check on InstanceExpression.
4945 return variable != null && InstanceExpression.Type.IsValueType && variable.VerifyFixed ();
4948 public override int GetHashCode ()
4950 return FieldInfo.GetHashCode ();
4953 public override bool Equals (object obj)
4955 FieldExpr fe = obj as FieldExpr;
4959 if (FieldInfo != fe.FieldInfo)
4962 if (InstanceExpression == null || fe.InstanceExpression == null)
4965 return InstanceExpression.Equals (fe.InstanceExpression);
4968 public void Emit (EmitContext ec, bool leave_copy)
4970 ILGenerator ig = ec.ig;
4971 bool is_volatile = false;
4973 FieldBase f = TypeManager.GetField (FieldInfo);
4975 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4978 f.SetMemberIsUsed ();
4981 if (FieldInfo.IsStatic){
4983 ig.Emit (OpCodes.Volatile);
4985 ig.Emit (OpCodes.Ldsfld, FieldInfo);
4988 EmitInstance (ec, false);
4990 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
4992 ig.Emit (OpCodes.Ldflda, FieldInfo);
4993 ig.Emit (OpCodes.Ldflda, ff.Element);
4996 ig.Emit (OpCodes.Volatile);
4998 ig.Emit (OpCodes.Ldfld, FieldInfo);
5003 ec.ig.Emit (OpCodes.Dup);
5004 if (!FieldInfo.IsStatic) {
5005 temp = new LocalTemporary (this.Type);
5011 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5013 FieldAttributes fa = FieldInfo.Attributes;
5014 bool is_static = (fa & FieldAttributes.Static) != 0;
5015 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
5016 ILGenerator ig = ec.ig;
5018 if (is_readonly && !ec.IsConstructor){
5019 Report_AssignToReadonly (source);
5024 // String concatenation creates a new string instance
5026 prepared = prepare_for_load && !(source is StringConcat);
5027 EmitInstance (ec, prepared);
5031 ec.ig.Emit (OpCodes.Dup);
5032 if (!FieldInfo.IsStatic) {
5033 temp = new LocalTemporary (this.Type);
5038 FieldBase f = TypeManager.GetField (FieldInfo);
5040 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
5041 ig.Emit (OpCodes.Volatile);
5047 ig.Emit (OpCodes.Stsfld, FieldInfo);
5049 ig.Emit (OpCodes.Stfld, FieldInfo);
5057 public override void Emit (EmitContext ec)
5062 public override void EmitSideEffect (EmitContext ec)
5064 FieldBase f = TypeManager.GetField (FieldInfo);
5065 bool is_volatile = f != null && (f.ModFlags & Modifiers.VOLATILE) != 0;
5067 if (is_volatile || is_marshal_by_ref ())
5068 base.EmitSideEffect (ec);
5071 public void AddressOf (EmitContext ec, AddressOp mode)
5073 ILGenerator ig = ec.ig;
5075 FieldBase f = TypeManager.GetField (FieldInfo);
5077 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
5078 Report.Warning (420, 1, loc, "`{0}': A volatile field references will not be treated as volatile",
5079 f.GetSignatureForError ());
5082 if ((mode & AddressOp.Store) != 0)
5084 if ((mode & AddressOp.Load) != 0)
5085 f.SetMemberIsUsed ();
5089 // Handle initonly fields specially: make a copy and then
5090 // get the address of the copy.
5093 if (FieldInfo.IsInitOnly){
5095 if (ec.IsConstructor){
5096 if (FieldInfo.IsStatic){
5108 local = ig.DeclareLocal (type);
5109 ig.Emit (OpCodes.Stloc, local);
5110 ig.Emit (OpCodes.Ldloca, local);
5115 if (FieldInfo.IsStatic){
5116 ig.Emit (OpCodes.Ldsflda, FieldInfo);
5119 EmitInstance (ec, false);
5120 ig.Emit (OpCodes.Ldflda, FieldInfo);
5127 /// Expression that evaluates to a Property. The Assign class
5128 /// might set the `Value' expression if we are in an assignment.
5130 /// This is not an LValue because we need to re-write the expression, we
5131 /// can not take data from the stack and store it.
5133 public class PropertyExpr : MemberExpr, IAssignMethod {
5134 public readonly PropertyInfo PropertyInfo;
5135 MethodInfo getter, setter;
5140 LocalTemporary temp;
5143 public PropertyExpr (Type container_type, PropertyInfo pi, Location l)
5146 eclass = ExprClass.PropertyAccess;
5150 type = TypeManager.TypeToCoreType (pi.PropertyType);
5152 ResolveAccessors (container_type);
5155 public override string Name {
5157 return PropertyInfo.Name;
5161 public override bool IsInstance {
5167 public override bool IsStatic {
5173 public override Expression CreateExpressionTree (EmitContext ec)
5175 if (IsSingleDimensionalArrayLength ()) {
5176 ArrayList args = new ArrayList (1);
5177 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5178 return CreateExpressionFactoryCall ("ArrayLength", args);
5181 // TODO: it's waiting for PropertyExpr refactoring
5182 //ArrayList args = new ArrayList (2);
5183 //args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5184 //args.Add (getter expression);
5185 //return CreateExpressionFactoryCall ("Property", args);
5186 return base.CreateExpressionTree (ec);
5189 public Expression CreateSetterTypeOfExpression ()
5191 return new Cast (new TypeExpression (typeof (MethodInfo), loc), new TypeOfMethod (setter, loc));
5194 public override Type DeclaringType {
5196 return PropertyInfo.DeclaringType;
5200 public override string GetSignatureForError ()
5202 return TypeManager.GetFullNameSignature (PropertyInfo);
5205 void FindAccessors (Type invocation_type)
5207 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
5208 BindingFlags.Static | BindingFlags.Instance |
5209 BindingFlags.DeclaredOnly;
5211 Type current = PropertyInfo.DeclaringType;
5212 for (; current != null; current = current.BaseType) {
5213 MemberInfo[] group = TypeManager.MemberLookup (
5214 invocation_type, invocation_type, current,
5215 MemberTypes.Property, flags, PropertyInfo.Name, null);
5220 if (group.Length != 1)
5221 // Oooops, can this ever happen ?
5224 PropertyInfo pi = (PropertyInfo) group [0];
5227 getter = pi.GetGetMethod (true);
5230 setter = pi.GetSetMethod (true);
5232 MethodInfo accessor = getter != null ? getter : setter;
5234 if (!accessor.IsVirtual)
5240 // We also perform the permission checking here, as the PropertyInfo does not
5241 // hold the information for the accessibility of its setter/getter
5243 // TODO: Refactor to use some kind of cache together with GetPropertyFromAccessor
5244 void ResolveAccessors (Type container_type)
5246 FindAccessors (container_type);
5248 if (getter != null) {
5249 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
5250 IMethodData md = TypeManager.GetMethod (the_getter);
5252 md.SetMemberIsUsed ();
5254 is_static = getter.IsStatic;
5257 if (setter != null) {
5258 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
5259 IMethodData md = TypeManager.GetMethod (the_setter);
5261 md.SetMemberIsUsed ();
5263 is_static = setter.IsStatic;
5267 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
5270 InstanceExpression = null;
5274 if (InstanceExpression == null) {
5275 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5279 InstanceExpression = InstanceExpression.DoResolve (ec);
5280 if (lvalue_instance && InstanceExpression != null)
5281 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
5283 if (InstanceExpression == null)
5286 InstanceExpression.CheckMarshalByRefAccess (ec);
5288 if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) &&
5289 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
5290 !TypeManager.IsNestedChildOf (ec.ContainerType, InstanceExpression.Type) &&
5291 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.ContainerType)) {
5292 Report.SymbolRelatedToPreviousError (PropertyInfo);
5293 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
5300 void Error_PropertyNotFound (MethodInfo mi, bool getter)
5302 // TODO: correctly we should compare arguments but it will lead to bigger changes
5303 if (mi is MethodBuilder) {
5304 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
5308 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
5310 ParameterData iparams = TypeManager.GetParameterData (mi);
5311 sig.Append (getter ? "get_" : "set_");
5313 sig.Append (iparams.GetSignatureForError ());
5315 Report.SymbolRelatedToPreviousError (mi);
5316 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
5317 Name, sig.ToString ());
5320 public bool IsAccessibleFrom (Type invocation_type, bool lvalue)
5323 MethodInfo accessor = lvalue ? setter : getter;
5324 if (accessor == null && lvalue)
5326 return accessor != null && IsAccessorAccessible (invocation_type, accessor, out dummy);
5329 bool IsSingleDimensionalArrayLength ()
5331 if (DeclaringType != TypeManager.array_type || getter == null || Name != "Length")
5334 string t_name = InstanceExpression.Type.Name;
5335 int t_name_len = t_name.Length;
5336 return t_name_len > 2 && t_name [t_name_len - 2] == '[' && t_name [t_name_len - 3] != ']';
5339 override public Expression DoResolve (EmitContext ec)
5344 if (getter != null){
5345 if (TypeManager.GetParameterData (getter).Count != 0){
5346 Error_PropertyNotFound (getter, true);
5351 if (getter == null){
5353 // The following condition happens if the PropertyExpr was
5354 // created, but is invalid (ie, the property is inaccessible),
5355 // and we did not want to embed the knowledge about this in
5356 // the caller routine. This only avoids double error reporting.
5361 if (InstanceExpression != EmptyExpression.Null) {
5362 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5363 TypeManager.GetFullNameSignature (PropertyInfo));
5368 bool must_do_cs1540_check = false;
5369 if (getter != null &&
5370 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
5371 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
5372 if (pm != null && pm.HasCustomAccessModifier) {
5373 Report.SymbolRelatedToPreviousError (pm);
5374 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5375 TypeManager.CSharpSignature (getter));
5378 Report.SymbolRelatedToPreviousError (getter);
5379 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
5384 if (!InstanceResolve (ec, false, must_do_cs1540_check))
5388 // Only base will allow this invocation to happen.
5390 if (IsBase && getter.IsAbstract) {
5391 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5395 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
5405 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
5407 if (right_side == EmptyExpression.OutAccess) {
5408 if (ec.CurrentBlock.Toplevel.GetTransparentIdentifier (PropertyInfo.Name) != null) {
5409 Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5412 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as `ref' or `out' parameter",
5413 GetSignatureForError ());
5418 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5419 Error_CannotModifyIntermediateExpressionValue (ec);
5422 if (setter == null){
5424 // The following condition happens if the PropertyExpr was
5425 // created, but is invalid (ie, the property is inaccessible),
5426 // and we did not want to embed the knowledge about this in
5427 // the caller routine. This only avoids double error reporting.
5431 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
5432 GetSignatureForError ());
5436 if (TypeManager.GetParameterData (setter).Count != 1){
5437 Error_PropertyNotFound (setter, false);
5441 bool must_do_cs1540_check;
5442 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
5443 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
5444 if (pm != null && pm.HasCustomAccessModifier) {
5445 Report.SymbolRelatedToPreviousError (pm);
5446 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5447 TypeManager.CSharpSignature (setter));
5450 Report.SymbolRelatedToPreviousError (setter);
5451 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
5456 if (!InstanceResolve (ec, PropertyInfo.DeclaringType.IsValueType, must_do_cs1540_check))
5460 // Only base will allow this invocation to happen.
5462 if (IsBase && setter.IsAbstract){
5463 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5470 public override void Emit (EmitContext ec)
5475 public void Emit (EmitContext ec, bool leave_copy)
5478 // Special case: length of single dimension array property is turned into ldlen
5480 if (IsSingleDimensionalArrayLength ()) {
5482 EmitInstance (ec, false);
5483 ec.ig.Emit (OpCodes.Ldlen);
5484 ec.ig.Emit (OpCodes.Conv_I4);
5488 Invocation.EmitCall (ec, IsBase, InstanceExpression, getter, null, loc, prepared, false);
5491 ec.ig.Emit (OpCodes.Dup);
5493 temp = new LocalTemporary (this.Type);
5500 // Implements the IAssignMethod interface for assignments
5502 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5504 Expression my_source = source;
5506 if (prepare_for_load) {
5507 if (source is StringConcat)
5508 EmitInstance (ec, false);
5516 ec.ig.Emit (OpCodes.Dup);
5518 temp = new LocalTemporary (this.Type);
5522 } else if (leave_copy) {
5524 temp = new LocalTemporary (this.Type);
5529 ArrayList args = new ArrayList (1);
5530 args.Add (new Argument (my_source, Argument.AType.Expression));
5532 Invocation.EmitCall (ec, IsBase, InstanceExpression, setter, args, loc, false, prepared);
5542 /// Fully resolved expression that evaluates to an Event
5544 public class EventExpr : MemberExpr {
5545 public readonly EventInfo EventInfo;
5548 MethodInfo add_accessor, remove_accessor;
5550 public EventExpr (EventInfo ei, Location loc)
5554 eclass = ExprClass.EventAccess;
5556 add_accessor = TypeManager.GetAddMethod (ei);
5557 remove_accessor = TypeManager.GetRemoveMethod (ei);
5558 if (add_accessor.IsStatic || remove_accessor.IsStatic)
5561 if (EventInfo is MyEventBuilder){
5562 MyEventBuilder eb = (MyEventBuilder) EventInfo;
5563 type = eb.EventType;
5566 type = EventInfo.EventHandlerType;
5569 public override string Name {
5571 return EventInfo.Name;
5575 public override bool IsInstance {
5581 public override bool IsStatic {
5587 public override Type DeclaringType {
5589 return EventInfo.DeclaringType;
5593 void Error_AssignmentEventOnly ()
5595 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5596 GetSignatureForError ());
5599 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
5600 SimpleName original)
5603 // If the event is local to this class, we transform ourselves into a FieldExpr
5606 if (EventInfo.DeclaringType == ec.ContainerType ||
5607 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
5608 EventField mi = TypeManager.GetEventField (EventInfo);
5611 if (!ec.IsInObsoleteScope)
5612 mi.CheckObsoleteness (loc);
5614 if ((mi.ModFlags & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0 && !ec.IsInCompoundAssignment)
5615 Error_AssignmentEventOnly ();
5617 FieldExpr ml = new FieldExpr (mi.FieldBuilder, loc);
5619 InstanceExpression = null;
5621 return ml.ResolveMemberAccess (ec, left, loc, original);
5625 if (left is This && !ec.IsInCompoundAssignment)
5626 Error_AssignmentEventOnly ();
5628 return base.ResolveMemberAccess (ec, left, loc, original);
5632 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
5635 InstanceExpression = null;
5639 if (InstanceExpression == null) {
5640 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5644 InstanceExpression = InstanceExpression.DoResolve (ec);
5645 if (InstanceExpression == null)
5648 if (IsBase && add_accessor.IsAbstract) {
5649 Error_CannotCallAbstractBase(TypeManager.CSharpSignature(add_accessor));
5654 // This is using the same mechanism as the CS1540 check in PropertyExpr.
5655 // However, in the Event case, we reported a CS0122 instead.
5657 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
5658 InstanceExpression.Type != ec.ContainerType &&
5659 TypeManager.IsSubclassOf (ec.ContainerType, InstanceExpression.Type)) {
5660 Report.SymbolRelatedToPreviousError (EventInfo);
5661 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5668 public bool IsAccessibleFrom (Type invocation_type)
5671 return IsAccessorAccessible (invocation_type, add_accessor, out dummy) &&
5672 IsAccessorAccessible (invocation_type, remove_accessor, out dummy);
5675 public override Expression CreateExpressionTree (EmitContext ec)
5677 throw new NotSupportedException ();
5680 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5682 return DoResolve (ec);
5685 public override Expression DoResolve (EmitContext ec)
5687 bool must_do_cs1540_check;
5688 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
5689 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
5690 Report.SymbolRelatedToPreviousError (EventInfo);
5691 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5695 if (!InstanceResolve (ec, must_do_cs1540_check))
5701 public override void Emit (EmitContext ec)
5703 Report.Error (70, loc, "The event `{0}' can only appear on the left hand side of += or -= "+
5704 "(except on the defining type)", GetSignatureForError ());
5707 public override string GetSignatureForError ()
5709 return TypeManager.CSharpSignature (EventInfo);
5712 public void EmitAddOrRemove (EmitContext ec, Expression source)
5714 BinaryDelegate source_del = source as BinaryDelegate;
5715 if (source_del == null) {
5719 Expression handler = source_del.Right;
5721 Argument arg = new Argument (handler, Argument.AType.Expression);
5722 ArrayList args = new ArrayList ();
5726 if (source_del.IsAddition)
5727 Invocation.EmitCall (
5728 ec, IsBase, InstanceExpression, add_accessor, args, loc);
5730 Invocation.EmitCall (
5731 ec, IsBase, InstanceExpression, remove_accessor, args, loc);
5735 public class TemporaryVariable : Expression, IMemoryLocation
5740 public TemporaryVariable (Type type, Location loc)
5744 eclass = ExprClass.Value;
5747 public override Expression DoResolve (EmitContext ec)
5752 TypeExpr te = new TypeExpression (type, loc);
5753 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
5754 if (!li.Resolve (ec))
5757 if (ec.MustCaptureVariable (li)) {
5758 ScopeInfo scope = li.Block.CreateScopeInfo ();
5759 var = scope.AddLocal (li);
5766 public Variable Variable {
5767 get { return var != null ? var : li.Variable; }
5770 public override void Emit (EmitContext ec)
5772 Variable.EmitInstance (ec);
5776 public void EmitLoadAddress (EmitContext ec)
5778 Variable.EmitInstance (ec);
5779 Variable.EmitAddressOf (ec);
5782 public void Store (EmitContext ec, Expression right_side)
5784 Variable.EmitInstance (ec);
5785 right_side.Emit (ec);
5786 Variable.EmitAssign (ec);
5789 public void EmitThis (EmitContext ec)
5791 Variable.EmitInstance (ec);
5794 public void EmitStore (EmitContext ec)
5796 Variable.EmitAssign (ec);
5799 public void AddressOf (EmitContext ec, AddressOp mode)
5801 EmitLoadAddress (ec);
5806 /// Handles `var' contextual keyword; var becomes a keyword only
5807 /// if no type called var exists in a variable scope
5809 public class VarExpr : SimpleName
5811 // Used for error reporting only
5812 ArrayList initializer;
5814 public VarExpr (Location loc)
5819 public ArrayList VariableInitializer {
5821 this.initializer = value;
5825 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5828 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
5830 type = right_side.Type;
5831 if (type == TypeManager.null_type || type == TypeManager.void_type || type == TypeManager.anonymous_method_type) {
5832 Report.Error (815, loc, "An implicitly typed local variable declaration cannot be initialized with `{0}'",
5833 right_side.GetSignatureForError ());
5837 eclass = ExprClass.Variable;
5841 protected override void Error_TypeOrNamespaceNotFound (IResolveContext ec)
5843 Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");
5846 public override TypeExpr ResolveAsContextualType (IResolveContext rc, bool silent)
5848 TypeExpr te = base.ResolveAsContextualType (rc, true);
5852 if (initializer == null)
5855 if (initializer.Count > 1) {
5856 Location loc = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [1]).Location;
5857 Report.Error (819, loc, "An implicitly typed local variable declaration cannot include multiple declarators");
5862 Expression variable_initializer = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [0]).expression_or_array_initializer;
5863 if (variable_initializer == null) {
5864 Report.Error (818, loc, "An implicitly typed local variable declarator must include an initializer");