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 Constant ConvertImplicitly (Type target_type)
1621 // FIXME: Do we need to check user conversions?
1622 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1624 return child.ConvertImplicitly (target_type);
1630 /// This class is used to wrap literals which belong inside Enums
1632 public class EnumConstant : Constant {
1633 public Constant Child;
1635 public EnumConstant (Constant child, Type enum_type):
1636 base (child.Location)
1638 eclass = child.eclass;
1643 public override Expression DoResolve (EmitContext ec)
1645 // This should never be invoked, we are born in fully
1646 // initialized state.
1651 public override void Emit (EmitContext ec)
1656 public override bool GetAttributableValue (Type value_type, out object value)
1658 value = GetTypedValue ();
1662 public override string GetSignatureForError()
1664 return TypeManager.CSharpName (Type);
1667 public override object GetValue ()
1669 return Child.GetValue ();
1672 public override object GetTypedValue ()
1674 // FIXME: runtime is not ready to work with just emited enums
1675 if (!RootContext.StdLib) {
1676 return Child.GetValue ();
1679 return System.Enum.ToObject (type, Child.GetValue ());
1682 public override string AsString ()
1684 return TypeManager.CSharpEnumValue (type, Child.GetValue ());
1687 public override Constant Increment()
1689 return new EnumConstant (Child.Increment (), type);
1692 public override bool IsDefaultValue {
1694 return Child.IsDefaultValue;
1698 public override bool IsZeroInteger {
1699 get { return Child.IsZeroInteger; }
1702 public override bool IsNegative {
1704 return Child.IsNegative;
1708 public override Constant ConvertExplicitly(bool in_checked_context, Type target_type)
1710 if (Child.Type == target_type)
1713 return Child.ConvertExplicitly (in_checked_context, target_type);
1716 public override Constant ConvertImplicitly (Type type)
1718 Type this_type = TypeManager.DropGenericTypeArguments (Type);
1719 type = TypeManager.DropGenericTypeArguments (type);
1721 if (this_type == type) {
1722 // This is workaround of mono bug. It can be removed when the latest corlib spreads enough
1723 if (TypeManager.IsEnumType (type.UnderlyingSystemType))
1726 Type child_type = TypeManager.DropGenericTypeArguments (Child.Type);
1727 if (type.UnderlyingSystemType != child_type)
1728 Child = Child.ConvertImplicitly (type.UnderlyingSystemType);
1732 if (!Convert.ImplicitStandardConversionExists (this, type)){
1736 return Child.ConvertImplicitly(type);
1742 /// This kind of cast is used to encapsulate Value Types in objects.
1744 /// The effect of it is to box the value type emitted by the previous
1747 public class BoxedCast : TypeCast {
1749 public BoxedCast (Expression expr, Type target_type)
1750 : base (expr, target_type)
1752 eclass = ExprClass.Value;
1755 public override Expression DoResolve (EmitContext ec)
1757 // This should never be invoked, we are born in fully
1758 // initialized state.
1763 public override void Emit (EmitContext ec)
1767 ec.ig.Emit (OpCodes.Box, child.Type);
1770 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1772 if (child.Type.IsValueType &&
1773 (type == TypeManager.object_type || type == TypeManager.value_type)) {
1774 // 'Box' involves runtime checks for interface types, so we can't unconditionally assume we'll get a non-null here
1775 child.EmitSideEffect (ec);
1777 ec.ig.Emit (OpCodes.Br, label);
1780 base.EmitBranchable (ec, label, on_true);
1783 public override void EmitSideEffect (EmitContext ec)
1785 if (child.Type.IsValueType &&
1786 (type == TypeManager.object_type || type == TypeManager.value_type)) {
1787 child.EmitSideEffect (ec);
1790 // boxing is side-effectful, since it involves runtime checks
1791 base.EmitSideEffect (ec);
1795 public class UnboxCast : TypeCast {
1796 public UnboxCast (Expression expr, Type return_type)
1797 : base (expr, return_type)
1801 public override Expression DoResolve (EmitContext ec)
1803 // This should never be invoked, we are born in fully
1804 // initialized state.
1809 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1811 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
1812 Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
1813 return base.DoResolveLValue (ec, right_side);
1816 public override void Emit (EmitContext ec)
1819 ILGenerator ig = ec.ig;
1823 if (t.IsGenericParameter || t.IsGenericType && t.IsValueType)
1824 ig.Emit (OpCodes.Unbox_Any, t);
1828 ig.Emit (OpCodes.Unbox, t);
1830 LoadFromPtr (ig, t);
1836 /// This is used to perform explicit numeric conversions.
1838 /// Explicit numeric conversions might trigger exceptions in a checked
1839 /// context, so they should generate the conv.ovf opcodes instead of
1842 public class ConvCast : TypeCast {
1843 public enum Mode : byte {
1844 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1846 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1847 U2_I1, U2_U1, U2_I2, U2_CH,
1848 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1849 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1850 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH,
1851 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH,
1852 CH_I1, CH_U1, CH_I2,
1853 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1854 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4
1859 public ConvCast (Expression child, Type return_type, Mode m)
1860 : base (child, return_type)
1865 public override Expression DoResolve (EmitContext ec)
1867 // This should never be invoked, we are born in fully
1868 // initialized state.
1873 public override string ToString ()
1875 return String.Format ("ConvCast ({0}, {1})", mode, child);
1878 public override void Emit (EmitContext ec)
1880 ILGenerator ig = ec.ig;
1886 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1887 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1888 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1889 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1890 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1892 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1893 case Mode.U1_CH: /* nothing */ break;
1895 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1896 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1897 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1898 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1899 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1900 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1902 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1903 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1904 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1905 case Mode.U2_CH: /* nothing */ break;
1907 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1908 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1909 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1910 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1911 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1912 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1913 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1915 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1916 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1917 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1918 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1919 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1920 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1922 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1923 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1924 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1925 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1926 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1927 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1928 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1929 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1931 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1932 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1933 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1934 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1935 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1936 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1937 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1938 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1940 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1941 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1942 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1944 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1945 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1946 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1947 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1948 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1949 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1950 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1951 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1952 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1954 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1955 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1956 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1957 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1958 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1959 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1960 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1961 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1962 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1963 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1967 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
1968 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
1969 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
1970 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
1971 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
1973 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
1974 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
1976 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
1977 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
1978 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
1979 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
1980 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
1981 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
1983 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
1984 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
1985 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
1986 case Mode.U2_CH: /* nothing */ break;
1988 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
1989 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
1990 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
1991 case Mode.I4_U4: /* nothing */ break;
1992 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
1993 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
1994 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
1996 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
1997 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
1998 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
1999 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
2000 case Mode.U4_I4: /* nothing */ break;
2001 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
2003 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
2004 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
2005 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
2006 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
2007 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
2008 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
2009 case Mode.I8_U8: /* nothing */ break;
2010 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
2012 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
2013 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
2014 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
2015 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
2016 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
2017 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
2018 case Mode.U8_I8: /* nothing */ break;
2019 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
2021 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
2022 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
2023 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
2025 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
2026 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
2027 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
2028 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
2029 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
2030 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
2031 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
2032 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
2033 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
2035 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
2036 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
2037 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
2038 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
2039 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
2040 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
2041 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
2042 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
2043 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
2044 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
2050 public class OpcodeCast : TypeCast {
2054 public OpcodeCast (Expression child, Type return_type, OpCode op)
2055 : base (child, return_type)
2059 second_valid = false;
2062 public OpcodeCast (Expression child, Type return_type, OpCode op, OpCode op2)
2063 : base (child, return_type)
2068 second_valid = true;
2071 public override Expression DoResolve (EmitContext ec)
2073 // This should never be invoked, we are born in fully
2074 // initialized state.
2079 public override void Emit (EmitContext ec)
2088 public Type UnderlyingType {
2089 get { return child.Type; }
2094 /// This kind of cast is used to encapsulate a child and cast it
2095 /// to the class requested
2097 public class ClassCast : TypeCast {
2098 public ClassCast (Expression child, Type return_type)
2099 : base (child, return_type)
2104 public override Expression DoResolve (EmitContext ec)
2106 // This should never be invoked, we are born in fully
2107 // initialized state.
2112 public override void Emit (EmitContext ec)
2116 if (TypeManager.IsGenericParameter (child.Type))
2117 ec.ig.Emit (OpCodes.Box, child.Type);
2120 if (type.IsGenericParameter)
2121 ec.ig.Emit (OpCodes.Unbox_Any, type);
2124 ec.ig.Emit (OpCodes.Castclass, type);
2129 // Used when resolved expression has different representations for
2130 // expression trees and emit phase
2132 public class ReducedExpression : Expression
2134 class ReducedConstantExpression : Constant
2136 readonly Constant expr;
2137 readonly Expression orig_expr;
2139 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2140 : base (expr.Location)
2143 this.orig_expr = orig_expr;
2144 eclass = expr.eclass;
2148 public override string AsString ()
2150 return expr.AsString ();
2153 public override Expression CreateExpressionTree (EmitContext ec)
2155 return orig_expr.CreateExpressionTree (ec);
2158 public override object GetValue ()
2160 return expr.GetValue ();
2163 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
2165 throw new NotImplementedException ();
2168 public override Expression DoResolve (EmitContext ec)
2173 public override Constant Increment ()
2175 throw new NotImplementedException ();
2178 public override bool IsDefaultValue {
2180 return expr.IsDefaultValue;
2184 public override bool IsNegative {
2186 return expr.IsNegative;
2190 public override void Emit (EmitContext ec)
2196 readonly Expression expr, orig_expr;
2198 private ReducedExpression (Expression expr, Expression orig_expr)
2201 this.orig_expr = orig_expr;
2202 this.loc = orig_expr.Location;
2205 public static Expression Create (Constant expr, Expression original_expr)
2207 return new ReducedConstantExpression (expr, original_expr);
2210 public static Expression Create (Expression expr, Expression original_expr)
2212 Constant c = expr as Constant;
2214 return Create (c, original_expr);
2216 return new ReducedExpression (expr, original_expr);
2219 public override Expression CreateExpressionTree (EmitContext ec)
2221 return orig_expr.CreateExpressionTree (ec);
2224 public override Expression DoResolve (EmitContext ec)
2226 eclass = expr.eclass;
2231 public override void Emit (EmitContext ec)
2236 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2238 expr.EmitBranchable (ec, target, on_true);
2243 /// SimpleName expressions are formed of a single word and only happen at the beginning
2244 /// of a dotted-name.
2246 public class SimpleName : Expression {
2247 public readonly string Name;
2248 public readonly TypeArguments Arguments;
2251 public SimpleName (string name, Location l)
2257 public SimpleName (string name, TypeArguments args, Location l)
2264 public SimpleName (string name, TypeParameter[] type_params, Location l)
2269 Arguments = new TypeArguments (l);
2270 foreach (TypeParameter type_param in type_params)
2271 Arguments.Add (new TypeParameterExpr (type_param, l));
2274 public static string RemoveGenericArity (string name)
2277 StringBuilder sb = null;
2279 int pos = name.IndexOf ('`', start);
2284 sb.Append (name.Substring (start));
2289 sb = new StringBuilder ();
2290 sb.Append (name.Substring (start, pos-start));
2293 while ((pos < name.Length) && Char.IsNumber (name [pos]))
2297 } while (start < name.Length);
2299 return sb.ToString ();
2302 public SimpleName GetMethodGroup ()
2304 return new SimpleName (RemoveGenericArity (Name), Arguments, loc);
2307 public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
2309 if (ec.IsInFieldInitializer)
2310 Report.Error (236, l,
2311 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2315 120, l, "`{0}': An object reference is required for the nonstatic field, method or property",
2319 public bool IdenticalNameAndTypeName (EmitContext ec, Expression resolved_to, Location loc)
2321 return resolved_to != null && resolved_to.Type != null &&
2322 resolved_to.Type.Name == Name &&
2323 (ec.DeclContainer.LookupNamespaceOrType (Name, loc, /* ignore_cs0104 = */ true) != null);
2326 public override Expression DoResolve (EmitContext ec)
2328 return SimpleNameResolve (ec, null, false);
2331 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
2333 return SimpleNameResolve (ec, right_side, false);
2337 public Expression DoResolve (EmitContext ec, bool intermediate)
2339 return SimpleNameResolve (ec, null, intermediate);
2342 static bool IsNestedChild (Type t, Type parent)
2344 while (parent != null) {
2345 if (TypeManager.IsNestedChildOf (t, TypeManager.DropGenericTypeArguments (parent)))
2348 parent = parent.BaseType;
2354 FullNamedExpression ResolveNested (IResolveContext ec, Type t)
2356 if (!TypeManager.IsGenericTypeDefinition (t) && !TypeManager.IsGenericType (t))
2359 DeclSpace ds = ec.DeclContainer;
2360 while (ds != null && !IsNestedChild (t, ds.TypeBuilder))
2366 Type[] gen_params = TypeManager.GetTypeArguments (t);
2368 int arg_count = Arguments != null ? Arguments.Count : 0;
2370 for (; (ds != null) && ds.IsGeneric; ds = ds.Parent) {
2371 if (arg_count + ds.CountTypeParameters == gen_params.Length) {
2372 TypeArguments new_args = new TypeArguments (loc);
2373 foreach (TypeParameter param in ds.TypeParameters)
2374 new_args.Add (new TypeParameterExpr (param, loc));
2376 if (Arguments != null)
2377 new_args.Add (Arguments);
2379 return new ConstructedType (t, new_args, loc);
2386 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2388 FullNamedExpression fne = ec.GenericDeclContainer.LookupGeneric (Name, loc);
2390 return fne.ResolveAsTypeStep (ec, silent);
2392 int errors = Report.Errors;
2393 fne = ec.DeclContainer.LookupNamespaceOrType (Name, loc, /*ignore_cs0104=*/ false);
2396 if (fne.Type == null)
2399 FullNamedExpression nested = ResolveNested (ec, fne.Type);
2401 return nested.ResolveAsTypeStep (ec, false);
2403 if (Arguments != null) {
2404 ConstructedType ct = new ConstructedType (fne, Arguments, loc);
2405 return ct.ResolveAsTypeStep (ec, false);
2411 if (silent || errors != Report.Errors)
2414 Error_TypeOrNamespaceNotFound (ec);
2418 protected virtual void Error_TypeOrNamespaceNotFound (IResolveContext ec)
2420 MemberCore mc = ec.DeclContainer.GetDefinition (Name);
2422 Error_UnexpectedKind (ec.DeclContainer, "type", GetMemberType (mc), loc);
2426 string ns = ec.DeclContainer.NamespaceEntry.NS.Name;
2427 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2428 foreach (Assembly a in RootNamespace.Global.Assemblies) {
2429 Type type = a.GetType (fullname);
2431 Report.SymbolRelatedToPreviousError (type);
2432 Expression.ErrorIsInaccesible (loc, TypeManager.CSharpName (type));
2437 Type t = ec.DeclContainer.LookupAnyGeneric (Name);
2439 Namespace.Error_InvalidNumberOfTypeArguments (t, loc);
2443 if (Arguments != null) {
2444 FullNamedExpression retval = ec.DeclContainer.LookupNamespaceOrType (SimpleName.RemoveGenericArity (Name), loc, true);
2445 if (retval != null) {
2446 Namespace.Error_TypeArgumentsCannotBeUsed (retval.Type, loc);
2451 NamespaceEntry.Error_NamespaceNotFound (loc, Name);
2454 // TODO: I am still not convinced about this. If someone else will need it
2455 // implement this as virtual property in MemberCore hierarchy
2456 public static string GetMemberType (MemberCore mc)
2462 if (mc is FieldBase)
2464 if (mc is MethodCore)
2466 if (mc is EnumMember)
2474 Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2480 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2486 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2493 /// 7.5.2: Simple Names.
2495 /// Local Variables and Parameters are handled at
2496 /// parse time, so they never occur as SimpleNames.
2498 /// The `intermediate' flag is used by MemberAccess only
2499 /// and it is used to inform us that it is ok for us to
2500 /// avoid the static check, because MemberAccess might end
2501 /// up resolving the Name as a Type name and the access as
2502 /// a static type access.
2504 /// ie: Type Type; .... { Type.GetType (""); }
2506 /// Type is both an instance variable and a Type; Type.GetType
2507 /// is the static method not an instance method of type.
2509 Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2511 Expression e = null;
2514 // Stage 1: Performed by the parser (binding to locals or parameters).
2516 Block current_block = ec.CurrentBlock;
2517 if (current_block != null){
2518 LocalInfo vi = current_block.GetLocalInfo (Name);
2520 if (Arguments != null) {
2521 Report.Error (307, loc,
2522 "The variable `{0}' cannot be used with type arguments",
2527 LocalVariableReference var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2528 if (right_side != null) {
2529 return var.ResolveLValue (ec, right_side, loc);
2531 ResolveFlags rf = ResolveFlags.VariableOrValue;
2533 rf |= ResolveFlags.DisableFlowAnalysis;
2534 return var.Resolve (ec, rf);
2538 ParameterReference pref = current_block.Toplevel.GetParameterReference (Name, loc);
2540 if (Arguments != null) {
2541 Report.Error (307, loc,
2542 "The variable `{0}' cannot be used with type arguments",
2547 if (right_side != null)
2548 return pref.ResolveLValue (ec, right_side, loc);
2550 return pref.Resolve (ec);
2553 Expression expr = current_block.Toplevel.GetTransparentIdentifier (Name);
2555 if (right_side != null)
2556 return expr.ResolveLValue (ec, right_side, loc);
2557 return expr.Resolve (ec);
2562 // Stage 2: Lookup members
2565 Type almost_matched_type = null;
2566 ArrayList almost_matched = null;
2567 for (DeclSpace lookup_ds = ec.DeclContainer; lookup_ds != null; lookup_ds = lookup_ds.Parent) {
2568 // either RootDeclSpace or GenericMethod
2569 if (lookup_ds.TypeBuilder == null)
2572 e = MemberLookup (ec.ContainerType, lookup_ds.TypeBuilder, Name, loc);
2574 if (e is PropertyExpr) {
2575 // since TypeManager.MemberLookup doesn't know if we're doing a lvalue access or not,
2576 // it doesn't know which accessor to check permissions against
2577 if (((PropertyExpr) e).IsAccessibleFrom (ec.ContainerType, right_side != null))
2579 } else if (e is EventExpr) {
2580 if (((EventExpr) e).IsAccessibleFrom (ec.ContainerType))
2588 if (almost_matched == null && almost_matched_members.Count > 0) {
2589 almost_matched_type = lookup_ds.TypeBuilder;
2590 almost_matched = (ArrayList) almost_matched_members.Clone ();
2595 if (almost_matched == null && almost_matched_members.Count > 0) {
2596 almost_matched_type = ec.ContainerType;
2597 almost_matched = (ArrayList) almost_matched_members.Clone ();
2599 e = ResolveAsTypeStep (ec, true);
2603 if (current_block != null) {
2604 IKnownVariable ikv = current_block.Explicit.GetKnownVariable (Name);
2606 LocalInfo li = ikv as LocalInfo;
2607 // Supress CS0219 warning
2611 Error_VariableIsUsedBeforeItIsDeclared (Name);
2616 if (almost_matched != null)
2617 almost_matched_members = almost_matched;
2618 if (almost_matched_type == null)
2619 almost_matched_type = ec.ContainerType;
2620 Error_MemberLookupFailed (ec.ContainerType, null, almost_matched_type, Name,
2621 ec.DeclContainer.Name, AllMemberTypes, AllBindingFlags);
2625 if (e is TypeExpr) {
2626 if (Arguments == null)
2629 ConstructedType ct = new ConstructedType (
2630 (FullNamedExpression) e, Arguments, loc);
2631 return ct.ResolveAsTypeStep (ec, false);
2634 if (e is MemberExpr) {
2635 MemberExpr me = (MemberExpr) e;
2638 if (me.IsInstance) {
2639 if (ec.IsStatic || ec.IsInFieldInitializer) {
2641 // Note that an MemberExpr can be both IsInstance and IsStatic.
2642 // An unresolved MethodGroupExpr can contain both kinds of methods
2643 // and each predicate is true if the MethodGroupExpr contains
2644 // at least one of that kind of method.
2648 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2649 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2654 // Pass the buck to MemberAccess and Invocation.
2656 left = EmptyExpression.Null;
2658 left = ec.GetThis (loc);
2661 left = new TypeExpression (ec.ContainerType, loc);
2664 me = me.ResolveMemberAccess (ec, left, loc, null);
2668 if (Arguments != null) {
2669 Arguments.Resolve (ec);
2670 me.SetTypeArguments (Arguments);
2673 if (!me.IsStatic && (me.InstanceExpression != null) &&
2674 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2675 me.InstanceExpression.Type != me.DeclaringType &&
2676 !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2677 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2678 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2679 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2683 return (right_side != null)
2684 ? me.DoResolveLValue (ec, right_side)
2685 : me.DoResolve (ec);
2691 public override void Emit (EmitContext ec)
2693 throw new InternalErrorException ("The resolve phase was not executed");
2696 public override string ToString ()
2701 public override string GetSignatureForError ()
2703 if (Arguments != null) {
2704 return TypeManager.RemoveGenericArity (Name) + "<" +
2705 Arguments.GetSignatureForError () + ">";
2711 protected override void CloneTo (CloneContext clonectx, Expression target)
2713 // CloneTo: Nothing, we do not keep any state on this expression
2718 /// Represents a namespace or a type. The name of the class was inspired by
2719 /// section 10.8.1 (Fully Qualified Names).
2721 public abstract class FullNamedExpression : Expression {
2722 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2727 public abstract string FullName {
2733 /// Expression that evaluates to a type
2735 public abstract class TypeExpr : FullNamedExpression {
2736 override public FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2738 TypeExpr t = DoResolveAsTypeStep (ec);
2742 eclass = ExprClass.Type;
2746 override public Expression DoResolve (EmitContext ec)
2748 return ResolveAsTypeTerminal (ec, false);
2751 override public void Emit (EmitContext ec)
2753 throw new Exception ("Should never be called");
2756 public virtual bool CheckAccessLevel (DeclSpace ds)
2758 return ds.CheckAccessLevel (Type);
2761 public virtual bool AsAccessible (DeclSpace ds)
2763 return ds.IsAccessibleAs (Type);
2766 public virtual bool IsClass {
2767 get { return Type.IsClass; }
2770 public virtual bool IsValueType {
2771 get { return Type.IsValueType; }
2774 public virtual bool IsInterface {
2775 get { return Type.IsInterface; }
2778 public virtual bool IsSealed {
2779 get { return Type.IsSealed; }
2782 public virtual bool CanInheritFrom ()
2784 if (Type == TypeManager.enum_type ||
2785 (Type == TypeManager.value_type && RootContext.StdLib) ||
2786 Type == TypeManager.multicast_delegate_type ||
2787 Type == TypeManager.delegate_type ||
2788 Type == TypeManager.array_type)
2794 protected abstract TypeExpr DoResolveAsTypeStep (IResolveContext ec);
2796 public abstract string Name {
2800 public override bool Equals (object obj)
2802 TypeExpr tobj = obj as TypeExpr;
2806 return Type == tobj.Type;
2809 public override int GetHashCode ()
2811 return Type.GetHashCode ();
2814 public override string ToString ()
2821 /// Fully resolved Expression that already evaluated to a type
2823 public class TypeExpression : TypeExpr {
2824 public TypeExpression (Type t, Location l)
2827 eclass = ExprClass.Type;
2831 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2836 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2841 public override string Name {
2842 get { return Type.ToString (); }
2845 public override string FullName {
2846 get { return Type.FullName; }
2851 /// Used to create types from a fully qualified name. These are just used
2852 /// by the parser to setup the core types. A TypeLookupExpression is always
2853 /// classified as a type.
2855 public sealed class TypeLookupExpression : TypeExpr {
2856 readonly string name;
2858 public TypeLookupExpression (string name)
2861 eclass = ExprClass.Type;
2864 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2866 // It's null for corlib compilation only
2868 return DoResolveAsTypeStep (ec);
2873 private class UnexpectedType
2877 // This performes recursive type lookup, providing support for generic types.
2878 // For example, given the type:
2880 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]]
2882 // The types will be checked in the following order:
2885 // System.Collections |
2886 // System.Collections.Generic |
2888 // System | recursive call 1 |
2889 // System.Int32 _| | main method call
2891 // System | recursive call 2 |
2892 // System.String _| |
2894 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]] _|
2896 private Type TypeLookup (IResolveContext ec, string name)
2901 FullNamedExpression resolved = null;
2903 Type recursive_type = null;
2904 while (index < name.Length) {
2905 if (name[index] == '[') {
2910 if (name[index] == '[')
2912 else if (name[index] == ']')
2914 } while (braces > 0);
2915 recursive_type = TypeLookup (ec, name.Substring (open + 1, index - open - 1));
2916 if (recursive_type == null || (recursive_type == typeof(UnexpectedType)))
2917 return recursive_type;
2920 if (name[index] == ',')
2922 else if ((name[index] == '.' && !done) || (index == name.Length && name[0] != '[')) {
2923 string substring = name.Substring(dot, index - dot);
2925 if (resolved == null)
2926 resolved = RootNamespace.Global.Lookup (ec.DeclContainer, substring, Location.Null);
2927 else if (resolved is Namespace)
2928 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
2929 else if (type != null)
2930 type = TypeManager.GetNestedType (type, substring);
2934 if (resolved == null)
2936 else if (type == null && resolved is TypeExpr)
2937 type = resolved.Type;
2944 if (name[0] != '[') {
2945 string substring = name.Substring(dot, index - dot);
2948 return TypeManager.GetNestedType (type, substring);
2950 if (resolved != null) {
2951 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
2952 if (resolved is TypeExpr)
2953 return resolved.Type;
2955 if (resolved == null)
2958 resolved.Error_UnexpectedKind (ec.DeclContainer, "type", loc);
2959 return typeof (UnexpectedType);
2965 return recursive_type;
2968 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2970 Type t = TypeLookup (ec, name);
2972 NamespaceEntry.Error_NamespaceNotFound (loc, name);
2975 if (t == typeof(UnexpectedType))
2981 public override string Name {
2982 get { return name; }
2985 public override string FullName {
2986 get { return name; }
2989 protected override void CloneTo (CloneContext clonectx, Expression target)
2991 // CloneTo: Nothing, we do not keep any state on this expression
2994 public override string GetSignatureForError ()
2997 return TypeManager.CSharpName (name);
2999 return base.GetSignatureForError ();
3004 /// Represents an "unbound generic type", ie. typeof (Foo<>).
3007 public class UnboundTypeExpression : TypeExpr
3011 public UnboundTypeExpression (MemberName name, Location l)
3017 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
3020 if (name.Left != null) {
3021 Expression lexpr = name.Left.GetTypeExpression ();
3022 expr = new MemberAccess (lexpr, name.Basename);
3024 expr = new SimpleName (name.Basename, loc);
3027 FullNamedExpression fne = expr.ResolveAsTypeStep (ec, false);
3032 return new TypeExpression (type, loc);
3035 public override string Name {
3036 get { return name.PrettyName; }
3039 public override string FullName {
3040 get { return name.FullyQualifiedName; }
3044 public class TypeAliasExpression : TypeExpr {
3045 FullNamedExpression alias;
3050 public TypeAliasExpression (FullNamedExpression alias, TypeArguments args, Location l)
3056 eclass = ExprClass.Type;
3058 name = alias.FullName + "<" + args.ToString () + ">";
3060 name = alias.FullName;
3063 public override string Name {
3064 get { return alias.FullName; }
3067 public override string FullName {
3068 get { return name; }
3071 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
3073 texpr = alias.ResolveAsTypeTerminal (ec, false);
3077 Type type = texpr.Type;
3078 int num_args = TypeManager.GetNumberOfTypeArguments (type);
3081 if (num_args == 0) {
3082 Report.Error (308, loc,
3083 "The non-generic type `{0}' cannot " +
3084 "be used with type arguments.",
3085 TypeManager.CSharpName (type));
3089 ConstructedType ctype = new ConstructedType (type, args, loc);
3090 return ctype.ResolveAsTypeTerminal (ec, false);
3091 } else if (num_args > 0) {
3092 Report.Error (305, loc,
3093 "Using the generic type `{0}' " +
3094 "requires {1} type arguments",
3095 TypeManager.CSharpName (type), num_args.ToString ());
3102 public override bool CheckAccessLevel (DeclSpace ds)
3104 return texpr.CheckAccessLevel (ds);
3107 public override bool AsAccessible (DeclSpace ds)
3109 return texpr.AsAccessible (ds);
3112 public override bool IsClass {
3113 get { return texpr.IsClass; }
3116 public override bool IsValueType {
3117 get { return texpr.IsValueType; }
3120 public override bool IsInterface {
3121 get { return texpr.IsInterface; }
3124 public override bool IsSealed {
3125 get { return texpr.IsSealed; }
3130 /// This class denotes an expression which evaluates to a member
3131 /// of a struct or a class.
3133 public abstract class MemberExpr : Expression
3135 protected bool is_base;
3138 /// The name of this member.
3140 public abstract string Name {
3145 // When base.member is used
3147 public bool IsBase {
3148 get { return is_base; }
3149 set { is_base = value; }
3153 /// Whether this is an instance member.
3155 public abstract bool IsInstance {
3160 /// Whether this is a static member.
3162 public abstract bool IsStatic {
3167 /// The type which declares this member.
3169 public abstract Type DeclaringType {
3174 /// The instance expression associated with this member, if it's a
3175 /// non-static member.
3177 public Expression InstanceExpression;
3179 public static void error176 (Location loc, string name)
3181 Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
3182 "with an instance reference, qualify it with a type name instead", name);
3185 // TODO: possible optimalization
3186 // Cache resolved constant result in FieldBuilder <-> expression map
3187 public virtual MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3188 SimpleName original)
3192 // original == null || original.Resolve (...) ==> left
3195 if (left is TypeExpr) {
3196 left = left.ResolveAsTypeTerminal (ec, true);
3201 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3209 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3212 return ResolveExtensionMemberAccess (left);
3215 InstanceExpression = left;
3219 protected virtual MemberExpr ResolveExtensionMemberAccess (Expression left)
3221 error176 (loc, GetSignatureForError ());
3225 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3230 if (InstanceExpression == EmptyExpression.Null) {
3231 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3235 if (InstanceExpression.Type.IsValueType) {
3236 if (InstanceExpression is IMemoryLocation) {
3237 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
3239 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
3240 InstanceExpression.Emit (ec);
3242 t.AddressOf (ec, AddressOp.Store);
3245 InstanceExpression.Emit (ec);
3247 if (prepare_for_load)
3248 ec.ig.Emit (OpCodes.Dup);
3251 public virtual void SetTypeArguments (TypeArguments ta)
3253 // TODO: need to get correct member type
3254 Report.Error (307, loc, "The property `{0}' cannot be used with type arguments",
3255 GetSignatureForError ());
3260 /// Represents group of extension methods
3262 public class ExtensionMethodGroupExpr : MethodGroupExpr
3264 readonly NamespaceEntry namespace_entry;
3265 public Expression ExtensionExpression;
3266 Argument extension_argument;
3268 public ExtensionMethodGroupExpr (ArrayList list, NamespaceEntry n, Type extensionType, Location l)
3269 : base (list, extensionType, l)
3271 this.namespace_entry = n;
3274 public override bool IsStatic {
3275 get { return true; }
3278 public bool IsTopLevel {
3279 get { return namespace_entry == null; }
3282 public override void EmitArguments (EmitContext ec, ArrayList arguments)
3284 if (arguments == null)
3285 arguments = new ArrayList (1);
3286 arguments.Insert (0, extension_argument);
3287 base.EmitArguments (ec, arguments);
3290 public override void EmitCall (EmitContext ec, ArrayList arguments)
3292 if (arguments == null)
3293 arguments = new ArrayList (1);
3294 arguments.Insert (0, extension_argument);
3295 base.EmitCall (ec, arguments);
3298 public override MethodGroupExpr OverloadResolve (EmitContext ec, ref ArrayList arguments, bool may_fail, Location loc)
3300 if (arguments == null)
3301 arguments = new ArrayList (1);
3303 arguments.Insert (0, new Argument (ExtensionExpression));
3304 MethodGroupExpr mg = ResolveOverloadExtensions (ec, arguments, namespace_entry, loc);
3306 // Store resolved argument and restore original arguments
3308 ((ExtensionMethodGroupExpr)mg).extension_argument = (Argument)arguments [0];
3309 arguments.RemoveAt (0);
3314 MethodGroupExpr ResolveOverloadExtensions (EmitContext ec, ArrayList arguments, NamespaceEntry ns, Location loc)
3316 // Use normal resolve rules
3317 MethodGroupExpr mg = base.OverloadResolve (ec, ref arguments, ns != null, loc);
3325 ExtensionMethodGroupExpr e = ns.LookupExtensionMethod (type, null, Name, loc);
3327 return base.OverloadResolve (ec, ref arguments, false, loc);
3329 e.ExtensionExpression = ExtensionExpression;
3330 return e.ResolveOverloadExtensions (ec, arguments, e.namespace_entry, loc);
3335 /// MethodGroupExpr represents a group of method candidates which
3336 /// can be resolved to the best method overload
3338 public class MethodGroupExpr : MemberExpr
3340 public interface IErrorHandler
3342 bool NoExactMatch (EmitContext ec, MethodBase method);
3345 public IErrorHandler CustomErrorHandler;
3346 public MethodBase [] Methods;
3347 MethodBase best_candidate;
3348 // TODO: make private
3349 public TypeArguments type_arguments;
3350 bool identical_type_name;
3353 public MethodGroupExpr (MemberInfo [] mi, Type type, Location l)
3356 Methods = new MethodBase [mi.Length];
3357 mi.CopyTo (Methods, 0);
3360 public MethodGroupExpr (ArrayList list, Type type, Location l)
3364 Methods = (MethodBase[])list.ToArray (typeof (MethodBase));
3366 foreach (MemberInfo m in list){
3367 if (!(m is MethodBase)){
3368 Console.WriteLine ("Name " + m.Name);
3369 Console.WriteLine ("Found a: " + m.GetType ().FullName);
3378 protected MethodGroupExpr (Type type, Location loc)
3381 eclass = ExprClass.MethodGroup;
3385 public override Type DeclaringType {
3388 // We assume that the top-level type is in the end
3390 return Methods [Methods.Length - 1].DeclaringType;
3391 //return Methods [0].DeclaringType;
3395 public Type DelegateType {
3397 delegate_type = value;
3401 public bool IdenticalTypeName {
3403 return identical_type_name;
3407 identical_type_name = value;
3411 public override string GetSignatureForError ()
3413 if (best_candidate != null)
3414 return TypeManager.CSharpSignature (best_candidate);
3416 return TypeManager.CSharpSignature (Methods [0]);
3419 public override string Name {
3421 return Methods [0].Name;
3425 public override bool IsInstance {
3427 if (best_candidate != null)
3428 return !best_candidate.IsStatic;
3430 foreach (MethodBase mb in Methods)
3438 public override bool IsStatic {
3440 if (best_candidate != null)
3441 return best_candidate.IsStatic;
3443 foreach (MethodBase mb in Methods)
3451 public static explicit operator ConstructorInfo (MethodGroupExpr mg)
3453 return (ConstructorInfo)mg.best_candidate;
3456 public static explicit operator MethodInfo (MethodGroupExpr mg)
3458 return (MethodInfo)mg.best_candidate;
3462 // 7.4.3.3 Better conversion from expression
3463 // Returns : 1 if a->p is better,
3464 // 2 if a->q is better,
3465 // 0 if neither is better
3467 static int BetterExpressionConversion (EmitContext ec, Argument a, Type p, Type q)
3469 Type argument_type = TypeManager.TypeToCoreType (a.Type);
3470 if (argument_type == TypeManager.anonymous_method_type && RootContext.Version > LanguageVersion.ISO_2) {
3472 // Uwrap delegate from Expression<T>
3474 if (TypeManager.DropGenericTypeArguments (p) == TypeManager.expression_type) {
3475 p = TypeManager.GetTypeArguments (p) [0];
3476 q = TypeManager.GetTypeArguments (q) [0];
3478 p = Delegate.GetInvokeMethod (null, p).ReturnType;
3479 q = Delegate.GetInvokeMethod (null, q).ReturnType;
3481 if (argument_type == p)
3484 if (argument_type == q)
3488 return BetterTypeConversion (ec, p, q);
3492 // 7.4.3.4 Better conversion from type
3494 public static int BetterTypeConversion (EmitContext ec, Type p, Type q)
3496 if (p == null || q == null)
3497 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3499 if (p == TypeManager.int32_type) {
3500 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3502 } else if (p == TypeManager.int64_type) {
3503 if (q == TypeManager.uint64_type)
3505 } else if (p == TypeManager.sbyte_type) {
3506 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3507 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3509 } else if (p == TypeManager.short_type) {
3510 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3511 q == TypeManager.uint64_type)
3515 if (q == TypeManager.int32_type) {
3516 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3518 } if (q == TypeManager.int64_type) {
3519 if (p == TypeManager.uint64_type)
3521 } else if (q == TypeManager.sbyte_type) {
3522 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3523 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3525 } if (q == TypeManager.short_type) {
3526 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3527 p == TypeManager.uint64_type)
3531 // TODO: this is expensive
3532 Expression p_tmp = new EmptyExpression (p);
3533 Expression q_tmp = new EmptyExpression (q);
3535 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3536 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3538 if (p_to_q && !q_to_p)
3541 if (q_to_p && !p_to_q)
3548 /// Determines "Better function" between candidate
3549 /// and the current best match
3552 /// Returns a boolean indicating :
3553 /// false if candidate ain't better
3554 /// true if candidate is better than the current best match
3556 static bool BetterFunction (EmitContext ec, ArrayList args, int argument_count,
3557 MethodBase candidate, bool candidate_params,
3558 MethodBase best, bool best_params)
3560 ParameterData candidate_pd = TypeManager.GetParameterData (candidate);
3561 ParameterData best_pd = TypeManager.GetParameterData (best);
3563 bool better_at_least_one = false;
3565 for (int j = 0, c_idx = 0, b_idx = 0; j < argument_count; ++j, ++c_idx, ++b_idx)
3567 Argument a = (Argument) args [j];
3569 Type ct = TypeManager.TypeToCoreType (candidate_pd.ParameterType (c_idx));
3570 Type bt = TypeManager.TypeToCoreType (best_pd.ParameterType (b_idx));
3572 if (candidate_params && candidate_pd.ParameterModifier (c_idx) == Parameter.Modifier.PARAMS)
3574 ct = TypeManager.GetElementType (ct);
3578 if (best_params && best_pd.ParameterModifier (b_idx) == Parameter.Modifier.PARAMS)
3580 bt = TypeManager.GetElementType (bt);
3588 int result = BetterExpressionConversion (ec, a, ct, bt);
3590 // for each argument, the conversion to 'ct' should be no worse than
3591 // the conversion to 'bt'.
3595 // for at least one argument, the conversion to 'ct' should be better than
3596 // the conversion to 'bt'.
3598 better_at_least_one = true;
3601 if (better_at_least_one)
3605 // This handles the case
3607 // Add (float f1, float f2, float f3);
3608 // Add (params decimal [] foo);
3610 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3611 // first candidate would've chosen as better.
3617 // The two methods have equal parameter types. Now apply tie-breaking rules
3619 if (TypeManager.IsGenericMethod (best) && !TypeManager.IsGenericMethod (candidate))
3621 if (!TypeManager.IsGenericMethod (best) && TypeManager.IsGenericMethod (candidate))
3625 // This handles the following cases:
3627 // Trim () is better than Trim (params char[] chars)
3628 // Concat (string s1, string s2, string s3) is better than
3629 // Concat (string s1, params string [] srest)
3630 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3632 if (!candidate_params && best_params)
3634 if (candidate_params && !best_params)
3637 int candidate_param_count = candidate_pd.Count;
3638 int best_param_count = best_pd.Count;
3640 if (candidate_param_count != best_param_count)
3641 // can only happen if (candidate_params && best_params)
3642 return candidate_param_count > best_param_count;
3645 // now, both methods have the same number of parameters, and the parameters have the same types
3646 // Pick the "more specific" signature
3649 MethodBase orig_candidate = TypeManager.DropGenericMethodArguments (candidate);
3650 MethodBase orig_best = TypeManager.DropGenericMethodArguments (best);
3652 ParameterData orig_candidate_pd = TypeManager.GetParameterData (orig_candidate);
3653 ParameterData orig_best_pd = TypeManager.GetParameterData (orig_best);
3655 bool specific_at_least_once = false;
3656 for (int j = 0; j < candidate_param_count; ++j)
3658 Type ct = TypeManager.TypeToCoreType (orig_candidate_pd.ParameterType (j));
3659 Type bt = TypeManager.TypeToCoreType (orig_best_pd.ParameterType (j));
3662 Type specific = MoreSpecific (ct, bt);
3666 specific_at_least_once = true;
3669 if (specific_at_least_once)
3672 // FIXME: handle lifted operators
3678 protected override MemberExpr ResolveExtensionMemberAccess (Expression left)
3681 return base.ResolveExtensionMemberAccess (left);
3684 // When left side is an expression and at least one candidate method is
3685 // static, it can be extension method
3687 InstanceExpression = left;
3691 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3692 SimpleName original)
3694 if (!(left is TypeExpr) &&
3695 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3696 IdenticalTypeName = true;
3698 return base.ResolveMemberAccess (ec, left, loc, original);
3701 public override Expression CreateExpressionTree (EmitContext ec)
3703 Type t = best_candidate.IsConstructor ?
3704 typeof (ConstructorInfo) : typeof (MethodInfo);
3706 return new Cast (new TypeExpression (t, loc), new TypeOfMethod (best_candidate, loc));
3709 override public Expression DoResolve (EmitContext ec)
3711 if (InstanceExpression != null) {
3712 InstanceExpression = InstanceExpression.DoResolve (ec);
3713 if (InstanceExpression == null)
3720 public void ReportUsageError ()
3722 Report.Error (654, loc, "Method `" + DeclaringType + "." +
3723 Name + "()' is referenced without parentheses");
3726 override public void Emit (EmitContext ec)
3728 ReportUsageError ();
3731 public virtual void EmitArguments (EmitContext ec, ArrayList arguments)
3733 Invocation.EmitArguments (ec, arguments, false, null);
3736 public virtual void EmitCall (EmitContext ec, ArrayList arguments)
3738 Invocation.EmitCall (ec, IsBase, InstanceExpression, best_candidate, arguments, loc);
3741 protected virtual void Error_InvalidArguments (EmitContext ec, Location loc, int idx, MethodBase method,
3742 Argument a, ParameterData expected_par, Type paramType)
3744 if (a is CollectionElementInitializer.ElementInitializerArgument) {
3745 Report.SymbolRelatedToPreviousError (method);
3746 if ((expected_par.ParameterModifier (idx) & Parameter.Modifier.ISBYREF) != 0) {
3747 Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
3748 TypeManager.CSharpSignature (method));
3751 Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
3752 TypeManager.CSharpSignature (method));
3753 } else if (delegate_type == null) {
3754 Report.SymbolRelatedToPreviousError (method);
3755 Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
3756 TypeManager.CSharpSignature (method));
3758 Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
3759 TypeManager.CSharpName (delegate_type));
3761 Parameter.Modifier mod = expected_par.ParameterModifier (idx);
3763 string index = (idx + 1).ToString ();
3764 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
3765 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
3766 if ((mod & Parameter.Modifier.ISBYREF) == 0)
3767 Report.Error (1615, loc, "Argument `{0}' should not be passed with the `{1}' keyword",
3768 index, Parameter.GetModifierSignature (a.Modifier));
3770 Report.Error (1620, loc, "Argument `{0}' must be passed with the `{1}' keyword",
3771 index, Parameter.GetModifierSignature (mod));
3773 string p1 = a.GetSignatureForError ();
3774 string p2 = TypeManager.CSharpName (paramType);
3777 Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
3778 Report.SymbolRelatedToPreviousError (a.Expr.Type);
3779 Report.SymbolRelatedToPreviousError (paramType);
3781 Report.Error (1503, loc, "Argument {0}: Cannot convert type `{1}' to `{2}'", index, p1, p2);
3785 public override void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl)
3787 Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3788 Name, TypeManager.CSharpName (target));
3791 protected virtual int GetApplicableParametersCount (MethodBase method, ParameterData parameters)
3793 return parameters.Count;
3796 public static bool IsAncestralType (Type first_type, Type second_type)
3798 return first_type != second_type &&
3799 (TypeManager.IsSubclassOf (second_type, first_type) ||
3800 TypeManager.ImplementsInterface (second_type, first_type));
3804 /// Determines if the candidate method is applicable (section 14.4.2.1)
3805 /// to the given set of arguments
3806 /// A return value rates candidate method compatibility,
3807 /// 0 = the best, int.MaxValue = the worst
3809 public int IsApplicable (EmitContext ec,
3810 ArrayList arguments, int arg_count, ref MethodBase method, ref bool params_expanded_form)
3812 MethodBase candidate = method;
3814 ParameterData pd = TypeManager.GetParameterData (candidate);
3815 int param_count = GetApplicableParametersCount (candidate, pd);
3817 if (arg_count != param_count) {
3819 return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
3820 if (arg_count < param_count - 1)
3821 return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
3826 // 1. Handle generic method using type arguments when specified or type inference
3828 if (TypeManager.IsGenericMethod (candidate)) {
3829 if (type_arguments != null) {
3830 Type [] g_args = candidate.GetGenericArguments ();
3831 if (g_args.Length != type_arguments.Count)
3832 return int.MaxValue - 20000 + Math.Abs (type_arguments.Count - g_args.Length);
3834 // TODO: Don't create new method, create Parameters only
3835 method = ((MethodInfo) candidate).MakeGenericMethod (type_arguments.Arguments);
3837 pd = TypeManager.GetParameterData (candidate);
3839 int score = TypeManager.InferTypeArguments (ec, arguments, ref candidate);
3841 return score - 20000;
3843 if (TypeManager.IsGenericMethodDefinition (candidate))
3844 throw new InternalErrorException ("A generic method `{0}' definition took part in overload resolution",
3845 TypeManager.CSharpSignature (candidate));
3847 pd = TypeManager.GetParameterData (candidate);
3850 if (type_arguments != null)
3851 return int.MaxValue - 15000;
3856 // 2. Each argument has to be implicitly convertible to method parameter
3859 Parameter.Modifier p_mod = 0;
3861 for (int i = 0; i < arg_count; i++) {
3862 Argument a = (Argument) arguments [i];
3863 Parameter.Modifier a_mod = a.Modifier &
3864 ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3866 if (p_mod != Parameter.Modifier.PARAMS) {
3867 p_mod = pd.ParameterModifier (i) & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3869 if (p_mod == Parameter.Modifier.ARGLIST) {
3870 if (a.Type == TypeManager.runtime_argument_handle_type)
3876 pt = pd.ParameterType (i);
3878 params_expanded_form = true;
3882 if (!params_expanded_form)
3883 score = IsArgumentCompatible (ec, a_mod, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
3885 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0) {
3886 // It can be applicable in expanded form
3887 score = IsArgumentCompatible (ec, a_mod, a, 0, pt.GetElementType ());
3889 params_expanded_form = true;
3893 if (params_expanded_form)
3895 return (arg_count - i) * 2 + score;
3899 if (arg_count != param_count)
3900 params_expanded_form = true;
3905 int IsArgumentCompatible (EmitContext ec, Parameter.Modifier arg_mod, Argument argument, Parameter.Modifier param_mod, Type parameter)
3908 // Types have to be identical when ref or out modifer is used
3910 if (arg_mod != 0 || param_mod != 0) {
3911 if (TypeManager.HasElementType (parameter))
3912 parameter = parameter.GetElementType ();
3914 Type a_type = argument.Type;
3915 if (TypeManager.HasElementType (a_type))
3916 a_type = a_type.GetElementType ();
3918 if (a_type != parameter)
3924 // FIXME: Kill this abomination (EmitContext.TempEc)
3925 EmitContext prevec = EmitContext.TempEc;
3926 EmitContext.TempEc = ec;
3928 if (delegate_type != null ?
3929 !Delegate.IsTypeCovariant (argument.Expr, parameter) :
3930 !Convert.ImplicitConversionExists (ec, argument.Expr, parameter))
3933 if (arg_mod != param_mod)
3937 EmitContext.TempEc = prevec;
3943 public static bool IsOverride (MethodBase cand_method, MethodBase base_method)
3945 if (!IsAncestralType (base_method.DeclaringType, cand_method.DeclaringType))
3948 ParameterData cand_pd = TypeManager.GetParameterData (cand_method);
3949 ParameterData base_pd = TypeManager.GetParameterData (base_method);
3951 if (cand_pd.Count != base_pd.Count)
3954 for (int j = 0; j < cand_pd.Count; ++j)
3956 Parameter.Modifier cm = cand_pd.ParameterModifier (j);
3957 Parameter.Modifier bm = base_pd.ParameterModifier (j);
3958 Type ct = TypeManager.TypeToCoreType (cand_pd.ParameterType (j));
3959 Type bt = TypeManager.TypeToCoreType (base_pd.ParameterType (j));
3961 if (cm != bm || ct != bt)
3968 public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2, Location loc)
3970 MemberInfo [] miset;
3971 MethodGroupExpr union;
3976 return (MethodGroupExpr) mg2;
3979 return (MethodGroupExpr) mg1;
3982 MethodGroupExpr left_set = null, right_set = null;
3983 int length1 = 0, length2 = 0;
3985 left_set = (MethodGroupExpr) mg1;
3986 length1 = left_set.Methods.Length;
3988 right_set = (MethodGroupExpr) mg2;
3989 length2 = right_set.Methods.Length;
3991 ArrayList common = new ArrayList ();
3993 foreach (MethodBase r in right_set.Methods){
3994 if (TypeManager.ArrayContainsMethod (left_set.Methods, r))
3998 miset = new MemberInfo [length1 + length2 - common.Count];
3999 left_set.Methods.CopyTo (miset, 0);
4003 foreach (MethodBase r in right_set.Methods) {
4004 if (!common.Contains (r))
4008 union = new MethodGroupExpr (miset, mg1.Type, loc);
4013 static Type MoreSpecific (Type p, Type q)
4015 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4017 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4020 if (TypeManager.HasElementType (p))
4022 Type pe = TypeManager.GetElementType (p);
4023 Type qe = TypeManager.GetElementType (q);
4024 Type specific = MoreSpecific (pe, qe);
4030 else if (TypeManager.IsGenericType (p))
4032 Type[] pargs = TypeManager.GetTypeArguments (p);
4033 Type[] qargs = TypeManager.GetTypeArguments (q);
4035 bool p_specific_at_least_once = false;
4036 bool q_specific_at_least_once = false;
4038 for (int i = 0; i < pargs.Length; i++)
4040 Type specific = MoreSpecific (pargs [i], qargs [i]);
4041 if (specific == pargs [i])
4042 p_specific_at_least_once = true;
4043 if (specific == qargs [i])
4044 q_specific_at_least_once = true;
4047 if (p_specific_at_least_once && !q_specific_at_least_once)
4049 if (!p_specific_at_least_once && q_specific_at_least_once)
4057 /// Find the Applicable Function Members (7.4.2.1)
4059 /// me: Method Group expression with the members to select.
4060 /// it might contain constructors or methods (or anything
4061 /// that maps to a method).
4063 /// Arguments: ArrayList containing resolved Argument objects.
4065 /// loc: The location if we want an error to be reported, or a Null
4066 /// location for "probing" purposes.
4068 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4069 /// that is the best match of me on Arguments.
4072 public virtual MethodGroupExpr OverloadResolve (EmitContext ec, ref ArrayList Arguments,
4073 bool may_fail, Location loc)
4075 bool method_params = false;
4076 Type applicable_type = null;
4078 ArrayList candidates = new ArrayList (2);
4079 ArrayList candidate_overrides = null;
4082 // Used to keep a map between the candidate
4083 // and whether it is being considered in its
4084 // normal or expanded form
4086 // false is normal form, true is expanded form
4088 Hashtable candidate_to_form = null;
4090 if (Arguments != null)
4091 arg_count = Arguments.Count;
4093 if (RootContext.Version == LanguageVersion.ISO_1 && Name == "Invoke" && TypeManager.IsDelegateType (DeclaringType)) {
4095 Report.Error (1533, loc, "Invoke cannot be called directly on a delegate");
4099 int nmethods = Methods.Length;
4103 // Methods marked 'override' don't take part in 'applicable_type'
4104 // computation, nor in the actual overload resolution.
4105 // However, they still need to be emitted instead of a base virtual method.
4106 // So, we salt them away into the 'candidate_overrides' array.
4108 // In case of reflected methods, we replace each overriding method with
4109 // its corresponding base virtual method. This is to improve compatibility
4110 // with non-C# libraries which change the visibility of overrides (#75636)
4113 for (int i = 0; i < Methods.Length; ++i) {
4114 MethodBase m = Methods [i];
4115 if (TypeManager.IsOverride (m)) {
4116 if (candidate_overrides == null)
4117 candidate_overrides = new ArrayList ();
4118 candidate_overrides.Add (m);
4119 m = TypeManager.TryGetBaseDefinition (m);
4128 // Enable message recording, it's used mainly by lambda expressions
4130 Report.IMessageRecorder msg_recorder = new Report.MessageRecorder ();
4131 Report.IMessageRecorder prev_recorder = Report.SetMessageRecorder (msg_recorder);
4134 // First we construct the set of applicable methods
4136 bool is_sorted = true;
4137 int best_candidate_rate = int.MaxValue;
4138 for (int i = 0; i < nmethods; i++) {
4139 Type decl_type = Methods [i].DeclaringType;
4142 // If we have already found an applicable method
4143 // we eliminate all base types (Section 14.5.5.1)
4145 if (applicable_type != null && IsAncestralType (decl_type, applicable_type))
4149 // Check if candidate is applicable (section 14.4.2.1)
4151 bool params_expanded_form = false;
4152 int candidate_rate = IsApplicable (ec, Arguments, arg_count, ref Methods [i], ref params_expanded_form);
4154 if (candidate_rate < best_candidate_rate) {
4155 best_candidate_rate = candidate_rate;
4156 best_candidate = Methods [i];
4159 if (params_expanded_form) {
4160 if (candidate_to_form == null)
4161 candidate_to_form = new PtrHashtable ();
4162 MethodBase candidate = Methods [i];
4163 candidate_to_form [candidate] = candidate;
4166 if (candidate_rate != 0) {
4167 if (msg_recorder != null)
4168 msg_recorder.EndSession ();
4172 msg_recorder = null;
4173 candidates.Add (Methods [i]);
4175 if (applicable_type == null)
4176 applicable_type = decl_type;
4177 else if (applicable_type != decl_type) {
4179 if (IsAncestralType (applicable_type, decl_type))
4180 applicable_type = decl_type;
4184 Report.SetMessageRecorder (prev_recorder);
4185 if (msg_recorder != null && msg_recorder.PrintMessages ())
4188 int candidate_top = candidates.Count;
4190 if (applicable_type == null) {
4192 // When we found a top level method which does not match and it's
4193 // not an extension method. We start extension methods lookup from here
4195 if (InstanceExpression != null) {
4196 ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (type, Name, loc);
4197 if (ex_method_lookup != null) {
4198 ex_method_lookup.ExtensionExpression = InstanceExpression;
4199 ex_method_lookup.SetTypeArguments (type_arguments);
4200 return ex_method_lookup.OverloadResolve (ec, ref Arguments, may_fail, loc);
4208 // Okay so we have failed to find exact match so we
4209 // return error info about the closest match
4211 if (best_candidate != null) {
4212 if (CustomErrorHandler != null) {
4213 if (CustomErrorHandler.NoExactMatch (ec, best_candidate))
4217 ParameterData pd = TypeManager.GetParameterData (best_candidate);
4218 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4219 if (arg_count == pd.Count || pd.HasParams) {
4220 if (TypeManager.IsGenericMethodDefinition (best_candidate)) {
4221 if (type_arguments == null) {
4222 Report.Error (411, loc,
4223 "The type arguments for method `{0}' cannot be inferred from " +
4224 "the usage. Try specifying the type arguments explicitly",
4225 TypeManager.CSharpSignature (best_candidate));
4229 Type [] g_args = TypeManager.GetGenericArguments (best_candidate);
4230 if (type_arguments.Count != g_args.Length) {
4231 Report.SymbolRelatedToPreviousError (best_candidate);
4232 Report.Error (305, loc, "Using the generic method `{0}' requires `{1}' type argument(s)",
4233 TypeManager.CSharpSignature (best_candidate),
4234 g_args.Length.ToString ());
4238 if (type_arguments != null && !TypeManager.IsGenericMethod (best_candidate)) {
4239 Namespace.Error_TypeArgumentsCannotBeUsed (best_candidate, loc);
4244 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate, cand_params, may_fail, loc))
4249 if (almost_matched_members.Count != 0) {
4250 Error_MemberLookupFailed (ec.ContainerType, type, type, ".ctor",
4251 null, MemberTypes.Constructor, AllBindingFlags);
4256 // We failed to find any method with correct argument count
4258 if (Name == ConstructorInfo.ConstructorName) {
4259 Report.SymbolRelatedToPreviousError (type);
4260 Report.Error (1729, loc,
4261 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4262 TypeManager.CSharpName (type), arg_count);
4264 Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4265 Name, arg_count.ToString ());
4273 // At this point, applicable_type is _one_ of the most derived types
4274 // in the set of types containing the methods in this MethodGroup.
4275 // Filter the candidates so that they only contain methods from the
4276 // most derived types.
4279 int finalized = 0; // Number of finalized candidates
4282 // Invariant: applicable_type is a most derived type
4284 // We'll try to complete Section 14.5.5.1 for 'applicable_type' by
4285 // eliminating all it's base types. At the same time, we'll also move
4286 // every unrelated type to the end of the array, and pick the next
4287 // 'applicable_type'.
4289 Type next_applicable_type = null;
4290 int j = finalized; // where to put the next finalized candidate
4291 int k = finalized; // where to put the next undiscarded candidate
4292 for (int i = finalized; i < candidate_top; ++i) {
4293 MethodBase candidate = (MethodBase) candidates [i];
4294 Type decl_type = candidate.DeclaringType;
4296 if (decl_type == applicable_type) {
4297 candidates [k++] = candidates [j];
4298 candidates [j++] = candidates [i];
4302 if (IsAncestralType (decl_type, applicable_type))
4305 if (next_applicable_type != null &&
4306 IsAncestralType (decl_type, next_applicable_type))
4309 candidates [k++] = candidates [i];
4311 if (next_applicable_type == null ||
4312 IsAncestralType (next_applicable_type, decl_type))
4313 next_applicable_type = decl_type;
4316 applicable_type = next_applicable_type;
4319 } while (applicable_type != null);
4323 // Now we actually find the best method
4326 best_candidate = (MethodBase) candidates [0];
4327 if (delegate_type == null)
4328 method_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4330 for (int ix = 1; ix < candidate_top; ix++) {
4331 MethodBase candidate = (MethodBase) candidates [ix];
4333 if (candidate == best_candidate)
4336 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4338 if (BetterFunction (ec, Arguments, arg_count,
4339 candidate, cand_params,
4340 best_candidate, method_params)) {
4341 best_candidate = candidate;
4342 method_params = cand_params;
4346 // Now check that there are no ambiguities i.e the selected method
4347 // should be better than all the others
4349 MethodBase ambiguous = null;
4350 for (int ix = 1; ix < candidate_top; ix++) {
4351 MethodBase candidate = (MethodBase) candidates [ix];
4353 if (candidate == best_candidate)
4356 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4357 if (!BetterFunction (ec, Arguments, arg_count,
4358 best_candidate, method_params,
4359 candidate, cand_params))
4362 Report.SymbolRelatedToPreviousError (candidate);
4363 ambiguous = candidate;
4367 if (ambiguous != null) {
4368 Report.SymbolRelatedToPreviousError (best_candidate);
4369 Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4370 TypeManager.CSharpSignature (ambiguous), TypeManager.CSharpSignature (best_candidate));
4375 // If the method is a virtual function, pick an override closer to the LHS type.
4377 if (!IsBase && best_candidate.IsVirtual) {
4378 if (TypeManager.IsOverride (best_candidate))
4379 throw new InternalErrorException (
4380 "Should not happen. An 'override' method took part in overload resolution: " + best_candidate);
4382 if (candidate_overrides != null) {
4383 Type[] gen_args = null;
4384 bool gen_override = false;
4385 if (TypeManager.IsGenericMethod (best_candidate))
4386 gen_args = TypeManager.GetGenericArguments (best_candidate);
4388 foreach (MethodBase candidate in candidate_overrides) {
4389 if (TypeManager.IsGenericMethod (candidate)) {
4390 if (gen_args == null)
4393 if (gen_args.Length != TypeManager.GetGenericArguments (candidate).Length)
4396 if (gen_args != null)
4400 if (IsOverride (candidate, best_candidate)) {
4401 gen_override = true;
4402 best_candidate = candidate;
4406 if (gen_override && gen_args != null) {
4408 best_candidate = ((MethodInfo) best_candidate).MakeGenericMethod (gen_args);
4415 // And now check if the arguments are all
4416 // compatible, perform conversions if
4417 // necessary etc. and return if everything is
4420 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate,
4421 method_params, may_fail, loc))
4424 if (best_candidate == null)
4427 MethodBase the_method = TypeManager.DropGenericMethodArguments (best_candidate);
4429 if (the_method.IsGenericMethodDefinition &&
4430 !ConstraintChecker.CheckConstraints (ec, the_method, best_candidate, loc))
4434 IMethodData data = TypeManager.GetMethod (the_method);
4436 data.SetMemberIsUsed ();
4441 public override void SetTypeArguments (TypeArguments ta)
4443 type_arguments = ta;
4446 public bool VerifyArgumentsCompat (EmitContext ec, ref ArrayList arguments,
4447 int arg_count, MethodBase method,
4448 bool chose_params_expanded,
4449 bool may_fail, Location loc)
4451 ParameterData pd = TypeManager.GetParameterData (method);
4453 int errors = Report.Errors;
4454 Parameter.Modifier p_mod = 0;
4456 int a_idx = 0, a_pos = 0;
4458 ArrayList params_initializers = null;
4460 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4461 a = (Argument) arguments [a_idx];
4462 if (p_mod != Parameter.Modifier.PARAMS) {
4463 p_mod = pd.ParameterModifier (a_idx);
4464 pt = pd.ParameterType (a_idx);
4466 if (p_mod == Parameter.Modifier.ARGLIST) {
4467 if (a.Type != TypeManager.runtime_argument_handle_type)
4472 if (pt.IsPointer && !ec.InUnsafe) {
4479 if (p_mod == Parameter.Modifier.PARAMS) {
4480 if (chose_params_expanded) {
4481 params_initializers = new ArrayList (arg_count - a_idx);
4482 pt = TypeManager.GetElementType (pt);
4484 } else if (p_mod != 0) {
4485 pt = TypeManager.GetElementType (pt);
4490 // Types have to be identical when ref or out modifer is used
4492 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4493 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4496 if (!TypeManager.IsEqual (a.Expr.Type, pt))
4503 if (TypeManager.IsEqual (a.Type, pt)) {
4506 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4512 // Convert params arguments to an array initializer
4514 if (params_initializers != null) {
4515 params_initializers.Add (conv);
4516 arguments.RemoveAt (a_idx--);
4521 // Update the argument with the implicit conversion
4526 // Fill not provided arguments required by params modifier
4528 if (params_initializers == null && pd.HasParams && arg_count < pd.Count && a_idx + 1 == pd.Count) {
4529 if (arguments == null)
4530 arguments = new ArrayList (1);
4532 pt = pd.Types [GetApplicableParametersCount (method, pd) - 1];
4533 pt = TypeManager.GetElementType (pt);
4534 params_initializers = new ArrayList (0);
4537 if (a_idx == arg_count) {
4539 // Append an array argument with all params arguments
4541 if (params_initializers != null) {
4542 arguments.Add (new Argument (
4543 new ArrayCreation (new TypeExpression (pt, loc), "[]",
4544 params_initializers, loc).Resolve (ec)));
4549 if (!may_fail && Report.Errors == errors) {
4550 if (CustomErrorHandler != null)
4551 CustomErrorHandler.NoExactMatch (ec, best_candidate);
4553 Error_InvalidArguments (ec, loc, a_pos, method, a, pd, pt);
4559 public class ConstantExpr : MemberExpr
4563 public ConstantExpr (FieldInfo constant, Location loc)
4565 this.constant = constant;
4569 public override string Name {
4570 get { throw new NotImplementedException (); }
4573 public override bool IsInstance {
4574 get { return !IsStatic; }
4577 public override bool IsStatic {
4578 get { return constant.IsStatic; }
4581 public override Type DeclaringType {
4582 get { return constant.DeclaringType; }
4585 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc, SimpleName original)
4587 constant = TypeManager.GetGenericFieldDefinition (constant);
4589 IConstant ic = TypeManager.GetConstant (constant);
4591 if (constant.IsLiteral) {
4592 ic = new ExternalConstant (constant);
4594 ic = ExternalConstant.CreateDecimal (constant);
4595 // HACK: decimal field was not resolved as constant
4597 return new FieldExpr (constant, loc).ResolveMemberAccess (ec, left, loc, original);
4599 TypeManager.RegisterConstant (constant, ic);
4602 return base.ResolveMemberAccess (ec, left, loc, original);
4605 public override Expression CreateExpressionTree (EmitContext ec)
4607 throw new NotSupportedException ();
4610 public override Expression DoResolve (EmitContext ec)
4612 IConstant ic = TypeManager.GetConstant (constant);
4613 if (ic.ResolveValue ()) {
4614 if (!ec.IsInObsoleteScope)
4615 ic.CheckObsoleteness (loc);
4618 return ic.CreateConstantReference (loc);
4621 public override void Emit (EmitContext ec)
4623 throw new NotSupportedException ();
4626 public override string GetSignatureForError ()
4628 return TypeManager.GetFullNameSignature (constant);
4633 /// Fully resolved expression that evaluates to a Field
4635 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariable {
4636 public readonly FieldInfo FieldInfo;
4637 VariableInfo variable_info;
4639 LocalTemporary temp;
4641 bool in_initializer;
4643 public FieldExpr (FieldInfo fi, Location l, bool in_initializer):
4646 this.in_initializer = in_initializer;
4649 public FieldExpr (FieldInfo fi, Location l)
4652 eclass = ExprClass.Variable;
4653 type = TypeManager.TypeToCoreType (fi.FieldType);
4657 public override string Name {
4659 return FieldInfo.Name;
4663 public override bool IsInstance {
4665 return !FieldInfo.IsStatic;
4669 public override bool IsStatic {
4671 return FieldInfo.IsStatic;
4675 public override Type DeclaringType {
4677 return FieldInfo.DeclaringType;
4681 public override string GetSignatureForError ()
4683 return TypeManager.GetFullNameSignature (FieldInfo);
4686 public VariableInfo VariableInfo {
4688 return variable_info;
4692 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
4693 SimpleName original)
4695 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
4696 Type t = fi.FieldType;
4698 if (t.IsPointer && !ec.InUnsafe) {
4702 return base.ResolveMemberAccess (ec, left, loc, original);
4705 public override Expression CreateExpressionTree (EmitContext ec)
4707 Expression instance;
4708 if (InstanceExpression == null) {
4709 instance = new NullLiteral (loc);
4711 instance = InstanceExpression.CreateExpressionTree (ec);
4714 ArrayList args = new ArrayList (2);
4715 args.Add (new Argument (instance));
4716 args.Add (new Argument (CreateTypeOfExpression ()));
4717 return CreateExpressionFactoryCall ("Field", args);
4720 public Expression CreateTypeOfExpression ()
4722 return new TypeOfField (FieldInfo, loc);
4725 override public Expression DoResolve (EmitContext ec)
4727 return DoResolve (ec, false, false);
4730 Expression DoResolve (EmitContext ec, bool lvalue_instance, bool out_access)
4732 if (!FieldInfo.IsStatic){
4733 if (InstanceExpression == null){
4735 // This can happen when referencing an instance field using
4736 // a fully qualified type expression: TypeName.InstanceField = xxx
4738 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4742 // Resolve the field's instance expression while flow analysis is turned
4743 // off: when accessing a field "a.b", we must check whether the field
4744 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4746 if (lvalue_instance) {
4747 using (ec.With (EmitContext.Flags.DoFlowAnalysis, false)) {
4748 Expression right_side =
4749 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4750 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side, loc);
4753 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
4754 InstanceExpression = InstanceExpression.Resolve (ec, rf);
4757 if (InstanceExpression == null)
4760 using (ec.Set (EmitContext.Flags.OmitStructFlowAnalysis)) {
4761 InstanceExpression.CheckMarshalByRefAccess (ec);
4765 if (!in_initializer && !ec.IsInFieldInitializer) {
4766 ObsoleteAttribute oa;
4767 FieldBase f = TypeManager.GetField (FieldInfo);
4769 if (!ec.IsInObsoleteScope)
4770 f.CheckObsoleteness (loc);
4772 // To be sure that type is external because we do not register generated fields
4773 } else if (!(FieldInfo.DeclaringType is TypeBuilder)) {
4774 oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
4776 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
4780 AnonymousContainer am = ec.CurrentAnonymousMethod;
4782 if (!FieldInfo.IsStatic){
4783 if (!am.IsIterator && (ec.TypeContainer is Struct)){
4784 Report.Error (1673, loc,
4785 "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",
4792 IFixedBuffer fb = AttributeTester.GetFixedBuffer (FieldInfo);
4794 if (!ec.InFixedInitializer && ec.ContainerType.IsValueType) {
4795 Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4798 if (InstanceExpression.eclass != ExprClass.Variable) {
4799 Report.SymbolRelatedToPreviousError (FieldInfo);
4800 Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4801 TypeManager.GetFullNameSignature (FieldInfo));
4804 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4807 // If the instance expression is a local variable or parameter.
4808 IVariable var = InstanceExpression as IVariable;
4809 if ((var == null) || (var.VariableInfo == null))
4812 VariableInfo vi = var.VariableInfo;
4813 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
4816 variable_info = vi.GetSubStruct (FieldInfo.Name);
4820 static readonly int [] codes = {
4821 191, // instance, write access
4822 192, // instance, out access
4823 198, // static, write access
4824 199, // static, out access
4825 1648, // member of value instance, write access
4826 1649, // member of value instance, out access
4827 1650, // member of value static, write access
4828 1651 // member of value static, out access
4831 static readonly string [] msgs = {
4832 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4833 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4834 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4835 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4836 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4837 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4838 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4839 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4842 // The return value is always null. Returning a value simplifies calling code.
4843 Expression Report_AssignToReadonly (Expression right_side)
4846 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4850 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4852 Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4857 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4859 IVariable var = InstanceExpression as IVariable;
4860 if ((var != null) && (var.VariableInfo != null))
4861 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
4863 bool lvalue_instance = !FieldInfo.IsStatic && FieldInfo.DeclaringType.IsValueType;
4864 bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
4866 Expression e = DoResolve (ec, lvalue_instance, out_access);
4871 FieldBase fb = TypeManager.GetField (FieldInfo);
4875 if (FieldInfo.IsInitOnly) {
4876 // InitOnly fields can only be assigned in constructors or initializers
4877 if (!ec.IsInFieldInitializer && !ec.IsConstructor)
4878 return Report_AssignToReadonly (right_side);
4880 if (ec.IsConstructor) {
4881 Type ctype = ec.TypeContainer.CurrentType;
4883 ctype = ec.ContainerType;
4885 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4886 if (!TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
4887 return Report_AssignToReadonly (right_side);
4888 // static InitOnly fields cannot be assigned-to in an instance constructor
4889 if (IsStatic && !ec.IsStatic)
4890 return Report_AssignToReadonly (right_side);
4891 // instance constructors can't modify InitOnly fields of other instances of the same type
4892 if (!IsStatic && !(InstanceExpression is This))
4893 return Report_AssignToReadonly (right_side);
4897 if (right_side == EmptyExpression.OutAccess &&
4898 !IsStatic && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type)) {
4899 Report.SymbolRelatedToPreviousError (DeclaringType);
4900 Report.Warning (197, 1, loc,
4901 "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",
4902 GetSignatureForError ());
4908 public override void CheckMarshalByRefAccess (EmitContext ec)
4910 if (!IsStatic && Type.IsValueType && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type)) {
4911 Report.SymbolRelatedToPreviousError (DeclaringType);
4912 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",
4913 GetSignatureForError ());
4917 public bool VerifyFixed ()
4919 IVariable variable = InstanceExpression as IVariable;
4920 // A variable of the form V.I is fixed when V is a fixed variable of a struct type.
4921 // We defer the InstanceExpression check after the variable check to avoid a
4922 // separate null check on InstanceExpression.
4923 return variable != null && InstanceExpression.Type.IsValueType && variable.VerifyFixed ();
4926 public override int GetHashCode ()
4928 return FieldInfo.GetHashCode ();
4931 public override bool Equals (object obj)
4933 FieldExpr fe = obj as FieldExpr;
4937 if (FieldInfo != fe.FieldInfo)
4940 if (InstanceExpression == null || fe.InstanceExpression == null)
4943 return InstanceExpression.Equals (fe.InstanceExpression);
4946 public void Emit (EmitContext ec, bool leave_copy)
4948 ILGenerator ig = ec.ig;
4949 bool is_volatile = false;
4951 FieldBase f = TypeManager.GetField (FieldInfo);
4953 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4956 f.SetMemberIsUsed ();
4959 if (FieldInfo.IsStatic){
4961 ig.Emit (OpCodes.Volatile);
4963 ig.Emit (OpCodes.Ldsfld, FieldInfo);
4966 EmitInstance (ec, false);
4968 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
4970 ig.Emit (OpCodes.Ldflda, FieldInfo);
4971 ig.Emit (OpCodes.Ldflda, ff.Element);
4974 ig.Emit (OpCodes.Volatile);
4976 ig.Emit (OpCodes.Ldfld, FieldInfo);
4981 ec.ig.Emit (OpCodes.Dup);
4982 if (!FieldInfo.IsStatic) {
4983 temp = new LocalTemporary (this.Type);
4989 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4991 FieldAttributes fa = FieldInfo.Attributes;
4992 bool is_static = (fa & FieldAttributes.Static) != 0;
4993 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
4994 ILGenerator ig = ec.ig;
4996 if (is_readonly && !ec.IsConstructor){
4997 Report_AssignToReadonly (source);
5002 // String concatenation creates a new string instance
5004 prepared = prepare_for_load && !(source is StringConcat);
5005 EmitInstance (ec, prepared);
5009 ec.ig.Emit (OpCodes.Dup);
5010 if (!FieldInfo.IsStatic) {
5011 temp = new LocalTemporary (this.Type);
5016 FieldBase f = TypeManager.GetField (FieldInfo);
5018 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
5019 ig.Emit (OpCodes.Volatile);
5025 ig.Emit (OpCodes.Stsfld, FieldInfo);
5027 ig.Emit (OpCodes.Stfld, FieldInfo);
5035 public override void Emit (EmitContext ec)
5040 public void AddressOf (EmitContext ec, AddressOp mode)
5042 ILGenerator ig = ec.ig;
5044 FieldBase f = TypeManager.GetField (FieldInfo);
5046 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
5047 Report.Warning (420, 1, loc, "`{0}': A volatile field references will not be treated as volatile",
5048 f.GetSignatureForError ());
5051 if ((mode & AddressOp.Store) != 0)
5053 if ((mode & AddressOp.Load) != 0)
5054 f.SetMemberIsUsed ();
5058 // Handle initonly fields specially: make a copy and then
5059 // get the address of the copy.
5062 if (FieldInfo.IsInitOnly){
5064 if (ec.IsConstructor){
5065 if (FieldInfo.IsStatic){
5077 local = ig.DeclareLocal (type);
5078 ig.Emit (OpCodes.Stloc, local);
5079 ig.Emit (OpCodes.Ldloca, local);
5084 if (FieldInfo.IsStatic){
5085 ig.Emit (OpCodes.Ldsflda, FieldInfo);
5088 EmitInstance (ec, false);
5089 ig.Emit (OpCodes.Ldflda, FieldInfo);
5096 /// Expression that evaluates to a Property. The Assign class
5097 /// might set the `Value' expression if we are in an assignment.
5099 /// This is not an LValue because we need to re-write the expression, we
5100 /// can not take data from the stack and store it.
5102 public class PropertyExpr : MemberExpr, IAssignMethod {
5103 public readonly PropertyInfo PropertyInfo;
5104 MethodInfo getter, setter;
5109 LocalTemporary temp;
5112 public PropertyExpr (Type container_type, PropertyInfo pi, Location l)
5115 eclass = ExprClass.PropertyAccess;
5119 type = TypeManager.TypeToCoreType (pi.PropertyType);
5121 ResolveAccessors (container_type);
5124 public override string Name {
5126 return PropertyInfo.Name;
5130 public override bool IsInstance {
5136 public override bool IsStatic {
5142 public override Expression CreateExpressionTree (EmitContext ec)
5144 if (IsSingleDimensionalArrayLength ()) {
5145 ArrayList args = new ArrayList (1);
5146 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5147 return CreateExpressionFactoryCall ("ArrayLength", args);
5150 // TODO: it's waiting for PropertyExpr refactoring
5151 //ArrayList args = new ArrayList (2);
5152 //args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5153 //args.Add (getter expression);
5154 //return CreateExpressionFactoryCall ("Property", args);
5155 return base.CreateExpressionTree (ec);
5158 public Expression CreateSetterTypeOfExpression ()
5160 return new Cast (new TypeExpression (typeof (MethodInfo), loc), new TypeOfMethod (setter, loc));
5163 public override Type DeclaringType {
5165 return PropertyInfo.DeclaringType;
5169 public override string GetSignatureForError ()
5171 return TypeManager.GetFullNameSignature (PropertyInfo);
5174 void FindAccessors (Type invocation_type)
5176 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
5177 BindingFlags.Static | BindingFlags.Instance |
5178 BindingFlags.DeclaredOnly;
5180 Type current = PropertyInfo.DeclaringType;
5181 for (; current != null; current = current.BaseType) {
5182 MemberInfo[] group = TypeManager.MemberLookup (
5183 invocation_type, invocation_type, current,
5184 MemberTypes.Property, flags, PropertyInfo.Name, null);
5189 if (group.Length != 1)
5190 // Oooops, can this ever happen ?
5193 PropertyInfo pi = (PropertyInfo) group [0];
5196 getter = pi.GetGetMethod (true);
5199 setter = pi.GetSetMethod (true);
5201 MethodInfo accessor = getter != null ? getter : setter;
5203 if (!accessor.IsVirtual)
5209 // We also perform the permission checking here, as the PropertyInfo does not
5210 // hold the information for the accessibility of its setter/getter
5212 // TODO: Refactor to use some kind of cache together with GetPropertyFromAccessor
5213 void ResolveAccessors (Type container_type)
5215 FindAccessors (container_type);
5217 if (getter != null) {
5218 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
5219 IMethodData md = TypeManager.GetMethod (the_getter);
5221 md.SetMemberIsUsed ();
5223 is_static = getter.IsStatic;
5226 if (setter != null) {
5227 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
5228 IMethodData md = TypeManager.GetMethod (the_setter);
5230 md.SetMemberIsUsed ();
5232 is_static = setter.IsStatic;
5236 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
5239 InstanceExpression = null;
5243 if (InstanceExpression == null) {
5244 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5248 InstanceExpression = InstanceExpression.DoResolve (ec);
5249 if (lvalue_instance && InstanceExpression != null)
5250 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
5252 if (InstanceExpression == null)
5255 InstanceExpression.CheckMarshalByRefAccess (ec);
5257 if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) &&
5258 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
5259 !TypeManager.IsNestedChildOf (ec.ContainerType, InstanceExpression.Type) &&
5260 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.ContainerType)) {
5261 Report.SymbolRelatedToPreviousError (PropertyInfo);
5262 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
5269 void Error_PropertyNotFound (MethodInfo mi, bool getter)
5271 // TODO: correctly we should compare arguments but it will lead to bigger changes
5272 if (mi is MethodBuilder) {
5273 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
5277 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
5279 ParameterData iparams = TypeManager.GetParameterData (mi);
5280 sig.Append (getter ? "get_" : "set_");
5282 sig.Append (iparams.GetSignatureForError ());
5284 Report.SymbolRelatedToPreviousError (mi);
5285 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
5286 Name, sig.ToString ());
5289 public bool IsAccessibleFrom (Type invocation_type, bool lvalue)
5292 MethodInfo accessor = lvalue ? setter : getter;
5293 if (accessor == null && lvalue)
5295 return accessor != null && IsAccessorAccessible (invocation_type, accessor, out dummy);
5298 bool IsSingleDimensionalArrayLength ()
5300 if (DeclaringType != TypeManager.array_type || getter == null || Name != "Length")
5303 string t_name = InstanceExpression.Type.Name;
5304 int t_name_len = t_name.Length;
5305 return t_name_len > 2 && t_name [t_name_len - 2] == '[' && t_name [t_name_len - 3] != ']';
5308 override public Expression DoResolve (EmitContext ec)
5313 if (getter != null){
5314 if (TypeManager.GetParameterData (getter).Count != 0){
5315 Error_PropertyNotFound (getter, true);
5320 if (getter == null){
5322 // The following condition happens if the PropertyExpr was
5323 // created, but is invalid (ie, the property is inaccessible),
5324 // and we did not want to embed the knowledge about this in
5325 // the caller routine. This only avoids double error reporting.
5330 if (InstanceExpression != EmptyExpression.Null) {
5331 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5332 TypeManager.GetFullNameSignature (PropertyInfo));
5337 bool must_do_cs1540_check = false;
5338 if (getter != null &&
5339 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
5340 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
5341 if (pm != null && pm.HasCustomAccessModifier) {
5342 Report.SymbolRelatedToPreviousError (pm);
5343 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5344 TypeManager.CSharpSignature (getter));
5347 Report.SymbolRelatedToPreviousError (getter);
5348 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
5353 if (!InstanceResolve (ec, false, must_do_cs1540_check))
5357 // Only base will allow this invocation to happen.
5359 if (IsBase && getter.IsAbstract) {
5360 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5364 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
5374 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
5376 if (right_side == EmptyExpression.OutAccess) {
5377 if (ec.CurrentBlock.Toplevel.GetTransparentIdentifier (PropertyInfo.Name) != null) {
5378 Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5381 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as `ref' or `out' parameter",
5382 GetSignatureForError ());
5387 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5388 Error_CannotModifyIntermediateExpressionValue (ec);
5391 if (setter == null){
5393 // The following condition happens if the PropertyExpr was
5394 // created, but is invalid (ie, the property is inaccessible),
5395 // and we did not want to embed the knowledge about this in
5396 // the caller routine. This only avoids double error reporting.
5400 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
5401 GetSignatureForError ());
5405 if (TypeManager.GetParameterData (setter).Count != 1){
5406 Error_PropertyNotFound (setter, false);
5410 bool must_do_cs1540_check;
5411 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
5412 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
5413 if (pm != null && pm.HasCustomAccessModifier) {
5414 Report.SymbolRelatedToPreviousError (pm);
5415 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5416 TypeManager.CSharpSignature (setter));
5419 Report.SymbolRelatedToPreviousError (setter);
5420 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
5425 if (!InstanceResolve (ec, PropertyInfo.DeclaringType.IsValueType, must_do_cs1540_check))
5429 // Only base will allow this invocation to happen.
5431 if (IsBase && setter.IsAbstract){
5432 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5439 public override void Emit (EmitContext ec)
5444 public void Emit (EmitContext ec, bool leave_copy)
5447 // Special case: length of single dimension array property is turned into ldlen
5449 if (IsSingleDimensionalArrayLength ()) {
5451 EmitInstance (ec, false);
5452 ec.ig.Emit (OpCodes.Ldlen);
5453 ec.ig.Emit (OpCodes.Conv_I4);
5457 Invocation.EmitCall (ec, IsBase, InstanceExpression, getter, null, loc, prepared, false);
5460 ec.ig.Emit (OpCodes.Dup);
5462 temp = new LocalTemporary (this.Type);
5469 // Implements the IAssignMethod interface for assignments
5471 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5473 Expression my_source = source;
5475 if (prepare_for_load) {
5476 if (source is StringConcat)
5477 EmitInstance (ec, false);
5485 ec.ig.Emit (OpCodes.Dup);
5487 temp = new LocalTemporary (this.Type);
5491 } else if (leave_copy) {
5493 temp = new LocalTemporary (this.Type);
5498 ArrayList args = new ArrayList (1);
5499 args.Add (new Argument (my_source, Argument.AType.Expression));
5501 Invocation.EmitCall (ec, IsBase, InstanceExpression, setter, args, loc, false, prepared);
5511 /// Fully resolved expression that evaluates to an Event
5513 public class EventExpr : MemberExpr {
5514 public readonly EventInfo EventInfo;
5517 MethodInfo add_accessor, remove_accessor;
5519 public EventExpr (EventInfo ei, Location loc)
5523 eclass = ExprClass.EventAccess;
5525 add_accessor = TypeManager.GetAddMethod (ei);
5526 remove_accessor = TypeManager.GetRemoveMethod (ei);
5527 if (add_accessor.IsStatic || remove_accessor.IsStatic)
5530 if (EventInfo is MyEventBuilder){
5531 MyEventBuilder eb = (MyEventBuilder) EventInfo;
5532 type = eb.EventType;
5535 type = EventInfo.EventHandlerType;
5538 public override string Name {
5540 return EventInfo.Name;
5544 public override bool IsInstance {
5550 public override bool IsStatic {
5556 public override Type DeclaringType {
5558 return EventInfo.DeclaringType;
5562 void Error_AssignmentEventOnly ()
5564 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5565 GetSignatureForError ());
5568 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
5569 SimpleName original)
5572 // If the event is local to this class, we transform ourselves into a FieldExpr
5575 if (EventInfo.DeclaringType == ec.ContainerType ||
5576 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
5577 EventField mi = TypeManager.GetEventField (EventInfo);
5580 if (!ec.IsInObsoleteScope)
5581 mi.CheckObsoleteness (loc);
5583 if ((mi.ModFlags & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0 && !ec.IsInCompoundAssignment)
5584 Error_AssignmentEventOnly ();
5586 FieldExpr ml = new FieldExpr (mi.FieldBuilder, loc);
5588 InstanceExpression = null;
5590 return ml.ResolveMemberAccess (ec, left, loc, original);
5594 if (left is This && !ec.IsInCompoundAssignment)
5595 Error_AssignmentEventOnly ();
5597 return base.ResolveMemberAccess (ec, left, loc, original);
5601 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
5604 InstanceExpression = null;
5608 if (InstanceExpression == null) {
5609 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5613 InstanceExpression = InstanceExpression.DoResolve (ec);
5614 if (InstanceExpression == null)
5617 if (IsBase && add_accessor.IsAbstract) {
5618 Error_CannotCallAbstractBase(TypeManager.CSharpSignature(add_accessor));
5623 // This is using the same mechanism as the CS1540 check in PropertyExpr.
5624 // However, in the Event case, we reported a CS0122 instead.
5626 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
5627 InstanceExpression.Type != ec.ContainerType &&
5628 TypeManager.IsSubclassOf (ec.ContainerType, InstanceExpression.Type)) {
5629 Report.SymbolRelatedToPreviousError (EventInfo);
5630 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5637 public bool IsAccessibleFrom (Type invocation_type)
5640 return IsAccessorAccessible (invocation_type, add_accessor, out dummy) &&
5641 IsAccessorAccessible (invocation_type, remove_accessor, out dummy);
5644 public override Expression CreateExpressionTree (EmitContext ec)
5646 throw new NotSupportedException ();
5649 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5651 return DoResolve (ec);
5654 public override Expression DoResolve (EmitContext ec)
5656 bool must_do_cs1540_check;
5657 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
5658 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
5659 Report.SymbolRelatedToPreviousError (EventInfo);
5660 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5664 if (!InstanceResolve (ec, must_do_cs1540_check))
5670 public override void Emit (EmitContext ec)
5672 Report.Error (70, loc, "The event `{0}' can only appear on the left hand side of += or -= "+
5673 "(except on the defining type)", GetSignatureForError ());
5676 public override string GetSignatureForError ()
5678 return TypeManager.CSharpSignature (EventInfo);
5681 public void EmitAddOrRemove (EmitContext ec, Expression source)
5683 BinaryDelegate source_del = source as BinaryDelegate;
5684 if (source_del == null) {
5688 Expression handler = source_del.Right;
5690 Argument arg = new Argument (handler, Argument.AType.Expression);
5691 ArrayList args = new ArrayList ();
5695 if (source_del.IsAddition)
5696 Invocation.EmitCall (
5697 ec, IsBase, InstanceExpression, add_accessor, args, loc);
5699 Invocation.EmitCall (
5700 ec, IsBase, InstanceExpression, remove_accessor, args, loc);
5704 public class TemporaryVariable : Expression, IMemoryLocation
5709 public TemporaryVariable (Type type, Location loc)
5713 eclass = ExprClass.Value;
5716 public override Expression DoResolve (EmitContext ec)
5721 TypeExpr te = new TypeExpression (type, loc);
5722 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
5723 if (!li.Resolve (ec))
5726 if (ec.MustCaptureVariable (li)) {
5727 ScopeInfo scope = li.Block.CreateScopeInfo ();
5728 var = scope.AddLocal (li);
5735 public Variable Variable {
5736 get { return var != null ? var : li.Variable; }
5739 public override void Emit (EmitContext ec)
5741 Variable.EmitInstance (ec);
5745 public void EmitLoadAddress (EmitContext ec)
5747 Variable.EmitInstance (ec);
5748 Variable.EmitAddressOf (ec);
5751 public void Store (EmitContext ec, Expression right_side)
5753 Variable.EmitInstance (ec);
5754 right_side.Emit (ec);
5755 Variable.EmitAssign (ec);
5758 public void EmitThis (EmitContext ec)
5760 Variable.EmitInstance (ec);
5763 public void EmitStore (EmitContext ec)
5765 Variable.EmitAssign (ec);
5768 public void AddressOf (EmitContext ec, AddressOp mode)
5770 EmitLoadAddress (ec);
5775 /// Handles `var' contextual keyword; var becomes a keyword only
5776 /// if no type called var exists in a variable scope
5778 public class VarExpr : SimpleName
5780 // Used for error reporting only
5781 ArrayList initializer;
5783 public VarExpr (Location loc)
5788 public ArrayList VariableInitializer {
5790 this.initializer = value;
5794 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5797 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
5799 type = right_side.Type;
5800 if (type == TypeManager.null_type || type == TypeManager.void_type || type == TypeManager.anonymous_method_type) {
5801 Report.Error (815, loc, "An implicitly typed local variable declaration cannot be initialized with `{0}'",
5802 right_side.GetSignatureForError ());
5806 eclass = ExprClass.Variable;
5810 protected override void Error_TypeOrNamespaceNotFound (IResolveContext ec)
5812 Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");
5815 public override TypeExpr ResolveAsContextualType (IResolveContext rc, bool silent)
5817 TypeExpr te = base.ResolveAsContextualType (rc, true);
5821 if (initializer == null)
5824 if (initializer.Count > 1) {
5825 Location loc = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [1]).Location;
5826 Report.Error (819, loc, "An implicitly typed local variable declaration cannot include multiple declarators");
5831 Expression variable_initializer = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [0]).expression_or_array_initializer;
5832 if (variable_initializer == null) {
5833 Report.Error (818, loc, "An implicitly typed local variable declarator must include an initializer");