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 ec, bool silent)
237 // C# 3.0 introduced contextual keywords (var) which behaves like a type if type with
238 // same name exists or as a keyword when no type was found
240 public virtual TypeExpr ResolveAsContextualType (IResolveContext rc, bool silent)
242 return ResolveAsTypeTerminal (rc, silent);
246 // This is used to resolve the expression as a type, a null
247 // value will be returned if the expression is not a type
250 public virtual TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
252 TypeExpr te = ResolveAsBaseTerminal (ec, silent);
256 if (!silent) { // && !(te is TypeParameterExpr)) {
257 ObsoleteAttribute obsolete_attr = AttributeTester.GetObsoleteAttribute (te.Type);
258 if (obsolete_attr != null && !ec.IsInObsoleteScope) {
259 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location);
263 // Constrains don't need to be checked for overrides
264 GenericMethod gm = ec.GenericDeclContainer as GenericMethod;
265 if (gm != null && (gm.ModFlags & Modifiers.OVERRIDE) != 0) {
270 ConstructedType ct = te as ConstructedType;
271 if ((ct != null) && !ct.CheckConstraints (ec))
277 public TypeExpr ResolveAsBaseTerminal (IResolveContext ec, bool silent)
279 int errors = Report.Errors;
281 FullNamedExpression fne = ResolveAsTypeStep (ec, silent);
286 if (fne.eclass != ExprClass.Type) {
287 if (!silent && errors == Report.Errors)
288 fne.Error_UnexpectedKind (null, "type", loc);
292 TypeExpr te = fne as TypeExpr;
294 if (!te.CheckAccessLevel (ec.DeclContainer)) {
295 Report.SymbolRelatedToPreviousError (te.Type);
296 ErrorIsInaccesible (loc, TypeManager.CSharpName (te.Type));
304 public static void ErrorIsInaccesible (Location loc, string name)
306 Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", name);
309 protected static void Error_CannotAccessProtected (Location loc, MemberInfo m, Type qualifier, Type container)
311 Report.Error (1540, loc, "Cannot access protected member `{0}' via a qualifier of type `{1}'."
312 + " The qualifier must be of type `{2}' or derived from it",
313 TypeManager.GetFullNameSignature (m),
314 TypeManager.CSharpName (qualifier),
315 TypeManager.CSharpName (container));
319 public static void Error_InvalidExpressionStatement (Location loc)
321 Report.Error (201, loc, "Only assignment, call, increment, decrement, and new object " +
322 "expressions can be used as a statement");
325 public void Error_InvalidExpressionStatement ()
327 Error_InvalidExpressionStatement (loc);
330 protected void Error_CannotAssign (string to, string roContext)
332 Report.Error (1656, loc, "Cannot assign to `{0}' because it is a `{1}'",
336 public static void Error_VoidInvalidInTheContext (Location loc)
338 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
341 public virtual void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl)
343 // The error was already reported as CS1660
344 if (type == TypeManager.anonymous_method_type)
347 if (TypeManager.IsGenericParameter (Type) && TypeManager.IsGenericParameter (target) && type.Name == target.Name) {
349 string sig1 = type.DeclaringMethod == null ?
350 TypeManager.CSharpName (type.DeclaringType) :
351 TypeManager.CSharpSignature (type.DeclaringMethod);
352 string sig2 = target.DeclaringMethod == null ?
353 TypeManager.CSharpName (target.DeclaringType) :
354 TypeManager.CSharpSignature (target.DeclaringMethod);
355 Report.ExtraInformation (loc,
357 "The generic parameter `{0}' of `{1}' cannot be converted to the generic parameter `{0}' of `{2}' (in the previous ",
358 Type.Name, sig1, sig2));
360 } else if (Type.FullName == target.FullName){
361 Report.ExtraInformation (loc,
363 "The type `{0}' has two conflicting definitions, one comes from `{1}' and the other from `{2}' (in the previous ",
364 Type.FullName, Type.Assembly.FullName, target.Assembly.FullName));
368 Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
369 TypeManager.CSharpName (type), TypeManager.CSharpName (target));
373 Expression e = (this is EnumConstant) ? ((EnumConstant)this).Child : this;
374 bool b = Convert.ExplicitNumericConversion (e, target) != null;
377 Convert.ExplicitReferenceConversionExists (Type, target) ||
378 Convert.ExplicitUnsafe (e, target) != null ||
379 (ec != null && Convert.UserDefinedConversion (ec, this, target, Location.Null, true) != null))
381 Report.Error (266, loc, "Cannot implicitly convert type `{0}' to `{1}'. " +
382 "An explicit conversion exists (are you missing a cast?)",
383 TypeManager.CSharpName (Type), TypeManager.CSharpName (target));
387 if (Type != TypeManager.string_type && this is Constant && !(this is EmptyConstantCast)) {
388 Report.Error (31, loc, "Constant value `{0}' cannot be converted to a `{1}'",
389 ((Constant)(this)).GetValue ().ToString (), TypeManager.CSharpName (target));
393 Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
394 TypeManager.CSharpName (type),
395 TypeManager.CSharpName (target));
398 protected void Error_VariableIsUsedBeforeItIsDeclared (string name)
400 Report.Error (841, loc, "The variable `{0}' cannot be used before it is declared",
404 protected virtual void Error_TypeDoesNotContainDefinition (Type type, string name)
406 Error_TypeDoesNotContainDefinition (loc, type, name);
409 public static void Error_TypeDoesNotContainDefinition (Location loc, Type type, string name)
411 Report.SymbolRelatedToPreviousError (type);
412 Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
413 TypeManager.CSharpName (type), name);
416 protected static void Error_ValueAssignment (Location loc)
418 Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
421 ResolveFlags ExprClassToResolveFlags
426 case ExprClass.Namespace:
427 return ResolveFlags.Type;
429 case ExprClass.MethodGroup:
430 return ResolveFlags.MethodGroup;
432 case ExprClass.Value:
433 case ExprClass.Variable:
434 case ExprClass.PropertyAccess:
435 case ExprClass.EventAccess:
436 case ExprClass.IndexerAccess:
437 return ResolveFlags.VariableOrValue;
440 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
446 /// Resolves an expression and performs semantic analysis on it.
450 /// Currently Resolve wraps DoResolve to perform sanity
451 /// checking and assertion checking on what we expect from Resolve.
453 public Expression Resolve (EmitContext ec, ResolveFlags flags)
455 if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type)
456 return ResolveAsTypeStep (ec, false);
458 bool do_flow_analysis = ec.DoFlowAnalysis;
459 bool omit_struct_analysis = ec.OmitStructFlowAnalysis;
460 if ((flags & ResolveFlags.DisableFlowAnalysis) != 0)
461 do_flow_analysis = false;
462 if ((flags & ResolveFlags.DisableStructFlowAnalysis) != 0)
463 omit_struct_analysis = true;
466 using (ec.WithFlowAnalysis (do_flow_analysis, omit_struct_analysis)) {
467 if (this is SimpleName) {
468 bool intermediate = (flags & ResolveFlags.Intermediate) == ResolveFlags.Intermediate;
469 e = ((SimpleName) this).DoResolve (ec, intermediate);
478 if ((flags & e.ExprClassToResolveFlags) == 0) {
479 e.Error_UnexpectedKind (flags, loc);
483 if (e.type == null && !(e is Namespace)) {
484 throw new Exception (
485 "Expression " + e.GetType () +
486 " did not set its type after Resolve\n" +
487 "called from: " + this.GetType ());
494 /// Resolves an expression and performs semantic analysis on it.
496 public Expression Resolve (EmitContext ec)
498 Expression e = Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
500 if (e != null && e.eclass == ExprClass.MethodGroup && RootContext.Version == LanguageVersion.ISO_1) {
501 ((MethodGroupExpr) e).ReportUsageError ();
507 public Constant ResolveAsConstant (EmitContext ec, MemberCore mc)
509 Expression e = Resolve (ec);
513 Constant c = e as Constant;
517 Const.Error_ExpressionMustBeConstant (loc, mc.GetSignatureForError ());
522 /// Resolves an expression for LValue assignment
526 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
527 /// checking and assertion checking on what we expect from Resolve
529 public Expression ResolveLValue (EmitContext ec, Expression right_side, Location loc)
531 int errors = Report.Errors;
532 bool out_access = right_side == EmptyExpression.OutAccess;
534 Expression e = DoResolveLValue (ec, right_side);
536 if (e != null && out_access && !(e is IMemoryLocation)) {
537 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
538 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
540 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
541 // e.GetType () + " " + e.GetSignatureForError ());
546 if (errors == Report.Errors) {
548 Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
550 Error_ValueAssignment (loc);
555 if (e.eclass == ExprClass.Invalid)
556 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
558 if (e.eclass == ExprClass.MethodGroup) {
559 ((MethodGroupExpr) e).ReportUsageError ();
563 if ((e.type == null) && !(e is ConstructedType))
564 throw new Exception ("Expression " + e + " did not set its type after Resolve");
570 /// Emits the code for the expression
574 /// The Emit method is invoked to generate the code
575 /// for the expression.
577 public abstract void Emit (EmitContext ec);
579 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
582 ec.ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
586 /// Protected constructor. Only derivate types should
587 /// be able to be created
590 protected Expression ()
592 eclass = ExprClass.Invalid;
597 /// Returns a fully formed expression after a MemberLookup
600 public static Expression ExprClassFromMemberInfo (Type container_type, MemberInfo mi, Location loc)
603 return new EventExpr ((EventInfo) mi, loc);
604 else if (mi is FieldInfo) {
605 FieldInfo fi = (FieldInfo) mi;
606 if (fi.IsLiteral || (fi.IsInitOnly && fi.FieldType == TypeManager.decimal_type))
607 return new ConstantExpr (fi, loc);
608 return new FieldExpr (fi, loc);
609 } else if (mi is PropertyInfo)
610 return new PropertyExpr (container_type, (PropertyInfo) mi, loc);
611 else if (mi is Type) {
612 return new TypeExpression ((System.Type) mi, loc);
618 protected static ArrayList almost_matched_members = new ArrayList (4);
621 // FIXME: Probably implement a cache for (t,name,current_access_set)?
623 // This code could use some optimizations, but we need to do some
624 // measurements. For example, we could use a delegate to `flag' when
625 // something can not any longer be a method-group (because it is something
629 // If the return value is an Array, then it is an array of
632 // If the return value is an MemberInfo, it is anything, but a Method
636 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
637 // the arguments here and have MemberLookup return only the methods that
638 // match the argument count/type, unlike we are doing now (we delay this
641 // This is so we can catch correctly attempts to invoke instance methods
642 // from a static body (scan for error 120 in ResolveSimpleName).
645 // FIXME: Potential optimization, have a static ArrayList
648 public static Expression MemberLookup (Type container_type, Type queried_type, string name,
649 MemberTypes mt, BindingFlags bf, Location loc)
651 return MemberLookup (container_type, null, queried_type, name, mt, bf, loc);
655 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
656 // `qualifier_type' or null to lookup members in the current class.
659 public static Expression MemberLookup (Type container_type,
660 Type qualifier_type, Type queried_type,
661 string name, MemberTypes mt,
662 BindingFlags bf, Location loc)
664 almost_matched_members.Clear ();
666 MemberInfo [] mi = TypeManager.MemberLookup (container_type, qualifier_type,
667 queried_type, mt, bf, name, almost_matched_members);
673 bool is_interface = qualifier_type != null && qualifier_type.IsInterface;
674 ArrayList methods = new ArrayList (2);
675 ArrayList non_methods = null;
677 foreach (MemberInfo m in mi) {
678 if (m is MethodBase) {
683 if (non_methods == null) {
684 non_methods = new ArrayList (2);
689 foreach (MemberInfo n_m in non_methods) {
690 if (m.DeclaringType.IsInterface && TypeManager.ImplementsInterface (m.DeclaringType, n_m.DeclaringType))
693 Report.SymbolRelatedToPreviousError (m);
694 Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
695 TypeManager.GetFullNameSignature (m), TypeManager.GetFullNameSignature (n_m));
700 if (methods.Count == 0)
701 return ExprClassFromMemberInfo (container_type, (MemberInfo)non_methods [0], loc);
703 if (non_methods != null) {
704 MethodBase method = (MethodBase) methods [0];
705 MemberInfo non_method = (MemberInfo) non_methods [0];
706 if (method.DeclaringType == non_method.DeclaringType) {
707 // Cannot happen with C# code, but is valid in IL
708 Report.SymbolRelatedToPreviousError (method);
709 Report.SymbolRelatedToPreviousError (non_method);
710 Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
711 TypeManager.GetFullNameSignature (non_method),
712 TypeManager.CSharpSignature (method));
717 Report.SymbolRelatedToPreviousError (method);
718 Report.SymbolRelatedToPreviousError (non_method);
719 Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and non-method `{1}'. Using method `{0}'",
720 TypeManager.CSharpSignature (method), TypeManager.GetFullNameSignature (non_method));
724 return new MethodGroupExpr (methods, queried_type, loc);
727 if (mi [0] is MethodBase)
728 return new MethodGroupExpr (mi, queried_type, loc);
730 return ExprClassFromMemberInfo (container_type, mi [0], loc);
733 public const MemberTypes AllMemberTypes =
734 MemberTypes.Constructor |
738 MemberTypes.NestedType |
739 MemberTypes.Property;
741 public const BindingFlags AllBindingFlags =
742 BindingFlags.Public |
743 BindingFlags.Static |
744 BindingFlags.Instance;
746 public static Expression MemberLookup (Type container_type, Type queried_type,
747 string name, Location loc)
749 return MemberLookup (container_type, null, queried_type, name,
750 AllMemberTypes, AllBindingFlags, loc);
753 public static Expression MemberLookup (Type container_type, Type qualifier_type,
754 Type queried_type, string name, Location loc)
756 return MemberLookup (container_type, qualifier_type, queried_type,
757 name, AllMemberTypes, AllBindingFlags, loc);
760 public static MethodGroupExpr MethodLookup (Type container_type, Type queried_type,
761 string name, Location loc)
763 return (MethodGroupExpr)MemberLookup (container_type, null, queried_type, name,
764 MemberTypes.Method, AllBindingFlags, loc);
768 /// This is a wrapper for MemberLookup that is not used to "probe", but
769 /// to find a final definition. If the final definition is not found, we
770 /// look for private members and display a useful debugging message if we
773 protected Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
774 Type queried_type, string name,
775 MemberTypes mt, BindingFlags bf,
780 int errors = Report.Errors;
782 e = MemberLookup (ec.ContainerType, qualifier_type, queried_type, name, mt, bf, loc);
784 if (e != null || errors != Report.Errors)
787 // No errors were reported by MemberLookup, but there was an error.
788 return Error_MemberLookupFailed (ec.ContainerType, qualifier_type, queried_type,
792 protected virtual Expression Error_MemberLookupFailed (Type container_type, Type qualifier_type,
793 Type queried_type, string name, string class_name,
794 MemberTypes mt, BindingFlags bf)
796 if (almost_matched_members.Count != 0) {
797 for (int i = 0; i < almost_matched_members.Count; ++i) {
798 MemberInfo m = (MemberInfo) almost_matched_members [i];
799 for (int j = 0; j < i; ++j) {
800 if (m == almost_matched_members [j]) {
808 Type declaring_type = m.DeclaringType;
810 Report.SymbolRelatedToPreviousError (m);
811 if (qualifier_type == null) {
812 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
813 TypeManager.CSharpName (m.DeclaringType),
814 TypeManager.CSharpName (container_type));
816 } else if (qualifier_type != container_type &&
817 TypeManager.IsNestedFamilyAccessible (container_type, declaring_type)) {
818 // Although a derived class can access protected members of
819 // its base class it cannot do so through an instance of the
820 // base class (CS1540). If the qualifier_type is a base of the
821 // ec.ContainerType and the lookup succeeds with the latter one,
822 // then we are in this situation.
823 Error_CannotAccessProtected (loc, m, qualifier_type, container_type);
825 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (m));
828 almost_matched_members.Clear ();
832 MemberInfo[] lookup = null;
833 if (queried_type == null) {
834 class_name = "global::";
836 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
837 mt, (bf & ~BindingFlags.Public) | BindingFlags.NonPublic,
840 if (lookup != null) {
841 Report.SymbolRelatedToPreviousError (lookup [0]);
842 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (lookup [0]));
843 return Error_MemberLookupFailed (lookup);
846 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
847 AllMemberTypes, AllBindingFlags | BindingFlags.NonPublic,
851 if (lookup == null) {
852 if (class_name != null) {
853 Report.Error (103, loc, "The name `{0}' does not exist in the current context",
856 Error_TypeDoesNotContainDefinition (queried_type, name);
861 if (TypeManager.MemberLookup (queried_type, null, queried_type,
862 AllMemberTypes, AllBindingFlags |
863 BindingFlags.NonPublic, name, null) == null) {
864 if ((lookup.Length == 1) && (lookup [0] is Type)) {
865 Type t = (Type) lookup [0];
867 Report.Error (305, loc,
868 "Using the generic type `{0}' " +
869 "requires {1} type arguments",
870 TypeManager.CSharpName (t),
871 TypeManager.GetNumberOfTypeArguments (t).ToString ());
876 return Error_MemberLookupFailed (lookup);
879 protected virtual Expression Error_MemberLookupFailed (MemberInfo[] members)
881 for (int i = 0; i < members.Length; ++i) {
882 if (!(members [i] is MethodBase))
886 // By default propagate the closest candidates upwards
887 return new MethodGroupExpr (members, type, loc);
890 protected virtual void Error_NegativeArrayIndex (Location loc)
892 throw new NotImplementedException ();
896 /// Returns an expression that can be used to invoke operator true
897 /// on the expression if it exists.
899 static public Expression GetOperatorTrue (EmitContext ec, Expression e, Location loc)
901 return GetOperatorTrueOrFalse (ec, e, true, loc);
905 /// Returns an expression that can be used to invoke operator false
906 /// on the expression if it exists.
908 static public Expression GetOperatorFalse (EmitContext ec, Expression e, Location loc)
910 return GetOperatorTrueOrFalse (ec, e, false, loc);
913 static Expression GetOperatorTrueOrFalse (EmitContext ec, Expression e, bool is_true, Location loc)
915 MethodGroupExpr operator_group;
916 operator_group = MethodLookup (ec.ContainerType, e.Type, is_true ? "op_True" : "op_False", loc) as MethodGroupExpr;
917 if (operator_group == null)
920 ArrayList arguments = new ArrayList (1);
921 arguments.Add (new Argument (e, Argument.AType.Expression));
922 operator_group = operator_group.OverloadResolve (
923 ec, ref arguments, false, loc);
925 if (operator_group == null)
928 return new UserOperatorCall (operator_group, arguments, null, loc);
932 /// Resolves the expression `e' into a boolean expression: either through
933 /// an implicit conversion, or through an `operator true' invocation
935 public static Expression ResolveBoolean (EmitContext ec, Expression e, Location loc)
941 if (e.Type == TypeManager.bool_type)
944 Expression converted = Convert.ImplicitConversion (ec, e, TypeManager.bool_type, Location.Null);
946 if (converted != null)
950 // If no implicit conversion to bool exists, try using `operator true'
952 converted = Expression.GetOperatorTrue (ec, e, loc);
953 if (converted == null){
954 e.Error_ValueCannotBeConverted (ec, loc, TypeManager.bool_type, false);
960 public virtual string ExprClassName
964 case ExprClass.Invalid:
966 case ExprClass.Value:
968 case ExprClass.Variable:
970 case ExprClass.Namespace:
974 case ExprClass.MethodGroup:
975 return "method group";
976 case ExprClass.PropertyAccess:
977 return "property access";
978 case ExprClass.EventAccess:
979 return "event access";
980 case ExprClass.IndexerAccess:
981 return "indexer access";
982 case ExprClass.Nothing:
985 throw new Exception ("Should not happen");
990 /// Reports that we were expecting `expr' to be of class `expected'
992 public void Error_UnexpectedKind (DeclSpace ds, string expected, Location loc)
994 Error_UnexpectedKind (ds, expected, ExprClassName, loc);
997 public void Error_UnexpectedKind (DeclSpace ds, string expected, string was, Location loc)
999 string name = GetSignatureForError ();
1001 name = ds.GetSignatureForError () + '.' + name;
1003 Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
1004 name, was, expected);
1007 public void Error_UnexpectedKind (ResolveFlags flags, Location loc)
1009 string [] valid = new string [4];
1012 if ((flags & ResolveFlags.VariableOrValue) != 0) {
1013 valid [count++] = "variable";
1014 valid [count++] = "value";
1017 if ((flags & ResolveFlags.Type) != 0)
1018 valid [count++] = "type";
1020 if ((flags & ResolveFlags.MethodGroup) != 0)
1021 valid [count++] = "method group";
1024 valid [count++] = "unknown";
1026 StringBuilder sb = new StringBuilder (valid [0]);
1027 for (int i = 1; i < count - 1; i++) {
1029 sb.Append (valid [i]);
1032 sb.Append ("' or `");
1033 sb.Append (valid [count - 1]);
1036 Report.Error (119, loc,
1037 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1040 public static void UnsafeError (Location loc)
1042 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1046 // Load the object from the pointer.
1048 public static void LoadFromPtr (ILGenerator ig, Type t)
1050 if (t == TypeManager.int32_type)
1051 ig.Emit (OpCodes.Ldind_I4);
1052 else if (t == TypeManager.uint32_type)
1053 ig.Emit (OpCodes.Ldind_U4);
1054 else if (t == TypeManager.short_type)
1055 ig.Emit (OpCodes.Ldind_I2);
1056 else if (t == TypeManager.ushort_type)
1057 ig.Emit (OpCodes.Ldind_U2);
1058 else if (t == TypeManager.char_type)
1059 ig.Emit (OpCodes.Ldind_U2);
1060 else if (t == TypeManager.byte_type)
1061 ig.Emit (OpCodes.Ldind_U1);
1062 else if (t == TypeManager.sbyte_type)
1063 ig.Emit (OpCodes.Ldind_I1);
1064 else if (t == TypeManager.uint64_type)
1065 ig.Emit (OpCodes.Ldind_I8);
1066 else if (t == TypeManager.int64_type)
1067 ig.Emit (OpCodes.Ldind_I8);
1068 else if (t == TypeManager.float_type)
1069 ig.Emit (OpCodes.Ldind_R4);
1070 else if (t == TypeManager.double_type)
1071 ig.Emit (OpCodes.Ldind_R8);
1072 else if (t == TypeManager.bool_type)
1073 ig.Emit (OpCodes.Ldind_I1);
1074 else if (t == TypeManager.intptr_type)
1075 ig.Emit (OpCodes.Ldind_I);
1076 else if (TypeManager.IsEnumType (t)) {
1077 if (t == TypeManager.enum_type)
1078 ig.Emit (OpCodes.Ldind_Ref);
1080 LoadFromPtr (ig, TypeManager.GetEnumUnderlyingType (t));
1081 } else if (t.IsValueType || TypeManager.IsGenericParameter (t))
1082 ig.Emit (OpCodes.Ldobj, t);
1083 else if (t.IsPointer)
1084 ig.Emit (OpCodes.Ldind_I);
1086 ig.Emit (OpCodes.Ldind_Ref);
1090 // The stack contains the pointer and the value of type `type'
1092 public static void StoreFromPtr (ILGenerator ig, Type type)
1094 if (TypeManager.IsEnumType (type))
1095 type = TypeManager.GetEnumUnderlyingType (type);
1096 if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
1097 ig.Emit (OpCodes.Stind_I4);
1098 else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
1099 ig.Emit (OpCodes.Stind_I8);
1100 else if (type == TypeManager.char_type || type == TypeManager.short_type ||
1101 type == TypeManager.ushort_type)
1102 ig.Emit (OpCodes.Stind_I2);
1103 else if (type == TypeManager.float_type)
1104 ig.Emit (OpCodes.Stind_R4);
1105 else if (type == TypeManager.double_type)
1106 ig.Emit (OpCodes.Stind_R8);
1107 else if (type == TypeManager.byte_type || type == TypeManager.sbyte_type ||
1108 type == TypeManager.bool_type)
1109 ig.Emit (OpCodes.Stind_I1);
1110 else if (type == TypeManager.intptr_type)
1111 ig.Emit (OpCodes.Stind_I);
1112 else if (type.IsValueType || TypeManager.IsGenericParameter (type))
1113 ig.Emit (OpCodes.Stobj, type);
1115 ig.Emit (OpCodes.Stind_Ref);
1119 // Returns the size of type `t' if known, otherwise, 0
1121 public static int GetTypeSize (Type t)
1123 t = TypeManager.TypeToCoreType (t);
1124 if (t == TypeManager.int32_type ||
1125 t == TypeManager.uint32_type ||
1126 t == TypeManager.float_type)
1128 else if (t == TypeManager.int64_type ||
1129 t == TypeManager.uint64_type ||
1130 t == TypeManager.double_type)
1132 else if (t == TypeManager.byte_type ||
1133 t == TypeManager.sbyte_type ||
1134 t == TypeManager.bool_type)
1136 else if (t == TypeManager.short_type ||
1137 t == TypeManager.char_type ||
1138 t == TypeManager.ushort_type)
1140 else if (t == TypeManager.decimal_type)
1146 protected void Error_CannotCallAbstractBase (string name)
1148 Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
1151 protected void Error_CannotModifyIntermediateExpressionValue (EmitContext ec)
1153 Report.SymbolRelatedToPreviousError (type);
1154 if (ec.CurrentInitializerVariable != null) {
1155 Report.Error (1918, loc, "Members of a value type property `{0}' cannot be assigned with an object initializer",
1156 GetSignatureForError ());
1158 Report.Error (1612, loc, "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
1159 GetSignatureForError ());
1164 // Converts `source' to an int, uint, long or ulong.
1166 public Expression ConvertExpressionToArrayIndex (EmitContext ec, Expression source)
1168 Expression converted;
1170 using (ec.With (EmitContext.Flags.CheckState, true)) {
1171 converted = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, source.loc);
1172 if (converted == null)
1173 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, source.loc);
1174 if (converted == null)
1175 converted = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, source.loc);
1176 if (converted == null)
1177 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, source.loc);
1179 if (converted == null) {
1180 source.Error_ValueCannotBeConverted (ec, source.loc, TypeManager.int32_type, false);
1186 // Only positive constants are allowed at compile time
1188 Constant c = converted as Constant;
1191 Error_NegativeArrayIndex (source.loc);
1196 return new ArrayIndexCast (converted).Resolve (ec);
1200 // Derived classes implement this method by cloning the fields that
1201 // could become altered during the Resolve stage
1203 // Only expressions that are created for the parser need to implement
1206 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1208 throw new NotImplementedException (
1210 "CloneTo not implemented for expression {0}", this.GetType ()));
1214 // Clones an expression created by the parser.
1216 // We only support expressions created by the parser so far, not
1217 // expressions that have been resolved (many more classes would need
1218 // to implement CloneTo).
1220 // This infrastructure is here merely for Lambda expressions which
1221 // compile the same code using different type values for the same
1222 // arguments to find the correct overload
1224 public Expression Clone (CloneContext clonectx)
1226 Expression cloned = (Expression) MemberwiseClone ();
1227 CloneTo (clonectx, cloned);
1232 public virtual Expression CreateExpressionTree (EmitContext ec)
1234 throw new NotImplementedException (
1235 "Expression tree conversion not implemented for " + GetType ());
1238 protected Expression CreateExpressionFactoryCall (string name, ArrayList args)
1240 return CreateExpressionFactoryCall (name, null, args, loc);
1243 protected Expression CreateExpressionFactoryCall (string name, TypeArguments typeArguments, ArrayList args)
1245 return CreateExpressionFactoryCall (name, typeArguments, args, loc);
1248 public static Expression CreateExpressionFactoryCall (string name, TypeArguments typeArguments, ArrayList args, Location loc)
1250 TypeExpr texpr = TypeManager.expression_type_expr;
1251 if (texpr == null) {
1252 Type t = TypeManager.CoreLookupType ("System.Linq.Expressions", "Expression", Kind.Class, true);
1256 TypeManager.expression_type_expr = texpr = new TypeExpression (t, Location.Null);
1259 return new Invocation (new MemberAccess (texpr, name, typeArguments, loc), args);
1264 /// This is just a base class for expressions that can
1265 /// appear on statements (invocations, object creation,
1266 /// assignments, post/pre increment and decrement). The idea
1267 /// being that they would support an extra Emition interface that
1268 /// does not leave a result on the stack.
1270 public abstract class ExpressionStatement : Expression {
1272 public virtual ExpressionStatement ResolveStatement (EmitContext ec)
1274 Expression e = Resolve (ec);
1278 ExpressionStatement es = e as ExpressionStatement;
1280 Error_InvalidExpressionStatement ();
1286 /// Requests the expression to be emitted in a `statement'
1287 /// context. This means that no new value is left on the
1288 /// stack after invoking this method (constrasted with
1289 /// Emit that will always leave a value on the stack).
1291 public abstract void EmitStatement (EmitContext ec);
1295 /// This kind of cast is used to encapsulate the child
1296 /// whose type is child.Type into an expression that is
1297 /// reported to return "return_type". This is used to encapsulate
1298 /// expressions which have compatible types, but need to be dealt
1299 /// at higher levels with.
1301 /// For example, a "byte" expression could be encapsulated in one
1302 /// of these as an "unsigned int". The type for the expression
1303 /// would be "unsigned int".
1306 public class EmptyCast : Expression
1308 protected Expression child;
1310 protected EmptyCast (Expression child, Type return_type)
1312 eclass = child.eclass;
1313 loc = child.Location;
1318 public static Expression Create (Expression child, Type type)
1320 Constant c = child as Constant;
1322 return new EmptyConstantCast (c, type);
1325 // No double conversion required when wrapping nullable types
1327 if (TypeManager.IsNullableType (type)) {
1328 EmptyCast empty_cast = child as EmptyCast;
1329 if (empty_cast != null) {
1330 if (TypeManager.IsNullableTypeOf (empty_cast.type, type))
1331 throw new InternalErrorException ("Missing nullable underlying type conversion {0} != {1}",
1332 TypeManager.CSharpName (empty_cast.type), TypeManager.CSharpName (type));
1334 empty_cast.type = type;
1339 return new EmptyCast (child, type);
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 EmptyCast target = (EmptyCast) t;
1372 target.child = child.Clone (clonectx);
1377 /// Performs a cast using an operator (op_Explicit or op_Implicit)
1379 public class OperatorCast : EmptyCast {
1380 MethodInfo conversion_operator;
1383 public OperatorCast (Expression child, Type target_type) : this (child, target_type, false) {}
1385 public OperatorCast (Expression child, Type target_type, bool find_explicit)
1386 : base (child, target_type)
1388 this.find_explicit = find_explicit;
1391 // Returns the implicit operator that converts from
1392 // 'child.Type' to our target type (type)
1393 MethodInfo GetConversionOperator (bool find_explicit)
1395 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1399 mi = TypeManager.MemberLookup (child.Type, child.Type, child.Type, MemberTypes.Method,
1400 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1403 mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1404 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1407 foreach (MethodInfo oper in mi) {
1408 ParameterData pd = TypeManager.GetParameterData (oper);
1410 if (pd.ParameterType (0) == child.Type && TypeManager.TypeToCoreType (oper.ReturnType) == type)
1418 public override void Emit (EmitContext ec)
1420 ILGenerator ig = ec.ig;
1423 conversion_operator = GetConversionOperator (find_explicit);
1425 if (conversion_operator == null)
1426 throw new InternalErrorException ("Outer conversion routine is out of sync");
1428 ig.Emit (OpCodes.Call, conversion_operator);
1434 /// This is a numeric cast to a Decimal
1436 public class CastToDecimal : EmptyCast {
1437 MethodInfo conversion_operator;
1439 public CastToDecimal (Expression child)
1440 : this (child, false)
1444 public CastToDecimal (Expression child, bool find_explicit)
1445 : base (child, TypeManager.decimal_type)
1447 conversion_operator = GetConversionOperator (find_explicit);
1449 if (conversion_operator == null)
1450 throw new InternalErrorException ("Outer conversion routine is out of sync");
1453 // Returns the implicit operator that converts from
1454 // 'child.Type' to System.Decimal.
1455 MethodInfo GetConversionOperator (bool find_explicit)
1457 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1459 MemberInfo [] mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1460 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1462 foreach (MethodInfo oper in mi) {
1463 ParameterData pd = TypeManager.GetParameterData (oper);
1465 if (pd.ParameterType (0) == child.Type && TypeManager.TypeToCoreType (oper.ReturnType) == type)
1471 public override void Emit (EmitContext ec)
1473 ILGenerator ig = ec.ig;
1476 ig.Emit (OpCodes.Call, conversion_operator);
1481 /// This is an explicit numeric cast from a Decimal
1483 public class CastFromDecimal : EmptyCast
1485 static IDictionary operators;
1487 public CastFromDecimal (Expression child, Type return_type)
1488 : base (child, return_type)
1490 if (child.Type != TypeManager.decimal_type)
1491 throw new InternalErrorException (
1492 "The expected type is Decimal, instead it is " + child.Type.FullName);
1495 // Returns the explicit operator that converts from an
1496 // express of type System.Decimal to 'type'.
1497 public Expression Resolve ()
1499 if (operators == null) {
1500 MemberInfo[] all_oper = TypeManager.MemberLookup (TypeManager.decimal_type,
1501 TypeManager.decimal_type, TypeManager.decimal_type, MemberTypes.Method,
1502 BindingFlags.Static | BindingFlags.Public, "op_Explicit", null);
1504 operators = new System.Collections.Specialized.HybridDictionary ();
1505 foreach (MethodInfo oper in all_oper) {
1506 ParameterData pd = TypeManager.GetParameterData (oper);
1507 if (pd.ParameterType (0) == TypeManager.decimal_type)
1508 operators.Add (TypeManager.TypeToCoreType (oper.ReturnType), oper);
1512 return operators.Contains (type) ? this : null;
1515 public override void Emit (EmitContext ec)
1517 ILGenerator ig = ec.ig;
1520 ig.Emit (OpCodes.Call, (MethodInfo)operators [type]);
1526 // Constant specialization of EmptyCast.
1527 // We need to special case this since an empty cast of
1528 // a constant is still a constant.
1530 public class EmptyConstantCast : Constant
1532 public readonly Constant child;
1534 public EmptyConstantCast(Constant child, Type type)
1535 : base (child.Location)
1537 eclass = child.eclass;
1542 public override string AsString ()
1544 return child.AsString ();
1547 public override object GetValue ()
1549 return child.GetValue ();
1552 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
1554 // FIXME: check that 'type' can be converted to 'target_type' first
1555 return child.ConvertExplicitly (in_checked_context, target_type);
1558 public override Constant Increment ()
1560 return child.Increment ();
1563 public override bool IsDefaultValue {
1564 get { return child.IsDefaultValue; }
1567 public override bool IsNegative {
1568 get { return child.IsNegative; }
1571 public override bool IsNull {
1572 get { return child.IsNull; }
1575 public override bool IsZeroInteger {
1576 get { return child.IsZeroInteger; }
1579 public override void Emit (EmitContext ec)
1584 public override Constant ConvertImplicitly (Type target_type)
1586 // FIXME: Do we need to check user conversions?
1587 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1589 return child.ConvertImplicitly (target_type);
1595 /// This class is used to wrap literals which belong inside Enums
1597 public class EnumConstant : Constant {
1598 public Constant Child;
1600 public EnumConstant (Constant child, Type enum_type):
1601 base (child.Location)
1603 eclass = child.eclass;
1608 public override Expression DoResolve (EmitContext ec)
1610 // This should never be invoked, we are born in fully
1611 // initialized state.
1616 public override void Emit (EmitContext ec)
1621 public override bool GetAttributableValue (Type value_type, out object value)
1623 value = GetTypedValue ();
1627 public override string GetSignatureForError()
1629 return TypeManager.CSharpName (Type);
1632 public override object GetValue ()
1634 return Child.GetValue ();
1637 public override object GetTypedValue ()
1639 // FIXME: runtime is not ready to work with just emited enums
1640 if (!RootContext.StdLib) {
1641 return Child.GetValue ();
1644 return System.Enum.ToObject (type, Child.GetValue ());
1647 public override string AsString ()
1649 return TypeManager.CSharpEnumValue (type, Child.GetValue ());
1652 public override Constant Increment()
1654 return new EnumConstant (Child.Increment (), type);
1657 public override bool IsDefaultValue {
1659 return Child.IsDefaultValue;
1663 public override bool IsZeroInteger {
1664 get { return Child.IsZeroInteger; }
1667 public override bool IsNegative {
1669 return Child.IsNegative;
1673 public override Constant ConvertExplicitly(bool in_checked_context, Type target_type)
1675 if (Child.Type == target_type)
1678 return Child.ConvertExplicitly (in_checked_context, target_type);
1681 public override Constant ConvertImplicitly (Type type)
1683 Type this_type = TypeManager.DropGenericTypeArguments (Type);
1684 type = TypeManager.DropGenericTypeArguments (type);
1686 if (this_type == type) {
1687 // This is workaround of mono bug. It can be removed when the latest corlib spreads enough
1688 if (TypeManager.IsEnumType (type.UnderlyingSystemType))
1691 Type child_type = TypeManager.DropGenericTypeArguments (Child.Type);
1692 if (type.UnderlyingSystemType != child_type)
1693 Child = Child.ConvertImplicitly (type.UnderlyingSystemType);
1697 if (!Convert.ImplicitStandardConversionExists (this, type)){
1701 return Child.ConvertImplicitly(type);
1707 /// This kind of cast is used to encapsulate Value Types in objects.
1709 /// The effect of it is to box the value type emitted by the previous
1712 public class BoxedCast : EmptyCast {
1714 public BoxedCast (Expression expr, Type target_type)
1715 : base (expr, target_type)
1717 eclass = ExprClass.Value;
1720 public override Expression DoResolve (EmitContext ec)
1722 // This should never be invoked, we are born in fully
1723 // initialized state.
1728 public override void Emit (EmitContext ec)
1732 ec.ig.Emit (OpCodes.Box, child.Type);
1736 public class UnboxCast : EmptyCast {
1737 public UnboxCast (Expression expr, Type return_type)
1738 : base (expr, return_type)
1742 public override Expression DoResolve (EmitContext ec)
1744 // This should never be invoked, we are born in fully
1745 // initialized state.
1750 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1752 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
1753 Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
1754 return base.DoResolveLValue (ec, right_side);
1757 public override void Emit (EmitContext ec)
1760 ILGenerator ig = ec.ig;
1764 if (t.IsGenericParameter || t.IsGenericType && t.IsValueType)
1765 ig.Emit (OpCodes.Unbox_Any, t);
1769 ig.Emit (OpCodes.Unbox, t);
1771 LoadFromPtr (ig, t);
1777 /// This is used to perform explicit numeric conversions.
1779 /// Explicit numeric conversions might trigger exceptions in a checked
1780 /// context, so they should generate the conv.ovf opcodes instead of
1783 public class ConvCast : EmptyCast {
1784 public enum Mode : byte {
1785 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1787 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1788 U2_I1, U2_U1, U2_I2, U2_CH,
1789 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1790 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1791 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH,
1792 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH,
1793 CH_I1, CH_U1, CH_I2,
1794 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1795 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4
1800 public ConvCast (Expression child, Type return_type, Mode m)
1801 : base (child, return_type)
1806 public override Expression DoResolve (EmitContext ec)
1808 // This should never be invoked, we are born in fully
1809 // initialized state.
1814 public override string ToString ()
1816 return String.Format ("ConvCast ({0}, {1})", mode, child);
1819 public override void Emit (EmitContext ec)
1821 ILGenerator ig = ec.ig;
1827 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1828 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1829 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1830 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1831 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1833 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1834 case Mode.U1_CH: /* nothing */ break;
1836 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1837 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1838 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1839 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1840 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1841 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1843 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1844 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1845 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1846 case Mode.U2_CH: /* nothing */ break;
1848 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1849 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1850 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1851 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1852 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1853 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1854 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1856 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1857 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1858 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1859 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1860 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1861 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1863 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1864 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1865 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1866 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1867 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1868 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1869 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1870 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1872 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1873 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1874 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1875 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1876 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1877 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1878 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1879 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1881 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1882 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1883 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1885 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1886 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1887 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1888 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1889 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1890 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1891 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1892 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1893 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1895 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1896 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1897 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1898 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1899 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1900 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1901 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1902 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1903 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1904 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1908 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
1909 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
1910 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
1911 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
1912 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
1914 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
1915 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
1917 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
1918 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
1919 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
1920 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
1921 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
1922 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
1924 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
1925 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
1926 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
1927 case Mode.U2_CH: /* nothing */ break;
1929 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
1930 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
1931 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
1932 case Mode.I4_U4: /* nothing */ break;
1933 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
1934 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
1935 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
1937 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
1938 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
1939 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
1940 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
1941 case Mode.U4_I4: /* nothing */ break;
1942 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
1944 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
1945 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
1946 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
1947 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
1948 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
1949 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
1950 case Mode.I8_U8: /* nothing */ break;
1951 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
1953 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
1954 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
1955 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
1956 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
1957 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
1958 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
1959 case Mode.U8_I8: /* nothing */ break;
1960 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
1962 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
1963 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
1964 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
1966 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
1967 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
1968 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
1969 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
1970 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
1971 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
1972 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
1973 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
1974 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
1976 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
1977 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
1978 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
1979 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
1980 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
1981 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
1982 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
1983 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
1984 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
1985 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1991 public class OpcodeCast : EmptyCast {
1995 public OpcodeCast (Expression child, Type return_type, OpCode op)
1996 : base (child, return_type)
2000 second_valid = false;
2003 public OpcodeCast (Expression child, Type return_type, OpCode op, OpCode op2)
2004 : base (child, return_type)
2009 second_valid = true;
2012 public override Expression CreateExpressionTree (EmitContext ec)
2014 // A cast has no expresion tree representation
2015 return child.CreateExpressionTree (ec);
2018 public override Expression DoResolve (EmitContext ec)
2020 // This should never be invoked, we are born in fully
2021 // initialized state.
2026 public override void Emit (EmitContext ec)
2035 public Type UnderlyingType {
2036 get { return child.Type; }
2041 /// This kind of cast is used to encapsulate a child and cast it
2042 /// to the class requested
2044 public class ClassCast : EmptyCast {
2045 public ClassCast (Expression child, Type return_type)
2046 : base (child, return_type)
2051 public override Expression DoResolve (EmitContext ec)
2053 // This should never be invoked, we are born in fully
2054 // initialized state.
2059 public override void Emit (EmitContext ec)
2063 if (TypeManager.IsGenericParameter (child.Type))
2064 ec.ig.Emit (OpCodes.Box, child.Type);
2067 if (type.IsGenericParameter)
2068 ec.ig.Emit (OpCodes.Unbox_Any, type);
2071 ec.ig.Emit (OpCodes.Castclass, type);
2076 // Used when resolved expression has different representations for
2077 // expression trees and emit phase
2079 public class ReducedExpression : Expression
2081 class ReducedConstantExpression : Constant
2083 readonly Constant expr;
2084 readonly Expression orig_expr;
2086 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2087 : base (expr.Location)
2090 this.orig_expr = orig_expr;
2093 public override string AsString ()
2095 return expr.AsString ();
2098 public override Expression CreateExpressionTree (EmitContext ec)
2100 return orig_expr.CreateExpressionTree (ec);
2103 public override object GetValue ()
2105 return expr.GetValue ();
2108 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
2110 throw new NotImplementedException ();
2113 public override Expression DoResolve (EmitContext ec)
2115 eclass = expr.eclass;
2120 public override Constant Increment ()
2122 throw new NotImplementedException ();
2125 public override bool IsDefaultValue {
2127 return expr.IsDefaultValue;
2131 public override bool IsNegative {
2133 return expr.IsNegative;
2137 public override void Emit (EmitContext ec)
2143 readonly Expression expr, orig_expr;
2145 private ReducedExpression (Expression expr, Expression orig_expr)
2148 this.orig_expr = orig_expr;
2151 public static Expression Create (Constant expr, Expression original_expr)
2153 return new ReducedConstantExpression (expr, original_expr);
2156 public static Expression Create (Expression expr, Expression original_expr)
2158 Constant c = expr as Constant;
2160 return Create (c, original_expr);
2162 return new ReducedExpression (expr, original_expr);
2165 public override Expression CreateExpressionTree (EmitContext ec)
2167 return orig_expr.CreateExpressionTree (ec);
2170 public override Expression DoResolve (EmitContext ec)
2172 eclass = expr.eclass;
2177 public override void Emit (EmitContext ec)
2184 /// SimpleName expressions are formed of a single word and only happen at the beginning
2185 /// of a dotted-name.
2187 public class SimpleName : Expression {
2188 public readonly string Name;
2189 public readonly TypeArguments Arguments;
2192 public SimpleName (string name, Location l)
2198 public SimpleName (string name, TypeArguments args, Location l)
2205 public SimpleName (string name, TypeParameter[] type_params, Location l)
2210 Arguments = new TypeArguments (l);
2211 foreach (TypeParameter type_param in type_params)
2212 Arguments.Add (new TypeParameterExpr (type_param, l));
2215 public static string RemoveGenericArity (string name)
2218 StringBuilder sb = null;
2220 int pos = name.IndexOf ('`', start);
2225 sb.Append (name.Substring (start));
2230 sb = new StringBuilder ();
2231 sb.Append (name.Substring (start, pos-start));
2234 while ((pos < name.Length) && Char.IsNumber (name [pos]))
2238 } while (start < name.Length);
2240 return sb.ToString ();
2243 public SimpleName GetMethodGroup ()
2245 return new SimpleName (RemoveGenericArity (Name), Arguments, loc);
2248 public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
2250 if (ec.IsInFieldInitializer)
2251 Report.Error (236, l,
2252 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2256 120, l, "`{0}': An object reference is required for the nonstatic field, method or property",
2260 public bool IdenticalNameAndTypeName (EmitContext ec, Expression resolved_to, Location loc)
2262 return resolved_to != null && resolved_to.Type != null &&
2263 resolved_to.Type.Name == Name &&
2264 (ec.DeclContainer.LookupNamespaceOrType (Name, loc, /* ignore_cs0104 = */ true) != null);
2267 public override Expression DoResolve (EmitContext ec)
2269 return SimpleNameResolve (ec, null, false);
2272 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
2274 return SimpleNameResolve (ec, right_side, false);
2278 public Expression DoResolve (EmitContext ec, bool intermediate)
2280 return SimpleNameResolve (ec, null, intermediate);
2283 static bool IsNestedChild (Type t, Type parent)
2285 while (parent != null) {
2286 if (TypeManager.IsNestedChildOf (t, TypeManager.DropGenericTypeArguments (parent)))
2289 parent = parent.BaseType;
2295 FullNamedExpression ResolveNested (IResolveContext ec, Type t)
2297 if (!TypeManager.IsGenericTypeDefinition (t) && !TypeManager.IsGenericType (t))
2300 DeclSpace ds = ec.DeclContainer;
2301 while (ds != null && !IsNestedChild (t, ds.TypeBuilder))
2307 Type[] gen_params = TypeManager.GetTypeArguments (t);
2309 int arg_count = Arguments != null ? Arguments.Count : 0;
2311 for (; (ds != null) && ds.IsGeneric; ds = ds.Parent) {
2312 if (arg_count + ds.CountTypeParameters == gen_params.Length) {
2313 TypeArguments new_args = new TypeArguments (loc);
2314 foreach (TypeParameter param in ds.TypeParameters)
2315 new_args.Add (new TypeParameterExpr (param, loc));
2317 if (Arguments != null)
2318 new_args.Add (Arguments);
2320 return new ConstructedType (t, new_args, loc);
2327 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2329 FullNamedExpression fne = ec.GenericDeclContainer.LookupGeneric (Name, loc);
2331 return fne.ResolveAsTypeStep (ec, silent);
2333 int errors = Report.Errors;
2334 fne = ec.DeclContainer.LookupNamespaceOrType (Name, loc, /*ignore_cs0104=*/ false);
2337 if (fne.Type == null)
2340 FullNamedExpression nested = ResolveNested (ec, fne.Type);
2342 return nested.ResolveAsTypeStep (ec, false);
2344 if (Arguments != null) {
2345 ConstructedType ct = new ConstructedType (fne, Arguments, loc);
2346 return ct.ResolveAsTypeStep (ec, false);
2352 if (silent || errors != Report.Errors)
2355 Error_TypeOrNamespaceNotFound (ec);
2359 protected virtual void Error_TypeOrNamespaceNotFound (IResolveContext ec)
2361 MemberCore mc = ec.DeclContainer.GetDefinition (Name);
2363 Error_UnexpectedKind (ec.DeclContainer, "type", GetMemberType (mc), loc);
2367 string ns = ec.DeclContainer.NamespaceEntry.NS.Name;
2368 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2369 foreach (Assembly a in RootNamespace.Global.Assemblies) {
2370 Type type = a.GetType (fullname);
2372 Report.SymbolRelatedToPreviousError (type);
2373 Expression.ErrorIsInaccesible (loc, TypeManager.CSharpName (type));
2378 Type t = ec.DeclContainer.LookupAnyGeneric (Name);
2380 Namespace.Error_InvalidNumberOfTypeArguments (t, loc);
2384 if (Arguments != null) {
2385 FullNamedExpression retval = ec.DeclContainer.LookupNamespaceOrType (SimpleName.RemoveGenericArity (Name), loc, true);
2386 if (retval != null) {
2387 Namespace.Error_TypeArgumentsCannotBeUsed (retval.Type, loc);
2392 NamespaceEntry.Error_NamespaceNotFound (loc, Name);
2395 // TODO: I am still not convinced about this. If someone else will need it
2396 // implement this as virtual property in MemberCore hierarchy
2397 public static string GetMemberType (MemberCore mc)
2403 if (mc is FieldBase)
2405 if (mc is MethodCore)
2407 if (mc is EnumMember)
2415 Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2421 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2427 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2434 /// 7.5.2: Simple Names.
2436 /// Local Variables and Parameters are handled at
2437 /// parse time, so they never occur as SimpleNames.
2439 /// The `intermediate' flag is used by MemberAccess only
2440 /// and it is used to inform us that it is ok for us to
2441 /// avoid the static check, because MemberAccess might end
2442 /// up resolving the Name as a Type name and the access as
2443 /// a static type access.
2445 /// ie: Type Type; .... { Type.GetType (""); }
2447 /// Type is both an instance variable and a Type; Type.GetType
2448 /// is the static method not an instance method of type.
2450 Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2452 Expression e = null;
2455 // Stage 1: Performed by the parser (binding to locals or parameters).
2457 Block current_block = ec.CurrentBlock;
2458 if (current_block != null){
2459 LocalInfo vi = current_block.GetLocalInfo (Name);
2461 if (Arguments != null) {
2462 Report.Error (307, loc,
2463 "The variable `{0}' cannot be used with type arguments",
2468 LocalVariableReference var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2469 if (right_side != null) {
2470 return var.ResolveLValue (ec, right_side, loc);
2472 ResolveFlags rf = ResolveFlags.VariableOrValue;
2474 rf |= ResolveFlags.DisableFlowAnalysis;
2475 return var.Resolve (ec, rf);
2479 ParameterReference pref = current_block.Toplevel.GetParameterReference (Name, loc);
2481 if (Arguments != null) {
2482 Report.Error (307, loc,
2483 "The variable `{0}' cannot be used with type arguments",
2488 if (right_side != null)
2489 return pref.ResolveLValue (ec, right_side, loc);
2491 return pref.Resolve (ec);
2494 Expression expr = current_block.Toplevel.GetTransparentIdentifier (Name);
2496 if (right_side != null)
2497 return expr.ResolveLValue (ec, right_side, loc);
2498 return expr.Resolve (ec);
2503 // Stage 2: Lookup members
2506 Type almost_matched_type = null;
2507 ArrayList almost_matched = null;
2508 for (DeclSpace lookup_ds = ec.DeclContainer; lookup_ds != null; lookup_ds = lookup_ds.Parent) {
2509 // either RootDeclSpace or GenericMethod
2510 if (lookup_ds.TypeBuilder == null)
2513 e = MemberLookup (ec.ContainerType, lookup_ds.TypeBuilder, Name, loc);
2515 if (e is PropertyExpr) {
2516 // since TypeManager.MemberLookup doesn't know if we're doing a lvalue access or not,
2517 // it doesn't know which accessor to check permissions against
2518 if (((PropertyExpr) e).IsAccessibleFrom (ec.ContainerType, right_side != null))
2520 } else if (e is EventExpr) {
2521 if (((EventExpr) e).IsAccessibleFrom (ec.ContainerType))
2529 if (almost_matched == null && almost_matched_members.Count > 0) {
2530 almost_matched_type = lookup_ds.TypeBuilder;
2531 almost_matched = (ArrayList) almost_matched_members.Clone ();
2536 if (almost_matched == null && almost_matched_members.Count > 0) {
2537 almost_matched_type = ec.ContainerType;
2538 almost_matched = (ArrayList) almost_matched_members.Clone ();
2540 e = ResolveAsTypeStep (ec, true);
2544 if (current_block != null) {
2545 IKnownVariable ikv = current_block.Explicit.GetKnownVariable (Name);
2547 LocalInfo li = ikv as LocalInfo;
2548 // Supress CS0219 warning
2552 Error_VariableIsUsedBeforeItIsDeclared (Name);
2557 if (almost_matched != null)
2558 almost_matched_members = almost_matched;
2559 if (almost_matched_type == null)
2560 almost_matched_type = ec.ContainerType;
2561 Error_MemberLookupFailed (ec.ContainerType, null, almost_matched_type, Name,
2562 ec.DeclContainer.Name, AllMemberTypes, AllBindingFlags);
2566 if (e is TypeExpr) {
2567 if (Arguments == null)
2570 ConstructedType ct = new ConstructedType (
2571 (FullNamedExpression) e, Arguments, loc);
2572 return ct.ResolveAsTypeStep (ec, false);
2575 if (e is MemberExpr) {
2576 MemberExpr me = (MemberExpr) e;
2579 if (me.IsInstance) {
2580 if (ec.IsStatic || ec.IsInFieldInitializer) {
2582 // Note that an MemberExpr can be both IsInstance and IsStatic.
2583 // An unresolved MethodGroupExpr can contain both kinds of methods
2584 // and each predicate is true if the MethodGroupExpr contains
2585 // at least one of that kind of method.
2589 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2590 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2595 // Pass the buck to MemberAccess and Invocation.
2597 left = EmptyExpression.Null;
2599 left = ec.GetThis (loc);
2602 left = new TypeExpression (ec.ContainerType, loc);
2605 me = me.ResolveMemberAccess (ec, left, loc, null);
2609 if (Arguments != null) {
2610 Arguments.Resolve (ec);
2611 me.SetTypeArguments (Arguments);
2614 if (!me.IsStatic && (me.InstanceExpression != null) &&
2615 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2616 me.InstanceExpression.Type != me.DeclaringType &&
2617 !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2618 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2619 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2620 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2624 return (right_side != null)
2625 ? me.DoResolveLValue (ec, right_side)
2626 : me.DoResolve (ec);
2632 public override void Emit (EmitContext ec)
2634 throw new InternalErrorException ("The resolve phase was not executed");
2637 public override string ToString ()
2642 public override string GetSignatureForError ()
2644 if (Arguments != null) {
2645 return TypeManager.RemoveGenericArity (Name) + "<" +
2646 Arguments.GetSignatureForError () + ">";
2652 protected override void CloneTo (CloneContext clonectx, Expression target)
2654 // CloneTo: Nothing, we do not keep any state on this expression
2659 /// Represents a namespace or a type. The name of the class was inspired by
2660 /// section 10.8.1 (Fully Qualified Names).
2662 public abstract class FullNamedExpression : Expression {
2663 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2668 public abstract string FullName {
2674 /// Expression that evaluates to a type
2676 public abstract class TypeExpr : FullNamedExpression {
2677 override public FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2679 TypeExpr t = DoResolveAsTypeStep (ec);
2683 eclass = ExprClass.Type;
2687 override public Expression DoResolve (EmitContext ec)
2689 return ResolveAsTypeTerminal (ec, false);
2692 override public void Emit (EmitContext ec)
2694 throw new Exception ("Should never be called");
2697 public virtual bool CheckAccessLevel (DeclSpace ds)
2699 return ds.CheckAccessLevel (Type);
2702 public virtual bool AsAccessible (DeclSpace ds)
2704 return ds.IsAccessibleAs (Type);
2707 public virtual bool IsClass {
2708 get { return Type.IsClass; }
2711 public virtual bool IsValueType {
2712 get { return Type.IsValueType; }
2715 public virtual bool IsInterface {
2716 get { return Type.IsInterface; }
2719 public virtual bool IsSealed {
2720 get { return Type.IsSealed; }
2723 public virtual bool CanInheritFrom ()
2725 if (Type == TypeManager.enum_type ||
2726 (Type == TypeManager.value_type && RootContext.StdLib) ||
2727 Type == TypeManager.multicast_delegate_type ||
2728 Type == TypeManager.delegate_type ||
2729 Type == TypeManager.array_type)
2735 protected abstract TypeExpr DoResolveAsTypeStep (IResolveContext ec);
2737 public abstract string Name {
2741 public override bool Equals (object obj)
2743 TypeExpr tobj = obj as TypeExpr;
2747 return Type == tobj.Type;
2750 public override int GetHashCode ()
2752 return Type.GetHashCode ();
2755 public override string ToString ()
2762 /// Fully resolved Expression that already evaluated to a type
2764 public class TypeExpression : TypeExpr {
2765 public TypeExpression (Type t, Location l)
2768 eclass = ExprClass.Type;
2772 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2777 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2782 public override string Name {
2783 get { return Type.ToString (); }
2786 public override string FullName {
2787 get { return Type.FullName; }
2792 /// Used to create types from a fully qualified name. These are just used
2793 /// by the parser to setup the core types. A TypeLookupExpression is always
2794 /// classified as a type.
2796 public sealed class TypeLookupExpression : TypeExpr {
2797 readonly string name;
2799 public TypeLookupExpression (string name)
2802 eclass = ExprClass.Type;
2805 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2807 // It's null for corlib compilation only
2809 return DoResolveAsTypeStep (ec);
2814 private class UnexpectedType
2818 // This performes recursive type lookup, providing support for generic types.
2819 // For example, given the type:
2821 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]]
2823 // The types will be checked in the following order:
2826 // System.Collections |
2827 // System.Collections.Generic |
2829 // System | recursive call 1 |
2830 // System.Int32 _| | main method call
2832 // System | recursive call 2 |
2833 // System.String _| |
2835 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]] _|
2837 private Type TypeLookup (IResolveContext ec, string name)
2842 FullNamedExpression resolved = null;
2844 Type recursive_type = null;
2845 while (index < name.Length) {
2846 if (name[index] == '[') {
2851 if (name[index] == '[')
2853 else if (name[index] == ']')
2855 } while (braces > 0);
2856 recursive_type = TypeLookup (ec, name.Substring (open + 1, index - open - 1));
2857 if (recursive_type == null || (recursive_type == typeof(UnexpectedType)))
2858 return recursive_type;
2861 if (name[index] == ',')
2863 else if ((name[index] == '.' && !done) || (index == name.Length && name[0] != '[')) {
2864 string substring = name.Substring(dot, index - dot);
2866 if (resolved == null)
2867 resolved = RootNamespace.Global.Lookup (ec.DeclContainer, substring, Location.Null);
2868 else if (resolved is Namespace)
2869 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
2870 else if (type != null)
2871 type = TypeManager.GetNestedType (type, substring);
2875 if (resolved == null)
2877 else if (type == null && resolved is TypeExpr)
2878 type = resolved.Type;
2885 if (name[0] != '[') {
2886 string substring = name.Substring(dot, index - dot);
2889 return TypeManager.GetNestedType (type, substring);
2891 if (resolved != null) {
2892 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
2893 if (resolved is TypeExpr)
2894 return resolved.Type;
2896 if (resolved == null)
2899 resolved.Error_UnexpectedKind (ec.DeclContainer, "type", loc);
2900 return typeof (UnexpectedType);
2906 return recursive_type;
2909 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2911 Type t = TypeLookup (ec, name);
2913 NamespaceEntry.Error_NamespaceNotFound (loc, name);
2916 if (t == typeof(UnexpectedType))
2922 public override string Name {
2923 get { return name; }
2926 public override string FullName {
2927 get { return name; }
2930 protected override void CloneTo (CloneContext clonectx, Expression target)
2932 // CloneTo: Nothing, we do not keep any state on this expression
2935 public override string GetSignatureForError ()
2938 return TypeManager.CSharpName (name);
2940 return base.GetSignatureForError ();
2945 /// Represents an "unbound generic type", ie. typeof (Foo<>).
2948 public class UnboundTypeExpression : TypeExpr
2952 public UnboundTypeExpression (MemberName name, Location l)
2958 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2961 if (name.Left != null) {
2962 Expression lexpr = name.Left.GetTypeExpression ();
2963 expr = new MemberAccess (lexpr, name.Basename);
2965 expr = new SimpleName (name.Basename, loc);
2968 FullNamedExpression fne = expr.ResolveAsTypeStep (ec, false);
2973 return new TypeExpression (type, loc);
2976 public override string Name {
2977 get { return name.FullName; }
2980 public override string FullName {
2981 get { return name.FullName; }
2985 public class TypeAliasExpression : TypeExpr {
2986 FullNamedExpression alias;
2991 public TypeAliasExpression (FullNamedExpression alias, TypeArguments args, Location l)
2997 eclass = ExprClass.Type;
2999 name = alias.FullName + "<" + args.ToString () + ">";
3001 name = alias.FullName;
3004 public override string Name {
3005 get { return alias.FullName; }
3008 public override string FullName {
3009 get { return name; }
3012 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
3014 texpr = alias.ResolveAsTypeTerminal (ec, false);
3018 Type type = texpr.Type;
3019 int num_args = TypeManager.GetNumberOfTypeArguments (type);
3022 if (num_args == 0) {
3023 Report.Error (308, loc,
3024 "The non-generic type `{0}' cannot " +
3025 "be used with type arguments.",
3026 TypeManager.CSharpName (type));
3030 ConstructedType ctype = new ConstructedType (type, args, loc);
3031 return ctype.ResolveAsTypeTerminal (ec, false);
3032 } else if (num_args > 0) {
3033 Report.Error (305, loc,
3034 "Using the generic type `{0}' " +
3035 "requires {1} type arguments",
3036 TypeManager.CSharpName (type), num_args.ToString ());
3043 public override bool CheckAccessLevel (DeclSpace ds)
3045 return texpr.CheckAccessLevel (ds);
3048 public override bool AsAccessible (DeclSpace ds)
3050 return texpr.AsAccessible (ds);
3053 public override bool IsClass {
3054 get { return texpr.IsClass; }
3057 public override bool IsValueType {
3058 get { return texpr.IsValueType; }
3061 public override bool IsInterface {
3062 get { return texpr.IsInterface; }
3065 public override bool IsSealed {
3066 get { return texpr.IsSealed; }
3071 /// This class denotes an expression which evaluates to a member
3072 /// of a struct or a class.
3074 public abstract class MemberExpr : Expression
3076 protected bool is_base;
3079 /// The name of this member.
3081 public abstract string Name {
3086 // When base.member is used
3088 public bool IsBase {
3089 get { return is_base; }
3090 set { is_base = value; }
3094 /// Whether this is an instance member.
3096 public abstract bool IsInstance {
3101 /// Whether this is a static member.
3103 public abstract bool IsStatic {
3108 /// The type which declares this member.
3110 public abstract Type DeclaringType {
3115 /// The instance expression associated with this member, if it's a
3116 /// non-static member.
3118 public Expression InstanceExpression;
3120 public static void error176 (Location loc, string name)
3122 Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
3123 "with an instance reference, qualify it with a type name instead", name);
3126 // TODO: possible optimalization
3127 // Cache resolved constant result in FieldBuilder <-> expression map
3128 public virtual MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3129 SimpleName original)
3133 // original == null || original.Resolve (...) ==> left
3136 if (left is TypeExpr) {
3137 left = left.ResolveAsTypeTerminal (ec, true);
3142 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3150 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3153 return ResolveExtensionMemberAccess (left);
3156 InstanceExpression = left;
3160 protected virtual MemberExpr ResolveExtensionMemberAccess (Expression left)
3162 error176 (loc, GetSignatureForError ());
3166 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3171 if (InstanceExpression == EmptyExpression.Null) {
3172 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3176 if (InstanceExpression.Type.IsValueType) {
3177 if (InstanceExpression is IMemoryLocation) {
3178 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
3180 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
3181 InstanceExpression.Emit (ec);
3183 t.AddressOf (ec, AddressOp.Store);
3186 InstanceExpression.Emit (ec);
3188 if (prepare_for_load)
3189 ec.ig.Emit (OpCodes.Dup);
3192 public virtual void SetTypeArguments (TypeArguments ta)
3194 // TODO: need to get correct member type
3195 Report.Error (307, loc, "The property `{0}' cannot be used with type arguments",
3196 GetSignatureForError ());
3201 /// Represents group of extension methods
3203 public class ExtensionMethodGroupExpr : MethodGroupExpr
3205 readonly NamespaceEntry namespace_entry;
3206 public Expression ExtensionExpression;
3207 Argument extension_argument;
3209 public ExtensionMethodGroupExpr (ArrayList list, NamespaceEntry n, Type extensionType, Location l)
3210 : base (list, extensionType, l)
3212 this.namespace_entry = n;
3215 public override bool IsStatic {
3216 get { return true; }
3219 public bool IsTopLevel {
3220 get { return namespace_entry == null; }
3223 public override void EmitArguments (EmitContext ec, ArrayList arguments)
3225 if (arguments == null)
3226 arguments = new ArrayList (1);
3227 arguments.Insert (0, extension_argument);
3228 base.EmitArguments (ec, arguments);
3231 public override void EmitCall (EmitContext ec, ArrayList arguments)
3233 if (arguments == null)
3234 arguments = new ArrayList (1);
3235 arguments.Insert (0, extension_argument);
3236 base.EmitCall (ec, arguments);
3239 public override MethodGroupExpr OverloadResolve (EmitContext ec, ref ArrayList arguments, bool may_fail, Location loc)
3241 if (arguments == null)
3242 arguments = new ArrayList (1);
3244 arguments.Insert (0, new Argument (ExtensionExpression));
3245 MethodGroupExpr mg = ResolveOverloadExtensions (ec, arguments, namespace_entry, loc);
3247 // Store resolved argument and restore original arguments
3249 ((ExtensionMethodGroupExpr)mg).extension_argument = (Argument)arguments [0];
3250 arguments.RemoveAt (0);
3255 MethodGroupExpr ResolveOverloadExtensions (EmitContext ec, ArrayList arguments, NamespaceEntry ns, Location loc)
3257 // Use normal resolve rules
3258 MethodGroupExpr mg = base.OverloadResolve (ec, ref arguments, ns != null, loc);
3266 ExtensionMethodGroupExpr e = ns.LookupExtensionMethod (type, null, Name);
3268 return base.OverloadResolve (ec, ref arguments, false, loc);
3270 e.ExtensionExpression = ExtensionExpression;
3271 return e.ResolveOverloadExtensions (ec, arguments, e.namespace_entry, loc);
3276 /// MethodGroupExpr represents a group of method candidates which
3277 /// can be resolved to the best method overload
3279 public class MethodGroupExpr : MemberExpr
3281 public interface IErrorHandler
3283 bool NoExactMatch (EmitContext ec, MethodBase method);
3286 public IErrorHandler CustomErrorHandler;
3287 public MethodBase [] Methods;
3288 MethodBase best_candidate;
3289 // TODO: make private
3290 public TypeArguments type_arguments;
3291 bool identical_type_name;
3294 public MethodGroupExpr (MemberInfo [] mi, Type type, Location l)
3297 Methods = new MethodBase [mi.Length];
3298 mi.CopyTo (Methods, 0);
3301 public MethodGroupExpr (ArrayList list, Type type, Location l)
3305 Methods = (MethodBase[])list.ToArray (typeof (MethodBase));
3307 foreach (MemberInfo m in list){
3308 if (!(m is MethodBase)){
3309 Console.WriteLine ("Name " + m.Name);
3310 Console.WriteLine ("Found a: " + m.GetType ().FullName);
3319 protected MethodGroupExpr (Type type, Location loc)
3322 eclass = ExprClass.MethodGroup;
3326 public override Type DeclaringType {
3329 // We assume that the top-level type is in the end
3331 return Methods [Methods.Length - 1].DeclaringType;
3332 //return Methods [0].DeclaringType;
3336 public Type DelegateType {
3338 delegate_type = value;
3342 public bool IdenticalTypeName {
3344 return identical_type_name;
3348 identical_type_name = value;
3352 public override string GetSignatureForError ()
3354 if (best_candidate != null)
3355 return TypeManager.CSharpSignature (best_candidate);
3357 return TypeManager.CSharpSignature (Methods [0]);
3360 public override string Name {
3362 return Methods [0].Name;
3366 public override bool IsInstance {
3368 if (best_candidate != null)
3369 return !best_candidate.IsStatic;
3371 foreach (MethodBase mb in Methods)
3379 public override bool IsStatic {
3381 if (best_candidate != null)
3382 return best_candidate.IsStatic;
3384 foreach (MethodBase mb in Methods)
3392 public static explicit operator ConstructorInfo (MethodGroupExpr mg)
3394 return (ConstructorInfo)mg.best_candidate;
3397 public static explicit operator MethodInfo (MethodGroupExpr mg)
3399 return (MethodInfo)mg.best_candidate;
3403 // 7.4.3.3 Better conversion from expression
3404 // Returns : 1 if a->p is better,
3405 // 2 if a->q is better,
3406 // 0 if neither is better
3408 static int BetterExpressionConversion (EmitContext ec, Argument a, Type p, Type q)
3410 Type argument_type = TypeManager.TypeToCoreType (a.Type);
3411 if (argument_type == TypeManager.anonymous_method_type && RootContext.Version > LanguageVersion.ISO_2) {
3413 // Uwrap delegate from Expression<T>
3415 if (TypeManager.DropGenericTypeArguments (p) == TypeManager.expression_type) {
3416 p = TypeManager.GetTypeArguments (p) [0];
3417 q = TypeManager.GetTypeArguments (q) [0];
3419 p = Delegate.GetInvokeMethod (null, p).ReturnType;
3420 q = Delegate.GetInvokeMethod (null, q).ReturnType;
3422 if (argument_type == p)
3425 if (argument_type == q)
3429 return BetterTypeConversion (ec, p, q);
3433 // 7.4.3.4 Better conversion from type
3435 public static int BetterTypeConversion (EmitContext ec, Type p, Type q)
3437 if (p == null || q == null)
3438 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3440 if (p == TypeManager.int32_type) {
3441 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3443 } else if (p == TypeManager.int64_type) {
3444 if (q == TypeManager.uint64_type)
3446 } else if (p == TypeManager.sbyte_type) {
3447 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3448 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3450 } else if (p == TypeManager.short_type) {
3451 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3452 q == TypeManager.uint64_type)
3456 if (q == TypeManager.int32_type) {
3457 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3459 } if (q == TypeManager.int64_type) {
3460 if (p == TypeManager.uint64_type)
3462 } else if (q == TypeManager.sbyte_type) {
3463 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3464 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3466 } if (q == TypeManager.short_type) {
3467 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3468 p == TypeManager.uint64_type)
3472 // TODO: this is expensive
3473 Expression p_tmp = new EmptyExpression (p);
3474 Expression q_tmp = new EmptyExpression (q);
3476 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3477 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3479 if (p_to_q && !q_to_p)
3482 if (q_to_p && !p_to_q)
3489 /// Determines "Better function" between candidate
3490 /// and the current best match
3493 /// Returns a boolean indicating :
3494 /// false if candidate ain't better
3495 /// true if candidate is better than the current best match
3497 static bool BetterFunction (EmitContext ec, ArrayList args, int argument_count,
3498 MethodBase candidate, bool candidate_params,
3499 MethodBase best, bool best_params)
3501 ParameterData candidate_pd = TypeManager.GetParameterData (candidate);
3502 ParameterData best_pd = TypeManager.GetParameterData (best);
3504 bool better_at_least_one = false;
3506 for (int j = 0, c_idx = 0, b_idx = 0; j < argument_count; ++j, ++c_idx, ++b_idx)
3508 Argument a = (Argument) args [j];
3510 Type ct = TypeManager.TypeToCoreType (candidate_pd.ParameterType (c_idx));
3511 Type bt = TypeManager.TypeToCoreType (best_pd.ParameterType (b_idx));
3513 if (candidate_params && candidate_pd.ParameterModifier (c_idx) == Parameter.Modifier.PARAMS)
3515 ct = TypeManager.GetElementType (ct);
3519 if (best_params && best_pd.ParameterModifier (b_idx) == Parameter.Modifier.PARAMS)
3521 bt = TypeManager.GetElementType (bt);
3529 int result = BetterExpressionConversion (ec, a, ct, bt);
3531 // for each argument, the conversion to 'ct' should be no worse than
3532 // the conversion to 'bt'.
3536 // for at least one argument, the conversion to 'ct' should be better than
3537 // the conversion to 'bt'.
3539 better_at_least_one = true;
3542 if (better_at_least_one)
3546 // This handles the case
3548 // Add (float f1, float f2, float f3);
3549 // Add (params decimal [] foo);
3551 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3552 // first candidate would've chosen as better.
3558 // The two methods have equal parameter types. Now apply tie-breaking rules
3560 if (TypeManager.IsGenericMethod (best) && !TypeManager.IsGenericMethod (candidate))
3562 if (!TypeManager.IsGenericMethod (best) && TypeManager.IsGenericMethod (candidate))
3566 // This handles the following cases:
3568 // Trim () is better than Trim (params char[] chars)
3569 // Concat (string s1, string s2, string s3) is better than
3570 // Concat (string s1, params string [] srest)
3571 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3573 if (!candidate_params && best_params)
3575 if (candidate_params && !best_params)
3578 int candidate_param_count = candidate_pd.Count;
3579 int best_param_count = best_pd.Count;
3581 if (candidate_param_count != best_param_count)
3582 // can only happen if (candidate_params && best_params)
3583 return candidate_param_count > best_param_count;
3586 // now, both methods have the same number of parameters, and the parameters have the same types
3587 // Pick the "more specific" signature
3590 MethodBase orig_candidate = TypeManager.DropGenericMethodArguments (candidate);
3591 MethodBase orig_best = TypeManager.DropGenericMethodArguments (best);
3593 ParameterData orig_candidate_pd = TypeManager.GetParameterData (orig_candidate);
3594 ParameterData orig_best_pd = TypeManager.GetParameterData (orig_best);
3596 bool specific_at_least_once = false;
3597 for (int j = 0; j < candidate_param_count; ++j)
3599 Type ct = TypeManager.TypeToCoreType (orig_candidate_pd.ParameterType (j));
3600 Type bt = TypeManager.TypeToCoreType (orig_best_pd.ParameterType (j));
3603 Type specific = MoreSpecific (ct, bt);
3607 specific_at_least_once = true;
3610 if (specific_at_least_once)
3613 // FIXME: handle lifted operators
3619 protected override MemberExpr ResolveExtensionMemberAccess (Expression left)
3622 return base.ResolveExtensionMemberAccess (left);
3625 // When left side is an expression and at least one candidate method is
3626 // static, it can be extension method
3628 InstanceExpression = left;
3632 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3633 SimpleName original)
3635 if (!(left is TypeExpr) &&
3636 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3637 IdenticalTypeName = true;
3639 return base.ResolveMemberAccess (ec, left, loc, original);
3642 public override Expression CreateExpressionTree (EmitContext ec)
3644 return new Cast (new TypeExpression (typeof (MethodInfo), loc),
3645 new TypeOfMethod ((MethodInfo)best_candidate, loc));
3648 override public Expression DoResolve (EmitContext ec)
3650 if (InstanceExpression != null) {
3651 InstanceExpression = InstanceExpression.DoResolve (ec);
3652 if (InstanceExpression == null)
3659 public void ReportUsageError ()
3661 Report.Error (654, loc, "Method `" + DeclaringType + "." +
3662 Name + "()' is referenced without parentheses");
3665 override public void Emit (EmitContext ec)
3667 ReportUsageError ();
3670 public virtual void EmitArguments (EmitContext ec, ArrayList arguments)
3672 Invocation.EmitArguments (ec, arguments, false, null);
3675 public virtual void EmitCall (EmitContext ec, ArrayList arguments)
3677 Invocation.EmitCall (ec, IsBase, InstanceExpression, best_candidate, arguments, loc);
3680 protected virtual void Error_InvalidArguments (EmitContext ec, Location loc, int idx, MethodBase method,
3681 Argument a, ParameterData expected_par, Type paramType)
3683 if (a is CollectionElementInitializer.ElementInitializerArgument) {
3684 Report.SymbolRelatedToPreviousError (method);
3685 if ((expected_par.ParameterModifier (idx) & Parameter.Modifier.ISBYREF) != 0) {
3686 Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
3687 TypeManager.CSharpSignature (method));
3690 Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
3691 TypeManager.CSharpSignature (method));
3692 } else if (delegate_type == null) {
3693 Report.SymbolRelatedToPreviousError (method);
3694 Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
3695 TypeManager.CSharpSignature (method));
3697 Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
3698 TypeManager.CSharpName (delegate_type));
3700 Parameter.Modifier mod = expected_par.ParameterModifier (idx);
3702 string index = (idx + 1).ToString ();
3703 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
3704 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
3705 if ((mod & Parameter.Modifier.ISBYREF) == 0)
3706 Report.Error (1615, loc, "Argument `{0}' should not be passed with the `{1}' keyword",
3707 index, Parameter.GetModifierSignature (a.Modifier));
3709 Report.Error (1620, loc, "Argument `{0}' must be passed with the `{1}' keyword",
3710 index, Parameter.GetModifierSignature (mod));
3712 string p1 = a.GetSignatureForError ();
3713 string p2 = TypeManager.CSharpName (paramType);
3716 Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
3717 Report.SymbolRelatedToPreviousError (a.Expr.Type);
3718 Report.SymbolRelatedToPreviousError (paramType);
3720 Report.Error (1503, loc, "Argument {0}: Cannot convert type `{1}' to `{2}'", index, p1, p2);
3724 protected virtual int GetApplicableParametersCount (MethodBase method, ParameterData parameters)
3726 return parameters.Count;
3729 public static bool IsAncestralType (Type first_type, Type second_type)
3731 return first_type != second_type &&
3732 (TypeManager.IsSubclassOf (second_type, first_type) ||
3733 TypeManager.ImplementsInterface (second_type, first_type));
3737 /// Determines if the candidate method is applicable (section 14.4.2.1)
3738 /// to the given set of arguments
3739 /// A return value rates candidate method compatibility,
3740 /// 0 = the best, int.MaxValue = the worst
3742 public int IsApplicable (EmitContext ec,
3743 ArrayList arguments, int arg_count, ref MethodBase method, ref bool params_expanded_form)
3745 MethodBase candidate = method;
3747 ParameterData pd = TypeManager.GetParameterData (candidate);
3748 int param_count = GetApplicableParametersCount (candidate, pd);
3750 if (arg_count != param_count) {
3752 return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
3753 if (arg_count < param_count - 1)
3754 return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
3759 // 1. Handle generic method using type arguments when specified or type inference
3761 if (TypeManager.IsGenericMethod (candidate)) {
3762 if (type_arguments != null) {
3763 Type [] g_args = candidate.GetGenericArguments ();
3764 if (g_args.Length != type_arguments.Count)
3765 return int.MaxValue - 20000 + Math.Abs (type_arguments.Count - g_args.Length);
3767 // TODO: Don't create new method, create Parameters only
3768 method = ((MethodInfo) candidate).MakeGenericMethod (type_arguments.Arguments);
3770 pd = TypeManager.GetParameterData (candidate);
3772 int score = TypeManager.InferTypeArguments (ec, arguments, ref candidate);
3774 return score - 20000;
3776 if (TypeManager.IsGenericMethodDefinition (candidate))
3777 throw new InternalErrorException ("A generic method `{0}' definition took part in overload resolution",
3778 TypeManager.CSharpSignature (candidate));
3780 pd = TypeManager.GetParameterData (candidate);
3783 if (type_arguments != null)
3784 return int.MaxValue - 15000;
3789 // 2. Each argument has to be implicitly convertible to method parameter
3792 Parameter.Modifier p_mod = 0;
3794 for (int i = 0; i < arg_count; i++) {
3795 Argument a = (Argument) arguments [i];
3796 Parameter.Modifier a_mod = a.Modifier &
3797 ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3799 if (p_mod != Parameter.Modifier.PARAMS) {
3800 p_mod = pd.ParameterModifier (i) & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3802 if (p_mod == Parameter.Modifier.ARGLIST) {
3803 if (a.Type == TypeManager.runtime_argument_handle_type)
3809 pt = pd.ParameterType (i);
3811 params_expanded_form = true;
3815 if (!params_expanded_form)
3816 score = IsArgumentCompatible (ec, a_mod, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
3818 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0) {
3819 // It can be applicable in expanded form
3820 score = IsArgumentCompatible (ec, a_mod, a, 0, pt.GetElementType ());
3822 params_expanded_form = true;
3826 if (params_expanded_form)
3828 return (arg_count - i) * 2 + score;
3832 if (arg_count != param_count)
3833 params_expanded_form = true;
3838 int IsArgumentCompatible (EmitContext ec, Parameter.Modifier arg_mod, Argument argument, Parameter.Modifier param_mod, Type parameter)
3841 // Types have to be identical when ref or out modifer is used
3843 if (arg_mod != 0 || param_mod != 0) {
3844 if (TypeManager.HasElementType (parameter))
3845 parameter = parameter.GetElementType ();
3847 Type a_type = argument.Type;
3848 if (TypeManager.HasElementType (a_type))
3849 a_type = a_type.GetElementType ();
3851 if (a_type != parameter)
3857 // FIXME: Kill this abomination (EmitContext.TempEc)
3858 EmitContext prevec = EmitContext.TempEc;
3859 EmitContext.TempEc = ec;
3861 if (delegate_type != null ?
3862 !Delegate.IsTypeCovariant (argument.Expr, parameter) :
3863 !Convert.ImplicitConversionExists (ec, argument.Expr, parameter))
3866 if (arg_mod != param_mod)
3870 EmitContext.TempEc = prevec;
3876 public static bool IsOverride (MethodBase cand_method, MethodBase base_method)
3878 if (!IsAncestralType (base_method.DeclaringType, cand_method.DeclaringType))
3881 ParameterData cand_pd = TypeManager.GetParameterData (cand_method);
3882 ParameterData base_pd = TypeManager.GetParameterData (base_method);
3884 if (cand_pd.Count != base_pd.Count)
3887 for (int j = 0; j < cand_pd.Count; ++j)
3889 Parameter.Modifier cm = cand_pd.ParameterModifier (j);
3890 Parameter.Modifier bm = base_pd.ParameterModifier (j);
3891 Type ct = TypeManager.TypeToCoreType (cand_pd.ParameterType (j));
3892 Type bt = TypeManager.TypeToCoreType (base_pd.ParameterType (j));
3894 if (cm != bm || ct != bt)
3901 public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2, Location loc)
3903 MemberInfo [] miset;
3904 MethodGroupExpr union;
3909 return (MethodGroupExpr) mg2;
3912 return (MethodGroupExpr) mg1;
3915 MethodGroupExpr left_set = null, right_set = null;
3916 int length1 = 0, length2 = 0;
3918 left_set = (MethodGroupExpr) mg1;
3919 length1 = left_set.Methods.Length;
3921 right_set = (MethodGroupExpr) mg2;
3922 length2 = right_set.Methods.Length;
3924 ArrayList common = new ArrayList ();
3926 foreach (MethodBase r in right_set.Methods){
3927 if (TypeManager.ArrayContainsMethod (left_set.Methods, r))
3931 miset = new MemberInfo [length1 + length2 - common.Count];
3932 left_set.Methods.CopyTo (miset, 0);
3936 foreach (MethodBase r in right_set.Methods) {
3937 if (!common.Contains (r))
3941 union = new MethodGroupExpr (miset, mg1.Type, loc);
3946 static Type MoreSpecific (Type p, Type q)
3948 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
3950 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
3953 if (TypeManager.HasElementType (p))
3955 Type pe = TypeManager.GetElementType (p);
3956 Type qe = TypeManager.GetElementType (q);
3957 Type specific = MoreSpecific (pe, qe);
3963 else if (TypeManager.IsGenericType (p))
3965 Type[] pargs = TypeManager.GetTypeArguments (p);
3966 Type[] qargs = TypeManager.GetTypeArguments (q);
3968 bool p_specific_at_least_once = false;
3969 bool q_specific_at_least_once = false;
3971 for (int i = 0; i < pargs.Length; i++)
3973 Type specific = MoreSpecific (pargs [i], qargs [i]);
3974 if (specific == pargs [i])
3975 p_specific_at_least_once = true;
3976 if (specific == qargs [i])
3977 q_specific_at_least_once = true;
3980 if (p_specific_at_least_once && !q_specific_at_least_once)
3982 if (!p_specific_at_least_once && q_specific_at_least_once)
3990 /// Find the Applicable Function Members (7.4.2.1)
3992 /// me: Method Group expression with the members to select.
3993 /// it might contain constructors or methods (or anything
3994 /// that maps to a method).
3996 /// Arguments: ArrayList containing resolved Argument objects.
3998 /// loc: The location if we want an error to be reported, or a Null
3999 /// location for "probing" purposes.
4001 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4002 /// that is the best match of me on Arguments.
4005 public virtual MethodGroupExpr OverloadResolve (EmitContext ec, ref ArrayList Arguments,
4006 bool may_fail, Location loc)
4008 bool method_params = false;
4009 Type applicable_type = null;
4011 ArrayList candidates = new ArrayList (2);
4012 ArrayList candidate_overrides = null;
4015 // Used to keep a map between the candidate
4016 // and whether it is being considered in its
4017 // normal or expanded form
4019 // false is normal form, true is expanded form
4021 Hashtable candidate_to_form = null;
4023 if (Arguments != null)
4024 arg_count = Arguments.Count;
4026 if (RootContext.Version == LanguageVersion.ISO_1 && Name == "Invoke" && TypeManager.IsDelegateType (DeclaringType)) {
4028 Report.Error (1533, loc, "Invoke cannot be called directly on a delegate");
4032 int nmethods = Methods.Length;
4036 // Methods marked 'override' don't take part in 'applicable_type'
4037 // computation, nor in the actual overload resolution.
4038 // However, they still need to be emitted instead of a base virtual method.
4039 // So, we salt them away into the 'candidate_overrides' array.
4041 // In case of reflected methods, we replace each overriding method with
4042 // its corresponding base virtual method. This is to improve compatibility
4043 // with non-C# libraries which change the visibility of overrides (#75636)
4046 for (int i = 0; i < Methods.Length; ++i) {
4047 MethodBase m = Methods [i];
4048 if (TypeManager.IsOverride (m)) {
4049 if (candidate_overrides == null)
4050 candidate_overrides = new ArrayList ();
4051 candidate_overrides.Add (m);
4052 m = TypeManager.TryGetBaseDefinition (m);
4061 // Enable message recording, it's used mainly by lambda expressions
4063 Report.IMessageRecorder msg_recorder = new Report.MessageRecorder ();
4064 Report.IMessageRecorder prev_recorder = Report.SetMessageRecorder (msg_recorder);
4067 // First we construct the set of applicable methods
4069 bool is_sorted = true;
4070 int best_candidate_rate = int.MaxValue;
4071 for (int i = 0; i < nmethods; i++) {
4072 Type decl_type = Methods [i].DeclaringType;
4075 // If we have already found an applicable method
4076 // we eliminate all base types (Section 14.5.5.1)
4078 if (applicable_type != null && IsAncestralType (decl_type, applicable_type))
4082 // Check if candidate is applicable (section 14.4.2.1)
4084 bool params_expanded_form = false;
4085 int candidate_rate = IsApplicable (ec, Arguments, arg_count, ref Methods [i], ref params_expanded_form);
4087 if (candidate_rate < best_candidate_rate) {
4088 best_candidate_rate = candidate_rate;
4089 best_candidate = Methods [i];
4092 if (params_expanded_form) {
4093 if (candidate_to_form == null)
4094 candidate_to_form = new PtrHashtable ();
4095 MethodBase candidate = Methods [i];
4096 candidate_to_form [candidate] = candidate;
4099 if (candidate_rate != 0) {
4100 if (msg_recorder != null)
4101 msg_recorder.EndSession ();
4105 msg_recorder = null;
4106 candidates.Add (Methods [i]);
4108 if (applicable_type == null)
4109 applicable_type = decl_type;
4110 else if (applicable_type != decl_type) {
4112 if (IsAncestralType (applicable_type, decl_type))
4113 applicable_type = decl_type;
4117 Report.SetMessageRecorder (prev_recorder);
4118 if (msg_recorder != null && msg_recorder.PrintMessages ())
4121 int candidate_top = candidates.Count;
4123 if (applicable_type == null) {
4125 // When we found a top level method which does not match and it's
4126 // not an extension method. We start extension methods lookup from here
4128 if (InstanceExpression != null) {
4129 ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (type, Name);
4130 if (ex_method_lookup != null) {
4131 ex_method_lookup.ExtensionExpression = InstanceExpression;
4132 ex_method_lookup.SetTypeArguments (type_arguments);
4133 return ex_method_lookup.OverloadResolve (ec, ref Arguments, may_fail, loc);
4141 // Okay so we have failed to find exact match so we
4142 // return error info about the closest match
4144 if (best_candidate != null) {
4145 if (CustomErrorHandler != null) {
4146 if (CustomErrorHandler.NoExactMatch (ec, best_candidate))
4150 ParameterData pd = TypeManager.GetParameterData (best_candidate);
4151 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4152 if (arg_count == pd.Count || pd.HasParams) {
4153 if (TypeManager.IsGenericMethodDefinition (best_candidate)) {
4154 if (type_arguments == null) {
4155 Report.Error (411, loc,
4156 "The type arguments for method `{0}' cannot be inferred from " +
4157 "the usage. Try specifying the type arguments explicitly",
4158 TypeManager.CSharpSignature (best_candidate));
4162 Type [] g_args = TypeManager.GetGenericArguments (best_candidate);
4163 if (type_arguments.Count != g_args.Length) {
4164 Report.SymbolRelatedToPreviousError (best_candidate);
4165 Report.Error (305, loc, "Using the generic method `{0}' requires `{1}' type argument(s)",
4166 TypeManager.CSharpSignature (best_candidate),
4167 g_args.Length.ToString ());
4171 if (type_arguments != null && !TypeManager.IsGenericMethod (best_candidate)) {
4172 Namespace.Error_TypeArgumentsCannotBeUsed (best_candidate, loc);
4177 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate, cand_params, may_fail, loc))
4182 if (almost_matched_members.Count != 0) {
4183 Error_MemberLookupFailed (ec.ContainerType, type, type, ".ctor",
4184 null, MemberTypes.Constructor, AllBindingFlags);
4189 // We failed to find any method with correct argument count
4191 if (Name == ConstructorInfo.ConstructorName) {
4192 Report.SymbolRelatedToPreviousError (type);
4193 Report.Error (1729, loc,
4194 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4195 TypeManager.CSharpName (type), arg_count);
4197 Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4198 Name, arg_count.ToString ());
4206 // At this point, applicable_type is _one_ of the most derived types
4207 // in the set of types containing the methods in this MethodGroup.
4208 // Filter the candidates so that they only contain methods from the
4209 // most derived types.
4212 int finalized = 0; // Number of finalized candidates
4215 // Invariant: applicable_type is a most derived type
4217 // We'll try to complete Section 14.5.5.1 for 'applicable_type' by
4218 // eliminating all it's base types. At the same time, we'll also move
4219 // every unrelated type to the end of the array, and pick the next
4220 // 'applicable_type'.
4222 Type next_applicable_type = null;
4223 int j = finalized; // where to put the next finalized candidate
4224 int k = finalized; // where to put the next undiscarded candidate
4225 for (int i = finalized; i < candidate_top; ++i) {
4226 MethodBase candidate = (MethodBase) candidates [i];
4227 Type decl_type = candidate.DeclaringType;
4229 if (decl_type == applicable_type) {
4230 candidates [k++] = candidates [j];
4231 candidates [j++] = candidates [i];
4235 if (IsAncestralType (decl_type, applicable_type))
4238 if (next_applicable_type != null &&
4239 IsAncestralType (decl_type, next_applicable_type))
4242 candidates [k++] = candidates [i];
4244 if (next_applicable_type == null ||
4245 IsAncestralType (next_applicable_type, decl_type))
4246 next_applicable_type = decl_type;
4249 applicable_type = next_applicable_type;
4252 } while (applicable_type != null);
4256 // Now we actually find the best method
4259 best_candidate = (MethodBase) candidates [0];
4260 if (delegate_type == null)
4261 method_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4263 for (int ix = 1; ix < candidate_top; ix++) {
4264 MethodBase candidate = (MethodBase) candidates [ix];
4266 if (candidate == best_candidate)
4269 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4271 if (BetterFunction (ec, Arguments, arg_count,
4272 candidate, cand_params,
4273 best_candidate, method_params)) {
4274 best_candidate = candidate;
4275 method_params = cand_params;
4279 // Now check that there are no ambiguities i.e the selected method
4280 // should be better than all the others
4282 MethodBase ambiguous = null;
4283 for (int ix = 1; ix < candidate_top; ix++) {
4284 MethodBase candidate = (MethodBase) candidates [ix];
4286 if (candidate == best_candidate)
4289 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4290 if (!BetterFunction (ec, Arguments, arg_count,
4291 best_candidate, method_params,
4292 candidate, cand_params))
4295 Report.SymbolRelatedToPreviousError (candidate);
4296 ambiguous = candidate;
4300 if (ambiguous != null) {
4301 Report.SymbolRelatedToPreviousError (best_candidate);
4302 Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4303 TypeManager.CSharpSignature (ambiguous), TypeManager.CSharpSignature (best_candidate));
4308 // If the method is a virtual function, pick an override closer to the LHS type.
4310 if (!IsBase && best_candidate.IsVirtual) {
4311 if (TypeManager.IsOverride (best_candidate))
4312 throw new InternalErrorException (
4313 "Should not happen. An 'override' method took part in overload resolution: " + best_candidate);
4315 if (candidate_overrides != null) {
4316 Type[] gen_args = null;
4317 bool gen_override = false;
4318 if (TypeManager.IsGenericMethod (best_candidate))
4319 gen_args = TypeManager.GetGenericArguments (best_candidate);
4321 foreach (MethodBase candidate in candidate_overrides) {
4322 if (TypeManager.IsGenericMethod (candidate)) {
4323 if (gen_args == null)
4326 if (gen_args.Length != TypeManager.GetGenericArguments (candidate).Length)
4329 if (gen_args != null)
4333 if (IsOverride (candidate, best_candidate)) {
4334 gen_override = true;
4335 best_candidate = candidate;
4339 if (gen_override && gen_args != null) {
4341 best_candidate = ((MethodInfo) best_candidate).MakeGenericMethod (gen_args);
4348 // And now check if the arguments are all
4349 // compatible, perform conversions if
4350 // necessary etc. and return if everything is
4353 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate,
4354 method_params, may_fail, loc))
4357 if (best_candidate == null)
4360 MethodBase the_method = TypeManager.DropGenericMethodArguments (best_candidate);
4362 if (the_method.IsGenericMethodDefinition &&
4363 !ConstraintChecker.CheckConstraints (ec, the_method, best_candidate, loc))
4367 IMethodData data = TypeManager.GetMethod (the_method);
4369 data.SetMemberIsUsed ();
4374 public override void SetTypeArguments (TypeArguments ta)
4376 type_arguments = ta;
4379 public bool VerifyArgumentsCompat (EmitContext ec, ref ArrayList arguments,
4380 int arg_count, MethodBase method,
4381 bool chose_params_expanded,
4382 bool may_fail, Location loc)
4384 ParameterData pd = TypeManager.GetParameterData (method);
4386 int errors = Report.Errors;
4387 Parameter.Modifier p_mod = 0;
4389 int a_idx = 0, a_pos = 0;
4391 ArrayList params_initializers = null;
4393 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4394 a = (Argument) arguments [a_idx];
4395 if (p_mod != Parameter.Modifier.PARAMS) {
4396 p_mod = pd.ParameterModifier (a_idx);
4397 pt = pd.ParameterType (a_idx);
4399 if (p_mod == Parameter.Modifier.ARGLIST) {
4400 if (a.Type != TypeManager.runtime_argument_handle_type)
4405 if (pt.IsPointer && !ec.InUnsafe) {
4412 if (p_mod == Parameter.Modifier.PARAMS) {
4413 if (chose_params_expanded) {
4414 params_initializers = new ArrayList (arg_count - a_idx);
4415 pt = TypeManager.GetElementType (pt);
4417 } else if (p_mod != 0) {
4418 pt = TypeManager.GetElementType (pt);
4423 // Types have to be identical when ref or out modifer is used
4425 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4426 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4429 if (!TypeManager.IsEqual (a.Expr.Type, pt))
4436 if (TypeManager.IsEqual (a.Type, pt)) {
4439 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4445 // Convert params arguments to an array initializer
4447 if (params_initializers != null) {
4448 params_initializers.Add (conv);
4449 arguments.RemoveAt (a_idx--);
4454 // Update the argument with the implicit conversion
4459 // Fill not provided arguments required by params modifier
4461 if (params_initializers == null && pd.HasParams && arg_count < pd.Count && a_idx + 1 == pd.Count) {
4462 if (arguments == null)
4463 arguments = new ArrayList (1);
4465 pt = pd.Types [GetApplicableParametersCount (method, pd) - 1];
4466 pt = TypeManager.GetElementType (pt);
4467 params_initializers = new ArrayList (0);
4470 if (a_idx == arg_count) {
4472 // Append an array argument with all params arguments
4474 if (params_initializers != null) {
4475 arguments.Add (new Argument (
4476 new ArrayCreation (new TypeExpression (pt, loc), "[]",
4477 params_initializers, loc).Resolve (ec)));
4482 if (!may_fail && Report.Errors == errors) {
4483 if (CustomErrorHandler != null)
4484 CustomErrorHandler.NoExactMatch (ec, best_candidate);
4486 Error_InvalidArguments (ec, loc, a_pos, method, a, pd, pt);
4492 public class ConstantExpr : MemberExpr
4496 public ConstantExpr (FieldInfo constant, Location loc)
4498 this.constant = constant;
4502 public override string Name {
4503 get { throw new NotImplementedException (); }
4506 public override bool IsInstance {
4507 get { return !IsStatic; }
4510 public override bool IsStatic {
4511 get { return constant.IsStatic; }
4514 public override Type DeclaringType {
4515 get { return constant.DeclaringType; }
4518 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc, SimpleName original)
4520 constant = TypeManager.GetGenericFieldDefinition (constant);
4522 IConstant ic = TypeManager.GetConstant (constant);
4524 if (constant.IsLiteral) {
4525 ic = new ExternalConstant (constant);
4527 ic = ExternalConstant.CreateDecimal (constant);
4528 // HACK: decimal field was not resolved as constant
4530 return new FieldExpr (constant, loc).ResolveMemberAccess (ec, left, loc, original);
4532 TypeManager.RegisterConstant (constant, ic);
4535 return base.ResolveMemberAccess (ec, left, loc, original);
4538 public override Expression DoResolve (EmitContext ec)
4540 IConstant ic = TypeManager.GetConstant (constant);
4541 if (ic.ResolveValue ()) {
4542 if (!ec.IsInObsoleteScope)
4543 ic.CheckObsoleteness (loc);
4546 return ic.CreateConstantReference (loc);
4549 public override void Emit (EmitContext ec)
4551 throw new NotSupportedException ();
4554 public override string GetSignatureForError ()
4556 return TypeManager.GetFullNameSignature (constant);
4561 /// Fully resolved expression that evaluates to a Field
4563 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariable {
4564 public readonly FieldInfo FieldInfo;
4565 VariableInfo variable_info;
4567 LocalTemporary temp;
4569 bool in_initializer;
4571 public FieldExpr (FieldInfo fi, Location l, bool in_initializer):
4574 this.in_initializer = in_initializer;
4577 public FieldExpr (FieldInfo fi, Location l)
4580 eclass = ExprClass.Variable;
4581 type = TypeManager.TypeToCoreType (fi.FieldType);
4585 public override string Name {
4587 return FieldInfo.Name;
4591 public override bool IsInstance {
4593 return !FieldInfo.IsStatic;
4597 public override bool IsStatic {
4599 return FieldInfo.IsStatic;
4603 public override Type DeclaringType {
4605 return FieldInfo.DeclaringType;
4609 public override string GetSignatureForError ()
4611 return TypeManager.GetFullNameSignature (FieldInfo);
4614 public VariableInfo VariableInfo {
4616 return variable_info;
4620 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
4621 SimpleName original)
4623 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
4624 Type t = fi.FieldType;
4626 if (t.IsPointer && !ec.InUnsafe) {
4630 return base.ResolveMemberAccess (ec, left, loc, original);
4633 override public Expression DoResolve (EmitContext ec)
4635 return DoResolve (ec, false, false);
4638 Expression DoResolve (EmitContext ec, bool lvalue_instance, bool out_access)
4640 if (!FieldInfo.IsStatic){
4641 if (InstanceExpression == null){
4643 // This can happen when referencing an instance field using
4644 // a fully qualified type expression: TypeName.InstanceField = xxx
4646 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4650 // Resolve the field's instance expression while flow analysis is turned
4651 // off: when accessing a field "a.b", we must check whether the field
4652 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4654 if (lvalue_instance) {
4655 using (ec.With (EmitContext.Flags.DoFlowAnalysis, false)) {
4656 Expression right_side =
4657 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4658 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side, loc);
4661 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
4662 InstanceExpression = InstanceExpression.Resolve (ec, rf);
4665 if (InstanceExpression == null)
4668 using (ec.Set (EmitContext.Flags.OmitStructFlowAnalysis)) {
4669 InstanceExpression.CheckMarshalByRefAccess (ec);
4673 if (!in_initializer && !ec.IsInFieldInitializer) {
4674 ObsoleteAttribute oa;
4675 FieldBase f = TypeManager.GetField (FieldInfo);
4677 if (!ec.IsInObsoleteScope)
4678 f.CheckObsoleteness (loc);
4680 // To be sure that type is external because we do not register generated fields
4681 } else if (!(FieldInfo.DeclaringType is TypeBuilder)) {
4682 oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
4684 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
4688 AnonymousContainer am = ec.CurrentAnonymousMethod;
4690 if (!FieldInfo.IsStatic){
4691 if (!am.IsIterator && (ec.TypeContainer is Struct)){
4692 Report.Error (1673, loc,
4693 "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",
4700 IFixedBuffer fb = AttributeTester.GetFixedBuffer (FieldInfo);
4702 if (!ec.InFixedInitializer && ec.ContainerType.IsValueType) {
4703 Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4706 if (InstanceExpression.eclass != ExprClass.Variable) {
4707 Report.SymbolRelatedToPreviousError (FieldInfo);
4708 Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4709 TypeManager.GetFullNameSignature (FieldInfo));
4712 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4715 // If the instance expression is a local variable or parameter.
4716 IVariable var = InstanceExpression as IVariable;
4717 if ((var == null) || (var.VariableInfo == null))
4720 VariableInfo vi = var.VariableInfo;
4721 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
4724 variable_info = vi.GetSubStruct (FieldInfo.Name);
4728 static readonly int [] codes = {
4729 191, // instance, write access
4730 192, // instance, out access
4731 198, // static, write access
4732 199, // static, out access
4733 1648, // member of value instance, write access
4734 1649, // member of value instance, out access
4735 1650, // member of value static, write access
4736 1651 // member of value static, out access
4739 static readonly string [] msgs = {
4740 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4741 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4742 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4743 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4744 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4745 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4746 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4747 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4750 // The return value is always null. Returning a value simplifies calling code.
4751 Expression Report_AssignToReadonly (Expression right_side)
4754 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4758 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4760 Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4765 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4767 IVariable var = InstanceExpression as IVariable;
4768 if ((var != null) && (var.VariableInfo != null))
4769 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
4771 bool lvalue_instance = !FieldInfo.IsStatic && FieldInfo.DeclaringType.IsValueType;
4772 bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
4774 Expression e = DoResolve (ec, lvalue_instance, out_access);
4779 FieldBase fb = TypeManager.GetField (FieldInfo);
4783 if (FieldInfo.IsInitOnly) {
4784 // InitOnly fields can only be assigned in constructors or initializers
4785 if (!ec.IsInFieldInitializer && !ec.IsConstructor)
4786 return Report_AssignToReadonly (right_side);
4788 if (ec.IsConstructor) {
4789 Type ctype = ec.TypeContainer.CurrentType;
4791 ctype = ec.ContainerType;
4793 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4794 if (!TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
4795 return Report_AssignToReadonly (right_side);
4796 // static InitOnly fields cannot be assigned-to in an instance constructor
4797 if (IsStatic && !ec.IsStatic)
4798 return Report_AssignToReadonly (right_side);
4799 // instance constructors can't modify InitOnly fields of other instances of the same type
4800 if (!IsStatic && !(InstanceExpression is This))
4801 return Report_AssignToReadonly (right_side);
4805 if (right_side == EmptyExpression.OutAccess &&
4806 !IsStatic && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type)) {
4807 Report.SymbolRelatedToPreviousError (DeclaringType);
4808 Report.Warning (197, 1, loc,
4809 "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",
4810 GetSignatureForError ());
4816 public override void CheckMarshalByRefAccess (EmitContext ec)
4818 if (!IsStatic && Type.IsValueType && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type)) {
4819 Report.SymbolRelatedToPreviousError (DeclaringType);
4820 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",
4821 GetSignatureForError ());
4825 public bool VerifyFixed ()
4827 IVariable variable = InstanceExpression as IVariable;
4828 // A variable of the form V.I is fixed when V is a fixed variable of a struct type.
4829 // We defer the InstanceExpression check after the variable check to avoid a
4830 // separate null check on InstanceExpression.
4831 return variable != null && InstanceExpression.Type.IsValueType && variable.VerifyFixed ();
4834 public override int GetHashCode ()
4836 return FieldInfo.GetHashCode ();
4839 public override bool Equals (object obj)
4841 FieldExpr fe = obj as FieldExpr;
4845 if (FieldInfo != fe.FieldInfo)
4848 if (InstanceExpression == null || fe.InstanceExpression == null)
4851 return InstanceExpression.Equals (fe.InstanceExpression);
4854 public void Emit (EmitContext ec, bool leave_copy)
4856 ILGenerator ig = ec.ig;
4857 bool is_volatile = false;
4859 FieldBase f = TypeManager.GetField (FieldInfo);
4861 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4864 f.SetMemberIsUsed ();
4867 if (FieldInfo.IsStatic){
4869 ig.Emit (OpCodes.Volatile);
4871 ig.Emit (OpCodes.Ldsfld, FieldInfo);
4874 EmitInstance (ec, false);
4876 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
4878 ig.Emit (OpCodes.Ldflda, FieldInfo);
4879 ig.Emit (OpCodes.Ldflda, ff.Element);
4882 ig.Emit (OpCodes.Volatile);
4884 ig.Emit (OpCodes.Ldfld, FieldInfo);
4889 ec.ig.Emit (OpCodes.Dup);
4890 if (!FieldInfo.IsStatic) {
4891 temp = new LocalTemporary (this.Type);
4897 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4899 FieldAttributes fa = FieldInfo.Attributes;
4900 bool is_static = (fa & FieldAttributes.Static) != 0;
4901 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
4902 ILGenerator ig = ec.ig;
4904 if (is_readonly && !ec.IsConstructor){
4905 Report_AssignToReadonly (source);
4910 // String concatenation creates a new string instance
4912 prepared = prepare_for_load && !(source is StringConcat);
4913 EmitInstance (ec, prepared);
4917 ec.ig.Emit (OpCodes.Dup);
4918 if (!FieldInfo.IsStatic) {
4919 temp = new LocalTemporary (this.Type);
4924 FieldBase f = TypeManager.GetField (FieldInfo);
4926 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4927 ig.Emit (OpCodes.Volatile);
4933 ig.Emit (OpCodes.Stsfld, FieldInfo);
4935 ig.Emit (OpCodes.Stfld, FieldInfo);
4943 public override void Emit (EmitContext ec)
4948 public void AddressOf (EmitContext ec, AddressOp mode)
4950 ILGenerator ig = ec.ig;
4952 FieldBase f = TypeManager.GetField (FieldInfo);
4954 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
4955 Report.Warning (420, 1, loc, "`{0}': A volatile field references will not be treated as volatile",
4956 f.GetSignatureForError ());
4959 if ((mode & AddressOp.Store) != 0)
4961 if ((mode & AddressOp.Load) != 0)
4962 f.SetMemberIsUsed ();
4966 // Handle initonly fields specially: make a copy and then
4967 // get the address of the copy.
4970 if (FieldInfo.IsInitOnly){
4972 if (ec.IsConstructor){
4973 if (FieldInfo.IsStatic){
4985 local = ig.DeclareLocal (type);
4986 ig.Emit (OpCodes.Stloc, local);
4987 ig.Emit (OpCodes.Ldloca, local);
4992 if (FieldInfo.IsStatic){
4993 ig.Emit (OpCodes.Ldsflda, FieldInfo);
4996 EmitInstance (ec, false);
4997 ig.Emit (OpCodes.Ldflda, FieldInfo);
5004 /// Expression that evaluates to a Property. The Assign class
5005 /// might set the `Value' expression if we are in an assignment.
5007 /// This is not an LValue because we need to re-write the expression, we
5008 /// can not take data from the stack and store it.
5010 public class PropertyExpr : MemberExpr, IAssignMethod {
5011 public readonly PropertyInfo PropertyInfo;
5012 MethodInfo getter, setter;
5017 LocalTemporary temp;
5020 public PropertyExpr (Type container_type, PropertyInfo pi, Location l)
5023 eclass = ExprClass.PropertyAccess;
5027 type = TypeManager.TypeToCoreType (pi.PropertyType);
5029 ResolveAccessors (container_type);
5032 public override string Name {
5034 return PropertyInfo.Name;
5038 public override bool IsInstance {
5044 public override bool IsStatic {
5050 public override Expression CreateExpressionTree (EmitContext ec)
5052 if (IsSingleDimensionalArrayLength ()) {
5053 ArrayList args = new ArrayList (1);
5054 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5055 return CreateExpressionFactoryCall ("ArrayLength", args);
5058 // TODO: it's waiting for PropertyExpr refactoring
5059 //ArrayList args = new ArrayList (2);
5060 //args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5061 //args.Add (getter expression);
5062 //return CreateExpressionFactoryCall ("Property", args);
5063 return base.CreateExpressionTree (ec);
5066 public override Type DeclaringType {
5068 return PropertyInfo.DeclaringType;
5072 public override string GetSignatureForError ()
5074 return TypeManager.GetFullNameSignature (PropertyInfo);
5077 void FindAccessors (Type invocation_type)
5079 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
5080 BindingFlags.Static | BindingFlags.Instance |
5081 BindingFlags.DeclaredOnly;
5083 Type current = PropertyInfo.DeclaringType;
5084 for (; current != null; current = current.BaseType) {
5085 MemberInfo[] group = TypeManager.MemberLookup (
5086 invocation_type, invocation_type, current,
5087 MemberTypes.Property, flags, PropertyInfo.Name, null);
5092 if (group.Length != 1)
5093 // Oooops, can this ever happen ?
5096 PropertyInfo pi = (PropertyInfo) group [0];
5099 getter = pi.GetGetMethod (true);
5102 setter = pi.GetSetMethod (true);
5104 MethodInfo accessor = getter != null ? getter : setter;
5106 if (!accessor.IsVirtual)
5112 // We also perform the permission checking here, as the PropertyInfo does not
5113 // hold the information for the accessibility of its setter/getter
5115 // TODO: Refactor to use some kind of cache together with GetPropertyFromAccessor
5116 void ResolveAccessors (Type container_type)
5118 FindAccessors (container_type);
5120 if (getter != null) {
5121 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
5122 IMethodData md = TypeManager.GetMethod (the_getter);
5124 md.SetMemberIsUsed ();
5126 is_static = getter.IsStatic;
5129 if (setter != null) {
5130 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
5131 IMethodData md = TypeManager.GetMethod (the_setter);
5133 md.SetMemberIsUsed ();
5135 is_static = setter.IsStatic;
5139 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
5142 InstanceExpression = null;
5146 if (InstanceExpression == null) {
5147 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5151 InstanceExpression = InstanceExpression.DoResolve (ec);
5152 if (lvalue_instance && InstanceExpression != null)
5153 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
5155 if (InstanceExpression == null)
5158 InstanceExpression.CheckMarshalByRefAccess (ec);
5160 if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) &&
5161 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
5162 !TypeManager.IsNestedChildOf (ec.ContainerType, InstanceExpression.Type) &&
5163 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.ContainerType)) {
5164 Report.SymbolRelatedToPreviousError (PropertyInfo);
5165 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
5172 void Error_PropertyNotFound (MethodInfo mi, bool getter)
5174 // TODO: correctly we should compare arguments but it will lead to bigger changes
5175 if (mi is MethodBuilder) {
5176 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
5180 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
5182 ParameterData iparams = TypeManager.GetParameterData (mi);
5183 sig.Append (getter ? "get_" : "set_");
5185 sig.Append (iparams.GetSignatureForError ());
5187 Report.SymbolRelatedToPreviousError (mi);
5188 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
5189 Name, sig.ToString ());
5192 public bool IsAccessibleFrom (Type invocation_type, bool lvalue)
5195 MethodInfo accessor = lvalue ? setter : getter;
5196 if (accessor == null && lvalue)
5198 return accessor != null && IsAccessorAccessible (invocation_type, accessor, out dummy);
5201 bool IsSingleDimensionalArrayLength ()
5203 if (DeclaringType != TypeManager.array_type || getter == null || Name != "Length")
5206 string t_name = InstanceExpression.Type.Name;
5207 int t_name_len = t_name.Length;
5208 return t_name_len > 2 && t_name [t_name_len - 2] == '[' && t_name [t_name_len - 3] != ']';
5211 override public Expression DoResolve (EmitContext ec)
5216 if (getter != null){
5217 if (TypeManager.GetParameterData (getter).Count != 0){
5218 Error_PropertyNotFound (getter, true);
5223 if (getter == null){
5225 // The following condition happens if the PropertyExpr was
5226 // created, but is invalid (ie, the property is inaccessible),
5227 // and we did not want to embed the knowledge about this in
5228 // the caller routine. This only avoids double error reporting.
5233 if (InstanceExpression != EmptyExpression.Null) {
5234 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5235 TypeManager.GetFullNameSignature (PropertyInfo));
5240 bool must_do_cs1540_check = false;
5241 if (getter != null &&
5242 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
5243 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
5244 if (pm != null && pm.HasCustomAccessModifier) {
5245 Report.SymbolRelatedToPreviousError (pm);
5246 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5247 TypeManager.CSharpSignature (getter));
5250 Report.SymbolRelatedToPreviousError (getter);
5251 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
5256 if (!InstanceResolve (ec, false, must_do_cs1540_check))
5260 // Only base will allow this invocation to happen.
5262 if (IsBase && getter.IsAbstract) {
5263 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5267 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
5277 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
5279 if (right_side == EmptyExpression.OutAccess) {
5280 if (ec.CurrentBlock.Toplevel.GetTransparentIdentifier (PropertyInfo.Name) != null) {
5281 Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5284 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as `ref' or `out' parameter",
5285 GetSignatureForError ());
5290 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5291 Error_CannotModifyIntermediateExpressionValue (ec);
5294 if (setter == null){
5296 // The following condition happens if the PropertyExpr was
5297 // created, but is invalid (ie, the property is inaccessible),
5298 // and we did not want to embed the knowledge about this in
5299 // the caller routine. This only avoids double error reporting.
5303 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
5304 GetSignatureForError ());
5308 if (TypeManager.GetParameterData (setter).Count != 1){
5309 Error_PropertyNotFound (setter, false);
5313 bool must_do_cs1540_check;
5314 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
5315 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
5316 if (pm != null && pm.HasCustomAccessModifier) {
5317 Report.SymbolRelatedToPreviousError (pm);
5318 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5319 TypeManager.CSharpSignature (setter));
5322 Report.SymbolRelatedToPreviousError (setter);
5323 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
5328 if (!InstanceResolve (ec, PropertyInfo.DeclaringType.IsValueType, must_do_cs1540_check))
5332 // Only base will allow this invocation to happen.
5334 if (IsBase && setter.IsAbstract){
5335 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5342 public override void Emit (EmitContext ec)
5347 public void Emit (EmitContext ec, bool leave_copy)
5350 // Special case: length of single dimension array property is turned into ldlen
5352 if (IsSingleDimensionalArrayLength ()) {
5354 EmitInstance (ec, false);
5355 ec.ig.Emit (OpCodes.Ldlen);
5356 ec.ig.Emit (OpCodes.Conv_I4);
5360 Invocation.EmitCall (ec, IsBase, InstanceExpression, getter, null, loc, prepared, false);
5363 ec.ig.Emit (OpCodes.Dup);
5365 temp = new LocalTemporary (this.Type);
5372 // Implements the IAssignMethod interface for assignments
5374 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5376 Expression my_source = source;
5378 if (prepare_for_load) {
5379 if (source is StringConcat)
5380 EmitInstance (ec, false);
5388 ec.ig.Emit (OpCodes.Dup);
5390 temp = new LocalTemporary (this.Type);
5394 } else if (leave_copy) {
5396 temp = new LocalTemporary (this.Type);
5401 ArrayList args = new ArrayList (1);
5402 args.Add (new Argument (my_source, Argument.AType.Expression));
5404 Invocation.EmitCall (ec, IsBase, InstanceExpression, setter, args, loc, false, prepared);
5414 /// Fully resolved expression that evaluates to an Event
5416 public class EventExpr : MemberExpr {
5417 public readonly EventInfo EventInfo;
5420 MethodInfo add_accessor, remove_accessor;
5422 public EventExpr (EventInfo ei, Location loc)
5426 eclass = ExprClass.EventAccess;
5428 add_accessor = TypeManager.GetAddMethod (ei);
5429 remove_accessor = TypeManager.GetRemoveMethod (ei);
5430 if (add_accessor.IsStatic || remove_accessor.IsStatic)
5433 if (EventInfo is MyEventBuilder){
5434 MyEventBuilder eb = (MyEventBuilder) EventInfo;
5435 type = eb.EventType;
5438 type = EventInfo.EventHandlerType;
5441 public override string Name {
5443 return EventInfo.Name;
5447 public override bool IsInstance {
5453 public override bool IsStatic {
5459 public override Type DeclaringType {
5461 return EventInfo.DeclaringType;
5465 void Error_AssignmentEventOnly ()
5467 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5468 GetSignatureForError ());
5471 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
5472 SimpleName original)
5475 // If the event is local to this class, we transform ourselves into a FieldExpr
5478 if (EventInfo.DeclaringType == ec.ContainerType ||
5479 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
5480 EventField mi = TypeManager.GetEventField (EventInfo);
5483 if (!ec.IsInObsoleteScope)
5484 mi.CheckObsoleteness (loc);
5486 if ((mi.ModFlags & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0 && !ec.IsInCompoundAssignment)
5487 Error_AssignmentEventOnly ();
5489 FieldExpr ml = new FieldExpr (mi.FieldBuilder, loc);
5491 InstanceExpression = null;
5493 return ml.ResolveMemberAccess (ec, left, loc, original);
5497 if (left is This && !ec.IsInCompoundAssignment)
5498 Error_AssignmentEventOnly ();
5500 return base.ResolveMemberAccess (ec, left, loc, original);
5504 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
5507 InstanceExpression = null;
5511 if (InstanceExpression == null) {
5512 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5516 InstanceExpression = InstanceExpression.DoResolve (ec);
5517 if (InstanceExpression == null)
5520 if (IsBase && add_accessor.IsAbstract) {
5521 Error_CannotCallAbstractBase(TypeManager.CSharpSignature(add_accessor));
5526 // This is using the same mechanism as the CS1540 check in PropertyExpr.
5527 // However, in the Event case, we reported a CS0122 instead.
5529 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
5530 InstanceExpression.Type != ec.ContainerType &&
5531 TypeManager.IsSubclassOf (ec.ContainerType, InstanceExpression.Type)) {
5532 Report.SymbolRelatedToPreviousError (EventInfo);
5533 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5540 public bool IsAccessibleFrom (Type invocation_type)
5543 return IsAccessorAccessible (invocation_type, add_accessor, out dummy) &&
5544 IsAccessorAccessible (invocation_type, remove_accessor, out dummy);
5547 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5549 return DoResolve (ec);
5552 public override Expression DoResolve (EmitContext ec)
5554 bool must_do_cs1540_check;
5555 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
5556 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
5557 Report.SymbolRelatedToPreviousError (EventInfo);
5558 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5562 if (!InstanceResolve (ec, must_do_cs1540_check))
5568 public override void Emit (EmitContext ec)
5570 Report.Error (70, loc, "The event `{0}' can only appear on the left hand side of += or -= "+
5571 "(except on the defining type)", GetSignatureForError ());
5574 public override string GetSignatureForError ()
5576 return TypeManager.CSharpSignature (EventInfo);
5579 public void EmitAddOrRemove (EmitContext ec, Expression source)
5581 BinaryDelegate source_del = source as BinaryDelegate;
5582 if (source_del == null) {
5586 Expression handler = source_del.Right;
5588 Argument arg = new Argument (handler, Argument.AType.Expression);
5589 ArrayList args = new ArrayList ();
5593 if (source_del.IsAddition)
5594 Invocation.EmitCall (
5595 ec, IsBase, InstanceExpression, add_accessor, args, loc);
5597 Invocation.EmitCall (
5598 ec, IsBase, InstanceExpression, remove_accessor, args, loc);
5602 public class TemporaryVariable : Expression, IMemoryLocation
5607 public TemporaryVariable (Type type, Location loc)
5611 eclass = ExprClass.Value;
5614 public override Expression DoResolve (EmitContext ec)
5619 TypeExpr te = new TypeExpression (type, loc);
5620 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
5621 if (!li.Resolve (ec))
5624 if (ec.MustCaptureVariable (li)) {
5625 ScopeInfo scope = li.Block.CreateScopeInfo ();
5626 var = scope.AddLocal (li);
5633 public Variable Variable {
5634 get { return var != null ? var : li.Variable; }
5637 public override void Emit (EmitContext ec)
5639 Variable.EmitInstance (ec);
5643 public void EmitLoadAddress (EmitContext ec)
5645 Variable.EmitInstance (ec);
5646 Variable.EmitAddressOf (ec);
5649 public void Store (EmitContext ec, Expression right_side)
5651 Variable.EmitInstance (ec);
5652 right_side.Emit (ec);
5653 Variable.EmitAssign (ec);
5656 public void EmitThis (EmitContext ec)
5658 Variable.EmitInstance (ec);
5661 public void EmitStore (EmitContext ec)
5663 Variable.EmitAssign (ec);
5666 public void AddressOf (EmitContext ec, AddressOp mode)
5668 EmitLoadAddress (ec);
5673 /// Handles `var' contextual keyword; var becomes a keyword only
5674 /// if no type called var exists in a variable scope
5676 public class VarExpr : SimpleName
5678 // Used for error reporting only
5679 ArrayList initializer;
5681 public VarExpr (Location loc)
5686 public ArrayList VariableInitializer {
5688 this.initializer = value;
5692 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5695 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
5697 type = right_side.Type;
5698 if (type == TypeManager.null_type || type == TypeManager.void_type || type == TypeManager.anonymous_method_type) {
5699 Report.Error (815, loc, "An implicitly typed local variable declaration cannot be initialized with `{0}'",
5700 right_side.GetSignatureForError ());
5704 eclass = ExprClass.Variable;
5708 protected override void Error_TypeOrNamespaceNotFound (IResolveContext ec)
5710 Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");
5713 public override TypeExpr ResolveAsContextualType (IResolveContext rc, bool silent)
5715 TypeExpr te = base.ResolveAsContextualType (rc, true);
5719 if (initializer == null)
5722 if (initializer.Count > 1) {
5723 Location loc = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [1]).Location;
5724 Report.Error (819, loc, "An implicitly typed local variable declaration cannot include multiple declarators");
5729 Expression variable_initializer = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [0]).expression_or_array_initializer;
5730 if (variable_initializer == null) {
5731 Report.Error (818, loc, "An implicitly typed local variable declarator must include an initializer");