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);
1324 return new EmptyCast (child, type);
1327 public override Expression CreateExpressionTree (EmitContext ec)
1329 ArrayList args = new ArrayList (2);
1330 args.Add (new Argument (child.CreateExpressionTree (ec)));
1331 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1332 return CreateExpressionFactoryCall (ec.CheckState ? "ConvertChecked" : "Convert", args);
1335 public override Expression DoResolve (EmitContext ec)
1337 // This should never be invoked, we are born in fully
1338 // initialized state.
1343 public override void Emit (EmitContext ec)
1348 public override bool GetAttributableValue (Type value_type, out object value)
1350 return child.GetAttributableValue (value_type, out value);
1353 protected override void CloneTo (CloneContext clonectx, Expression t)
1355 EmptyCast target = (EmptyCast) t;
1357 target.child = child.Clone (clonectx);
1362 /// Performs a cast using an operator (op_Explicit or op_Implicit)
1364 public class OperatorCast : EmptyCast {
1365 MethodInfo conversion_operator;
1368 public OperatorCast (Expression child, Type target_type) : this (child, target_type, false) {}
1370 public OperatorCast (Expression child, Type target_type, bool find_explicit)
1371 : base (child, target_type)
1373 this.find_explicit = find_explicit;
1376 // Returns the implicit operator that converts from
1377 // 'child.Type' to our target type (type)
1378 MethodInfo GetConversionOperator (bool find_explicit)
1380 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1384 mi = TypeManager.MemberLookup (child.Type, child.Type, child.Type, MemberTypes.Method,
1385 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1388 mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1389 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1392 foreach (MethodInfo oper in mi) {
1393 ParameterData pd = TypeManager.GetParameterData (oper);
1395 if (pd.ParameterType (0) == child.Type && TypeManager.TypeToCoreType (oper.ReturnType) == type)
1403 public override void Emit (EmitContext ec)
1405 ILGenerator ig = ec.ig;
1408 conversion_operator = GetConversionOperator (find_explicit);
1410 if (conversion_operator == null)
1411 throw new InternalErrorException ("Outer conversion routine is out of sync");
1413 ig.Emit (OpCodes.Call, conversion_operator);
1419 /// This is a numeric cast to a Decimal
1421 public class CastToDecimal : EmptyCast {
1422 MethodInfo conversion_operator;
1424 public CastToDecimal (Expression child)
1425 : this (child, false)
1429 public CastToDecimal (Expression child, bool find_explicit)
1430 : base (child, TypeManager.decimal_type)
1432 conversion_operator = GetConversionOperator (find_explicit);
1434 if (conversion_operator == null)
1435 throw new InternalErrorException ("Outer conversion routine is out of sync");
1438 // Returns the implicit operator that converts from
1439 // 'child.Type' to System.Decimal.
1440 MethodInfo GetConversionOperator (bool find_explicit)
1442 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1444 MemberInfo [] mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1445 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1447 foreach (MethodInfo oper in mi) {
1448 ParameterData pd = TypeManager.GetParameterData (oper);
1450 if (pd.ParameterType (0) == child.Type && TypeManager.TypeToCoreType (oper.ReturnType) == type)
1456 public override void Emit (EmitContext ec)
1458 ILGenerator ig = ec.ig;
1461 ig.Emit (OpCodes.Call, conversion_operator);
1466 /// This is an explicit numeric cast from a Decimal
1468 public class CastFromDecimal : EmptyCast
1470 static IDictionary operators;
1472 public CastFromDecimal (Expression child, Type return_type)
1473 : base (child, return_type)
1475 if (child.Type != TypeManager.decimal_type)
1476 throw new InternalErrorException (
1477 "The expected type is Decimal, instead it is " + child.Type.FullName);
1480 // Returns the explicit operator that converts from an
1481 // express of type System.Decimal to 'type'.
1482 public Expression Resolve ()
1484 if (operators == null) {
1485 MemberInfo[] all_oper = TypeManager.MemberLookup (TypeManager.decimal_type,
1486 TypeManager.decimal_type, TypeManager.decimal_type, MemberTypes.Method,
1487 BindingFlags.Static | BindingFlags.Public, "op_Explicit", null);
1489 operators = new System.Collections.Specialized.HybridDictionary ();
1490 foreach (MethodInfo oper in all_oper) {
1491 ParameterData pd = TypeManager.GetParameterData (oper);
1492 if (pd.ParameterType (0) == TypeManager.decimal_type)
1493 operators.Add (TypeManager.TypeToCoreType (oper.ReturnType), oper);
1497 return operators.Contains (type) ? this : null;
1500 public override void Emit (EmitContext ec)
1502 ILGenerator ig = ec.ig;
1505 ig.Emit (OpCodes.Call, (MethodInfo)operators [type]);
1511 // Constant specialization of EmptyCast.
1512 // We need to special case this since an empty cast of
1513 // a constant is still a constant.
1515 public class EmptyConstantCast : Constant
1517 public readonly Constant child;
1519 public EmptyConstantCast(Constant child, Type type)
1520 : base (child.Location)
1522 eclass = child.eclass;
1527 public override string AsString ()
1529 return child.AsString ();
1532 public override object GetValue ()
1534 return child.GetValue ();
1537 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
1539 // FIXME: check that 'type' can be converted to 'target_type' first
1540 return child.ConvertExplicitly (in_checked_context, target_type);
1543 public override Constant Increment ()
1545 return child.Increment ();
1548 public override bool IsDefaultValue {
1549 get { return child.IsDefaultValue; }
1552 public override bool IsNegative {
1553 get { return child.IsNegative; }
1556 public override bool IsNull {
1557 get { return child.IsNull; }
1560 public override bool IsZeroInteger {
1561 get { return child.IsZeroInteger; }
1564 public override void Emit (EmitContext ec)
1569 public override Constant ConvertImplicitly (Type target_type)
1571 // FIXME: Do we need to check user conversions?
1572 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1574 return child.ConvertImplicitly (target_type);
1580 /// This class is used to wrap literals which belong inside Enums
1582 public class EnumConstant : Constant {
1583 public Constant Child;
1585 public EnumConstant (Constant child, Type enum_type):
1586 base (child.Location)
1588 eclass = child.eclass;
1593 public override Expression DoResolve (EmitContext ec)
1595 // This should never be invoked, we are born in fully
1596 // initialized state.
1601 public override void Emit (EmitContext ec)
1606 public override bool GetAttributableValue (Type value_type, out object value)
1608 value = GetTypedValue ();
1612 public override string GetSignatureForError()
1614 return TypeManager.CSharpName (Type);
1617 public override object GetValue ()
1619 return Child.GetValue ();
1622 public override object GetTypedValue ()
1624 // FIXME: runtime is not ready to work with just emited enums
1625 if (!RootContext.StdLib) {
1626 return Child.GetValue ();
1629 return System.Enum.ToObject (type, Child.GetValue ());
1632 public override string AsString ()
1634 return TypeManager.CSharpEnumValue (type, Child.GetValue ());
1637 public override Constant Increment()
1639 return new EnumConstant (Child.Increment (), type);
1642 public override bool IsDefaultValue {
1644 return Child.IsDefaultValue;
1648 public override bool IsZeroInteger {
1649 get { return Child.IsZeroInteger; }
1652 public override bool IsNegative {
1654 return Child.IsNegative;
1658 public override Constant ConvertExplicitly(bool in_checked_context, Type target_type)
1660 if (Child.Type == target_type)
1663 return Child.ConvertExplicitly (in_checked_context, target_type);
1666 public override Constant ConvertImplicitly (Type type)
1668 Type this_type = TypeManager.DropGenericTypeArguments (Type);
1669 type = TypeManager.DropGenericTypeArguments (type);
1671 if (this_type == type) {
1672 // This is workaround of mono bug. It can be removed when the latest corlib spreads enough
1673 if (TypeManager.IsEnumType (type.UnderlyingSystemType))
1676 Type child_type = TypeManager.DropGenericTypeArguments (Child.Type);
1677 if (type.UnderlyingSystemType != child_type)
1678 Child = Child.ConvertImplicitly (type.UnderlyingSystemType);
1682 if (!Convert.ImplicitStandardConversionExists (this, type)){
1686 return Child.ConvertImplicitly(type);
1692 /// This kind of cast is used to encapsulate Value Types in objects.
1694 /// The effect of it is to box the value type emitted by the previous
1697 public class BoxedCast : EmptyCast {
1699 public BoxedCast (Expression expr, Type target_type)
1700 : base (expr, target_type)
1702 eclass = ExprClass.Value;
1705 public override Expression DoResolve (EmitContext ec)
1707 // This should never be invoked, we are born in fully
1708 // initialized state.
1713 public override void Emit (EmitContext ec)
1717 ec.ig.Emit (OpCodes.Box, child.Type);
1721 public class UnboxCast : EmptyCast {
1722 public UnboxCast (Expression expr, Type return_type)
1723 : base (expr, return_type)
1727 public override Expression DoResolve (EmitContext ec)
1729 // This should never be invoked, we are born in fully
1730 // initialized state.
1735 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1737 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
1738 Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
1739 return base.DoResolveLValue (ec, right_side);
1742 public override void Emit (EmitContext ec)
1745 ILGenerator ig = ec.ig;
1749 if (t.IsGenericParameter || t.IsGenericType && t.IsValueType)
1750 ig.Emit (OpCodes.Unbox_Any, t);
1754 ig.Emit (OpCodes.Unbox, t);
1756 LoadFromPtr (ig, t);
1762 /// This is used to perform explicit numeric conversions.
1764 /// Explicit numeric conversions might trigger exceptions in a checked
1765 /// context, so they should generate the conv.ovf opcodes instead of
1768 public class ConvCast : EmptyCast {
1769 public enum Mode : byte {
1770 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1772 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1773 U2_I1, U2_U1, U2_I2, U2_CH,
1774 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1775 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1776 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH,
1777 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH,
1778 CH_I1, CH_U1, CH_I2,
1779 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1780 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4
1785 public ConvCast (Expression child, Type return_type, Mode m)
1786 : base (child, return_type)
1791 public override Expression DoResolve (EmitContext ec)
1793 // This should never be invoked, we are born in fully
1794 // initialized state.
1799 public override string ToString ()
1801 return String.Format ("ConvCast ({0}, {1})", mode, child);
1804 public override void Emit (EmitContext ec)
1806 ILGenerator ig = ec.ig;
1812 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1813 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1814 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1815 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1816 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1818 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1819 case Mode.U1_CH: /* nothing */ break;
1821 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1822 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1823 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1824 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1825 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1826 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1828 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1829 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1830 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1831 case Mode.U2_CH: /* nothing */ break;
1833 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1834 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1835 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1836 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1837 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1838 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1839 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1841 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1842 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1843 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1844 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1845 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1846 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1848 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1849 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1850 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1851 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1852 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1853 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1854 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1855 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1857 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1858 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1859 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1860 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1861 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1862 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1863 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1864 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1866 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1867 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1868 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1870 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1871 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1872 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1873 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1874 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1875 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1876 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1877 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1878 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1880 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1881 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1882 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1883 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1884 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1885 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1886 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1887 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1888 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1889 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1893 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
1894 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
1895 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
1896 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
1897 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
1899 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
1900 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
1902 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
1903 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
1904 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
1905 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
1906 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
1907 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
1909 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
1910 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
1911 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
1912 case Mode.U2_CH: /* nothing */ break;
1914 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
1915 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
1916 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
1917 case Mode.I4_U4: /* nothing */ break;
1918 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
1919 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
1920 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
1922 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
1923 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
1924 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
1925 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
1926 case Mode.U4_I4: /* nothing */ break;
1927 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
1929 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
1930 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
1931 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
1932 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
1933 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
1934 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
1935 case Mode.I8_U8: /* nothing */ break;
1936 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
1938 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
1939 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
1940 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
1941 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
1942 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
1943 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
1944 case Mode.U8_I8: /* nothing */ break;
1945 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
1947 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
1948 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
1949 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
1951 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
1952 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
1953 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
1954 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
1955 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
1956 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
1957 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
1958 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
1959 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
1961 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
1962 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
1963 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
1964 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
1965 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
1966 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
1967 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
1968 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
1969 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
1970 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1976 public class OpcodeCast : EmptyCast {
1980 public OpcodeCast (Expression child, Type return_type, OpCode op)
1981 : base (child, return_type)
1985 second_valid = false;
1988 public OpcodeCast (Expression child, Type return_type, OpCode op, OpCode op2)
1989 : base (child, return_type)
1994 second_valid = true;
1997 public override Expression CreateExpressionTree (EmitContext ec)
1999 // This has no expresion tree representation
2003 public override Expression DoResolve (EmitContext ec)
2005 // This should never be invoked, we are born in fully
2006 // initialized state.
2011 public override void Emit (EmitContext ec)
2020 public Type UnderlyingType {
2021 get { return child.Type; }
2026 /// This kind of cast is used to encapsulate a child and cast it
2027 /// to the class requested
2029 public class ClassCast : EmptyCast {
2030 public ClassCast (Expression child, Type return_type)
2031 : base (child, return_type)
2036 public override Expression DoResolve (EmitContext ec)
2038 // This should never be invoked, we are born in fully
2039 // initialized state.
2044 public override void Emit (EmitContext ec)
2048 if (TypeManager.IsGenericParameter (child.Type))
2049 ec.ig.Emit (OpCodes.Box, child.Type);
2052 if (type.IsGenericParameter)
2053 ec.ig.Emit (OpCodes.Unbox_Any, type);
2056 ec.ig.Emit (OpCodes.Castclass, type);
2061 /// SimpleName expressions are formed of a single word and only happen at the beginning
2062 /// of a dotted-name.
2064 public class SimpleName : Expression {
2065 public readonly string Name;
2066 public readonly TypeArguments Arguments;
2069 public SimpleName (string name, Location l)
2075 public SimpleName (string name, TypeArguments args, Location l)
2082 public SimpleName (string name, TypeParameter[] type_params, Location l)
2087 Arguments = new TypeArguments (l);
2088 foreach (TypeParameter type_param in type_params)
2089 Arguments.Add (new TypeParameterExpr (type_param, l));
2092 public static string RemoveGenericArity (string name)
2095 StringBuilder sb = null;
2097 int pos = name.IndexOf ('`', start);
2102 sb.Append (name.Substring (start));
2107 sb = new StringBuilder ();
2108 sb.Append (name.Substring (start, pos-start));
2111 while ((pos < name.Length) && Char.IsNumber (name [pos]))
2115 } while (start < name.Length);
2117 return sb.ToString ();
2120 public SimpleName GetMethodGroup ()
2122 return new SimpleName (RemoveGenericArity (Name), Arguments, loc);
2125 public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
2127 if (ec.IsInFieldInitializer)
2128 Report.Error (236, l,
2129 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2133 120, l, "`{0}': An object reference is required for the nonstatic field, method or property",
2137 public bool IdenticalNameAndTypeName (EmitContext ec, Expression resolved_to, Location loc)
2139 return resolved_to != null && resolved_to.Type != null &&
2140 resolved_to.Type.Name == Name &&
2141 (ec.DeclContainer.LookupNamespaceOrType (Name, loc, /* ignore_cs0104 = */ true) != null);
2144 public override Expression DoResolve (EmitContext ec)
2146 return SimpleNameResolve (ec, null, false);
2149 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
2151 return SimpleNameResolve (ec, right_side, false);
2155 public Expression DoResolve (EmitContext ec, bool intermediate)
2157 return SimpleNameResolve (ec, null, intermediate);
2160 static bool IsNestedChild (Type t, Type parent)
2162 while (parent != null) {
2163 if (TypeManager.IsNestedChildOf (t, TypeManager.DropGenericTypeArguments (parent)))
2166 parent = parent.BaseType;
2172 FullNamedExpression ResolveNested (IResolveContext ec, Type t)
2174 if (!TypeManager.IsGenericTypeDefinition (t) && !TypeManager.IsGenericType (t))
2177 DeclSpace ds = ec.DeclContainer;
2178 while (ds != null && !IsNestedChild (t, ds.TypeBuilder))
2184 Type[] gen_params = TypeManager.GetTypeArguments (t);
2186 int arg_count = Arguments != null ? Arguments.Count : 0;
2188 for (; (ds != null) && ds.IsGeneric; ds = ds.Parent) {
2189 if (arg_count + ds.CountTypeParameters == gen_params.Length) {
2190 TypeArguments new_args = new TypeArguments (loc);
2191 foreach (TypeParameter param in ds.TypeParameters)
2192 new_args.Add (new TypeParameterExpr (param, loc));
2194 if (Arguments != null)
2195 new_args.Add (Arguments);
2197 return new ConstructedType (t, new_args, loc);
2204 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2206 FullNamedExpression fne = ec.GenericDeclContainer.LookupGeneric (Name, loc);
2208 return fne.ResolveAsTypeStep (ec, silent);
2210 int errors = Report.Errors;
2211 fne = ec.DeclContainer.LookupNamespaceOrType (Name, loc, /*ignore_cs0104=*/ false);
2214 if (fne.Type == null)
2217 FullNamedExpression nested = ResolveNested (ec, fne.Type);
2219 return nested.ResolveAsTypeStep (ec, false);
2221 if (Arguments != null) {
2222 ConstructedType ct = new ConstructedType (fne, Arguments, loc);
2223 return ct.ResolveAsTypeStep (ec, false);
2229 if (silent || errors != Report.Errors)
2232 Error_TypeOrNamespaceNotFound (ec);
2236 protected virtual void Error_TypeOrNamespaceNotFound (IResolveContext ec)
2238 MemberCore mc = ec.DeclContainer.GetDefinition (Name);
2240 Error_UnexpectedKind (ec.DeclContainer, "type", GetMemberType (mc), loc);
2244 string ns = ec.DeclContainer.NamespaceEntry.NS.Name;
2245 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2246 foreach (Assembly a in RootNamespace.Global.Assemblies) {
2247 Type type = a.GetType (fullname);
2249 Report.SymbolRelatedToPreviousError (type);
2250 Expression.ErrorIsInaccesible (loc, TypeManager.CSharpName (type));
2255 Type t = ec.DeclContainer.LookupAnyGeneric (Name);
2257 Namespace.Error_InvalidNumberOfTypeArguments (t, loc);
2261 if (Arguments != null) {
2262 FullNamedExpression retval = ec.DeclContainer.LookupNamespaceOrType (SimpleName.RemoveGenericArity (Name), loc, true);
2263 if (retval != null) {
2264 Namespace.Error_TypeArgumentsCannotBeUsed (retval.Type, loc);
2269 NamespaceEntry.Error_NamespaceNotFound (loc, Name);
2272 // TODO: I am still not convinced about this. If someone else will need it
2273 // implement this as virtual property in MemberCore hierarchy
2274 public static string GetMemberType (MemberCore mc)
2280 if (mc is FieldBase)
2282 if (mc is MethodCore)
2284 if (mc is EnumMember)
2292 Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2298 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2304 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2311 /// 7.5.2: Simple Names.
2313 /// Local Variables and Parameters are handled at
2314 /// parse time, so they never occur as SimpleNames.
2316 /// The `intermediate' flag is used by MemberAccess only
2317 /// and it is used to inform us that it is ok for us to
2318 /// avoid the static check, because MemberAccess might end
2319 /// up resolving the Name as a Type name and the access as
2320 /// a static type access.
2322 /// ie: Type Type; .... { Type.GetType (""); }
2324 /// Type is both an instance variable and a Type; Type.GetType
2325 /// is the static method not an instance method of type.
2327 Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2329 Expression e = null;
2332 // Stage 1: Performed by the parser (binding to locals or parameters).
2334 Block current_block = ec.CurrentBlock;
2335 if (current_block != null){
2336 LocalInfo vi = current_block.GetLocalInfo (Name);
2338 if (Arguments != null) {
2339 Report.Error (307, loc,
2340 "The variable `{0}' cannot be used with type arguments",
2345 LocalVariableReference var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2346 if (right_side != null) {
2347 return var.ResolveLValue (ec, right_side, loc);
2349 ResolveFlags rf = ResolveFlags.VariableOrValue;
2351 rf |= ResolveFlags.DisableFlowAnalysis;
2352 return var.Resolve (ec, rf);
2356 ParameterReference pref = current_block.Toplevel.GetParameterReference (Name, loc);
2358 if (Arguments != null) {
2359 Report.Error (307, loc,
2360 "The variable `{0}' cannot be used with type arguments",
2365 if (right_side != null)
2366 return pref.ResolveLValue (ec, right_side, loc);
2368 return pref.Resolve (ec);
2371 Expression expr = current_block.Toplevel.GetTransparentIdentifier (Name);
2373 if (right_side != null)
2374 return expr.ResolveLValue (ec, right_side, loc);
2375 return expr.Resolve (ec);
2380 // Stage 2: Lookup members
2383 Type almost_matched_type = null;
2384 ArrayList almost_matched = null;
2385 for (DeclSpace lookup_ds = ec.DeclContainer; lookup_ds != null; lookup_ds = lookup_ds.Parent) {
2386 // either RootDeclSpace or GenericMethod
2387 if (lookup_ds.TypeBuilder == null)
2390 e = MemberLookup (ec.ContainerType, lookup_ds.TypeBuilder, Name, loc);
2392 if (e is PropertyExpr) {
2393 // since TypeManager.MemberLookup doesn't know if we're doing a lvalue access or not,
2394 // it doesn't know which accessor to check permissions against
2395 if (((PropertyExpr) e).IsAccessibleFrom (ec.ContainerType, right_side != null))
2397 } else if (e is EventExpr) {
2398 if (((EventExpr) e).IsAccessibleFrom (ec.ContainerType))
2406 if (almost_matched == null && almost_matched_members.Count > 0) {
2407 almost_matched_type = lookup_ds.TypeBuilder;
2408 almost_matched = (ArrayList) almost_matched_members.Clone ();
2413 if (almost_matched == null && almost_matched_members.Count > 0) {
2414 almost_matched_type = ec.ContainerType;
2415 almost_matched = (ArrayList) almost_matched_members.Clone ();
2417 e = ResolveAsTypeStep (ec, true);
2421 if (current_block != null) {
2422 IKnownVariable ikv = current_block.Explicit.GetKnownVariable (Name);
2424 LocalInfo li = ikv as LocalInfo;
2425 // Supress CS0219 warning
2429 Error_VariableIsUsedBeforeItIsDeclared (Name);
2434 if (almost_matched != null)
2435 almost_matched_members = almost_matched;
2436 if (almost_matched_type == null)
2437 almost_matched_type = ec.ContainerType;
2438 Error_MemberLookupFailed (ec.ContainerType, null, almost_matched_type, Name,
2439 ec.DeclContainer.Name, AllMemberTypes, AllBindingFlags);
2443 if (e is TypeExpr) {
2444 if (Arguments == null)
2447 ConstructedType ct = new ConstructedType (
2448 (FullNamedExpression) e, Arguments, loc);
2449 return ct.ResolveAsTypeStep (ec, false);
2452 if (e is MemberExpr) {
2453 MemberExpr me = (MemberExpr) e;
2456 if (me.IsInstance) {
2457 if (ec.IsStatic || ec.IsInFieldInitializer) {
2459 // Note that an MemberExpr can be both IsInstance and IsStatic.
2460 // An unresolved MethodGroupExpr can contain both kinds of methods
2461 // and each predicate is true if the MethodGroupExpr contains
2462 // at least one of that kind of method.
2466 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2467 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2472 // Pass the buck to MemberAccess and Invocation.
2474 left = EmptyExpression.Null;
2476 left = ec.GetThis (loc);
2479 left = new TypeExpression (ec.ContainerType, loc);
2482 me = me.ResolveMemberAccess (ec, left, loc, null);
2486 if (Arguments != null) {
2487 Arguments.Resolve (ec);
2488 me.SetTypeArguments (Arguments);
2491 if (!me.IsStatic && (me.InstanceExpression != null) &&
2492 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2493 me.InstanceExpression.Type != me.DeclaringType &&
2494 !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2495 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2496 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2497 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2501 return (right_side != null)
2502 ? me.DoResolveLValue (ec, right_side)
2503 : me.DoResolve (ec);
2509 public override void Emit (EmitContext ec)
2511 throw new InternalErrorException ("The resolve phase was not executed");
2514 public override string ToString ()
2519 public override string GetSignatureForError ()
2521 if (Arguments != null) {
2522 return TypeManager.RemoveGenericArity (Name) + "<" +
2523 Arguments.GetSignatureForError () + ">";
2529 protected override void CloneTo (CloneContext clonectx, Expression target)
2531 // CloneTo: Nothing, we do not keep any state on this expression
2536 /// Represents a namespace or a type. The name of the class was inspired by
2537 /// section 10.8.1 (Fully Qualified Names).
2539 public abstract class FullNamedExpression : Expression {
2540 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2545 public abstract string FullName {
2551 /// Expression that evaluates to a type
2553 public abstract class TypeExpr : FullNamedExpression {
2554 override public FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2556 TypeExpr t = DoResolveAsTypeStep (ec);
2560 eclass = ExprClass.Type;
2564 override public Expression DoResolve (EmitContext ec)
2566 return ResolveAsTypeTerminal (ec, false);
2569 override public void Emit (EmitContext ec)
2571 throw new Exception ("Should never be called");
2574 public virtual bool CheckAccessLevel (DeclSpace ds)
2576 return ds.CheckAccessLevel (Type);
2579 public virtual bool AsAccessible (DeclSpace ds)
2581 return ds.IsAccessibleAs (Type);
2584 public virtual bool IsClass {
2585 get { return Type.IsClass; }
2588 public virtual bool IsValueType {
2589 get { return Type.IsValueType; }
2592 public virtual bool IsInterface {
2593 get { return Type.IsInterface; }
2596 public virtual bool IsSealed {
2597 get { return Type.IsSealed; }
2600 public virtual bool CanInheritFrom ()
2602 if (Type == TypeManager.enum_type ||
2603 (Type == TypeManager.value_type && RootContext.StdLib) ||
2604 Type == TypeManager.multicast_delegate_type ||
2605 Type == TypeManager.delegate_type ||
2606 Type == TypeManager.array_type)
2612 protected abstract TypeExpr DoResolveAsTypeStep (IResolveContext ec);
2614 public abstract string Name {
2618 public override bool Equals (object obj)
2620 TypeExpr tobj = obj as TypeExpr;
2624 return Type == tobj.Type;
2627 public override int GetHashCode ()
2629 return Type.GetHashCode ();
2632 public override string ToString ()
2639 /// Fully resolved Expression that already evaluated to a type
2641 public class TypeExpression : TypeExpr {
2642 public TypeExpression (Type t, Location l)
2645 eclass = ExprClass.Type;
2649 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2654 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2659 public override string Name {
2660 get { return Type.ToString (); }
2663 public override string FullName {
2664 get { return Type.FullName; }
2669 /// Used to create types from a fully qualified name. These are just used
2670 /// by the parser to setup the core types. A TypeLookupExpression is always
2671 /// classified as a type.
2673 public sealed class TypeLookupExpression : TypeExpr {
2674 readonly string name;
2676 public TypeLookupExpression (string name)
2679 eclass = ExprClass.Type;
2682 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2684 // It's null for corlib compilation only
2686 return DoResolveAsTypeStep (ec);
2691 private class UnexpectedType
2695 // This performes recursive type lookup, providing support for generic types.
2696 // For example, given the type:
2698 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]]
2700 // The types will be checked in the following order:
2703 // System.Collections |
2704 // System.Collections.Generic |
2706 // System | recursive call 1 |
2707 // System.Int32 _| | main method call
2709 // System | recursive call 2 |
2710 // System.String _| |
2712 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]] _|
2714 private Type TypeLookup (IResolveContext ec, string name)
2719 FullNamedExpression resolved = null;
2721 Type recursive_type = null;
2722 while (index < name.Length) {
2723 if (name[index] == '[') {
2728 if (name[index] == '[')
2730 else if (name[index] == ']')
2732 } while (braces > 0);
2733 recursive_type = TypeLookup (ec, name.Substring (open + 1, index - open - 1));
2734 if (recursive_type == null || (recursive_type == typeof(UnexpectedType)))
2735 return recursive_type;
2738 if (name[index] == ',')
2740 else if ((name[index] == '.' && !done) || (index == name.Length && name[0] != '[')) {
2741 string substring = name.Substring(dot, index - dot);
2743 if (resolved == null)
2744 resolved = RootNamespace.Global.Lookup (ec.DeclContainer, substring, Location.Null);
2745 else if (resolved is Namespace)
2746 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
2747 else if (type != null)
2748 type = TypeManager.GetNestedType (type, substring);
2752 if (resolved == null)
2754 else if (type == null && resolved is TypeExpr)
2755 type = resolved.Type;
2762 if (name[0] != '[') {
2763 string substring = name.Substring(dot, index - dot);
2766 return TypeManager.GetNestedType (type, substring);
2768 if (resolved != null) {
2769 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
2770 if (resolved is TypeExpr)
2771 return resolved.Type;
2773 if (resolved == null)
2776 resolved.Error_UnexpectedKind (ec.DeclContainer, "type", loc);
2777 return typeof (UnexpectedType);
2783 return recursive_type;
2786 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2788 Type t = TypeLookup (ec, name);
2790 NamespaceEntry.Error_NamespaceNotFound (loc, name);
2793 if (t == typeof(UnexpectedType))
2799 public override string Name {
2800 get { return name; }
2803 public override string FullName {
2804 get { return name; }
2807 protected override void CloneTo (CloneContext clonectx, Expression target)
2809 // CloneTo: Nothing, we do not keep any state on this expression
2812 public override string GetSignatureForError ()
2815 return TypeManager.CSharpName (name);
2817 return base.GetSignatureForError ();
2822 /// Represents an "unbound generic type", ie. typeof (Foo<>).
2825 public class UnboundTypeExpression : TypeExpr
2829 public UnboundTypeExpression (MemberName name, Location l)
2835 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2838 if (name.Left != null) {
2839 Expression lexpr = name.Left.GetTypeExpression ();
2840 expr = new MemberAccess (lexpr, name.Basename);
2842 expr = new SimpleName (name.Basename, loc);
2845 FullNamedExpression fne = expr.ResolveAsTypeStep (ec, false);
2850 return new TypeExpression (type, loc);
2853 public override string Name {
2854 get { return name.FullName; }
2857 public override string FullName {
2858 get { return name.FullName; }
2862 public class TypeAliasExpression : TypeExpr {
2863 FullNamedExpression alias;
2868 public TypeAliasExpression (FullNamedExpression alias, TypeArguments args, Location l)
2874 eclass = ExprClass.Type;
2876 name = alias.FullName + "<" + args.ToString () + ">";
2878 name = alias.FullName;
2881 public override string Name {
2882 get { return alias.FullName; }
2885 public override string FullName {
2886 get { return name; }
2889 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2891 texpr = alias.ResolveAsTypeTerminal (ec, false);
2895 Type type = texpr.Type;
2896 int num_args = TypeManager.GetNumberOfTypeArguments (type);
2899 if (num_args == 0) {
2900 Report.Error (308, loc,
2901 "The non-generic type `{0}' cannot " +
2902 "be used with type arguments.",
2903 TypeManager.CSharpName (type));
2907 ConstructedType ctype = new ConstructedType (type, args, loc);
2908 return ctype.ResolveAsTypeTerminal (ec, false);
2909 } else if (num_args > 0) {
2910 Report.Error (305, loc,
2911 "Using the generic type `{0}' " +
2912 "requires {1} type arguments",
2913 TypeManager.CSharpName (type), num_args.ToString ());
2920 public override bool CheckAccessLevel (DeclSpace ds)
2922 return texpr.CheckAccessLevel (ds);
2925 public override bool AsAccessible (DeclSpace ds)
2927 return texpr.AsAccessible (ds);
2930 public override bool IsClass {
2931 get { return texpr.IsClass; }
2934 public override bool IsValueType {
2935 get { return texpr.IsValueType; }
2938 public override bool IsInterface {
2939 get { return texpr.IsInterface; }
2942 public override bool IsSealed {
2943 get { return texpr.IsSealed; }
2948 /// This class denotes an expression which evaluates to a member
2949 /// of a struct or a class.
2951 public abstract class MemberExpr : Expression
2953 protected bool is_base;
2956 /// The name of this member.
2958 public abstract string Name {
2963 // When base.member is used
2965 public bool IsBase {
2966 get { return is_base; }
2967 set { is_base = value; }
2971 /// Whether this is an instance member.
2973 public abstract bool IsInstance {
2978 /// Whether this is a static member.
2980 public abstract bool IsStatic {
2985 /// The type which declares this member.
2987 public abstract Type DeclaringType {
2992 /// The instance expression associated with this member, if it's a
2993 /// non-static member.
2995 public Expression InstanceExpression;
2997 public static void error176 (Location loc, string name)
2999 Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
3000 "with an instance reference, qualify it with a type name instead", name);
3003 // TODO: possible optimalization
3004 // Cache resolved constant result in FieldBuilder <-> expression map
3005 public virtual MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3006 SimpleName original)
3010 // original == null || original.Resolve (...) ==> left
3013 if (left is TypeExpr) {
3014 left = left.ResolveAsTypeTerminal (ec, true);
3019 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3027 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3030 return ResolveExtensionMemberAccess (left);
3033 InstanceExpression = left;
3037 protected virtual MemberExpr ResolveExtensionMemberAccess (Expression left)
3039 error176 (loc, GetSignatureForError ());
3043 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3048 if (InstanceExpression == EmptyExpression.Null) {
3049 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3053 if (InstanceExpression.Type.IsValueType) {
3054 if (InstanceExpression is IMemoryLocation) {
3055 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
3057 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
3058 InstanceExpression.Emit (ec);
3060 t.AddressOf (ec, AddressOp.Store);
3063 InstanceExpression.Emit (ec);
3065 if (prepare_for_load)
3066 ec.ig.Emit (OpCodes.Dup);
3069 public virtual void SetTypeArguments (TypeArguments ta)
3071 // TODO: need to get correct member type
3072 Report.Error (307, loc, "The property `{0}' cannot be used with type arguments",
3073 GetSignatureForError ());
3078 /// Represents group of extension methods
3080 public class ExtensionMethodGroupExpr : MethodGroupExpr
3082 readonly NamespaceEntry namespace_entry;
3083 public Expression ExtensionExpression;
3084 Argument extension_argument;
3086 public ExtensionMethodGroupExpr (ArrayList list, NamespaceEntry n, Type extensionType, Location l)
3087 : base (list, extensionType, l)
3089 this.namespace_entry = n;
3092 public override bool IsStatic {
3093 get { return true; }
3096 public bool IsTopLevel {
3097 get { return namespace_entry == null; }
3100 public override void EmitArguments (EmitContext ec, ArrayList arguments)
3102 if (arguments == null)
3103 arguments = new ArrayList (1);
3104 arguments.Insert (0, extension_argument);
3105 base.EmitArguments (ec, arguments);
3108 public override void EmitCall (EmitContext ec, ArrayList arguments)
3110 if (arguments == null)
3111 arguments = new ArrayList (1);
3112 arguments.Insert (0, extension_argument);
3113 base.EmitCall (ec, arguments);
3116 public override MethodGroupExpr OverloadResolve (EmitContext ec, ref ArrayList arguments, bool may_fail, Location loc)
3118 if (arguments == null)
3119 arguments = new ArrayList (1);
3121 arguments.Insert (0, new Argument (ExtensionExpression));
3122 MethodGroupExpr mg = ResolveOverloadExtensions (ec, arguments, namespace_entry, loc);
3124 // Store resolved argument and restore original arguments
3126 ((ExtensionMethodGroupExpr)mg).extension_argument = (Argument)arguments [0];
3127 arguments.RemoveAt (0);
3132 MethodGroupExpr ResolveOverloadExtensions (EmitContext ec, ArrayList arguments, NamespaceEntry ns, Location loc)
3134 // Use normal resolve rules
3135 MethodGroupExpr mg = base.OverloadResolve (ec, ref arguments, ns != null, loc);
3143 ExtensionMethodGroupExpr e = ns.LookupExtensionMethod (type, null, Name);
3145 return base.OverloadResolve (ec, ref arguments, false, loc);
3147 e.ExtensionExpression = ExtensionExpression;
3148 return e.ResolveOverloadExtensions (ec, arguments, e.namespace_entry, loc);
3153 /// MethodGroupExpr represents a group of method candidates which
3154 /// can be resolved to the best method overload
3156 public class MethodGroupExpr : MemberExpr
3158 public interface IErrorHandler
3160 bool NoExactMatch (EmitContext ec, MethodBase method);
3163 public IErrorHandler CustomErrorHandler;
3164 public MethodBase [] Methods;
3165 MethodBase best_candidate;
3166 // TODO: make private
3167 public TypeArguments type_arguments;
3168 bool identical_type_name;
3171 public MethodGroupExpr (MemberInfo [] mi, Type type, Location l)
3174 Methods = new MethodBase [mi.Length];
3175 mi.CopyTo (Methods, 0);
3178 public MethodGroupExpr (ArrayList list, Type type, Location l)
3182 Methods = (MethodBase[])list.ToArray (typeof (MethodBase));
3184 foreach (MemberInfo m in list){
3185 if (!(m is MethodBase)){
3186 Console.WriteLine ("Name " + m.Name);
3187 Console.WriteLine ("Found a: " + m.GetType ().FullName);
3196 protected MethodGroupExpr (Type type, Location loc)
3199 eclass = ExprClass.MethodGroup;
3203 public override Type DeclaringType {
3206 // We assume that the top-level type is in the end
3208 return Methods [Methods.Length - 1].DeclaringType;
3209 //return Methods [0].DeclaringType;
3213 public Type DelegateType {
3215 delegate_type = value;
3219 public bool IdenticalTypeName {
3221 return identical_type_name;
3225 identical_type_name = value;
3229 public override string GetSignatureForError ()
3231 if (best_candidate != null)
3232 return TypeManager.CSharpSignature (best_candidate);
3234 return TypeManager.CSharpSignature (Methods [0]);
3237 public override string Name {
3239 return Methods [0].Name;
3243 public override bool IsInstance {
3245 if (best_candidate != null)
3246 return !best_candidate.IsStatic;
3248 foreach (MethodBase mb in Methods)
3256 public override bool IsStatic {
3258 if (best_candidate != null)
3259 return best_candidate.IsStatic;
3261 foreach (MethodBase mb in Methods)
3269 public static explicit operator ConstructorInfo (MethodGroupExpr mg)
3271 return (ConstructorInfo)mg.best_candidate;
3274 public static explicit operator MethodInfo (MethodGroupExpr mg)
3276 return (MethodInfo)mg.best_candidate;
3280 // 7.4.3.3 Better conversion from expression
3281 // Returns : 1 if a->p is better,
3282 // 2 if a->q is better,
3283 // 0 if neither is better
3285 static int BetterExpressionConversion (EmitContext ec, Argument a, Type p, Type q)
3287 Type argument_type = TypeManager.TypeToCoreType (a.Type);
3288 if (argument_type == TypeManager.anonymous_method_type && RootContext.Version > LanguageVersion.ISO_2) {
3290 // Uwrap delegate from Expression<T>
3292 if (TypeManager.DropGenericTypeArguments (p) == TypeManager.expression_type) {
3293 p = TypeManager.GetTypeArguments (p) [0];
3294 q = TypeManager.GetTypeArguments (q) [0];
3296 p = Delegate.GetInvokeMethod (null, p).ReturnType;
3297 q = Delegate.GetInvokeMethod (null, q).ReturnType;
3299 if (argument_type == p)
3302 if (argument_type == q)
3306 return BetterTypeConversion (ec, p, q);
3310 // 7.4.3.4 Better conversion from type
3312 public static int BetterTypeConversion (EmitContext ec, Type p, Type q)
3314 if (p == null || q == null)
3315 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3317 if (p == TypeManager.int32_type) {
3318 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3320 } else if (p == TypeManager.int64_type) {
3321 if (q == TypeManager.uint64_type)
3323 } else if (p == TypeManager.sbyte_type) {
3324 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3325 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3327 } else if (p == TypeManager.short_type) {
3328 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3329 q == TypeManager.uint64_type)
3333 if (q == TypeManager.int32_type) {
3334 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3336 } if (q == TypeManager.int64_type) {
3337 if (p == TypeManager.uint64_type)
3339 } else if (q == TypeManager.sbyte_type) {
3340 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3341 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3343 } if (q == TypeManager.short_type) {
3344 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3345 p == TypeManager.uint64_type)
3349 // TODO: this is expensive
3350 Expression p_tmp = new EmptyExpression (p);
3351 Expression q_tmp = new EmptyExpression (q);
3353 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3354 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3356 if (p_to_q && !q_to_p)
3359 if (q_to_p && !p_to_q)
3366 /// Determines "Better function" between candidate
3367 /// and the current best match
3370 /// Returns a boolean indicating :
3371 /// false if candidate ain't better
3372 /// true if candidate is better than the current best match
3374 static bool BetterFunction (EmitContext ec, ArrayList args, int argument_count,
3375 MethodBase candidate, bool candidate_params,
3376 MethodBase best, bool best_params)
3378 ParameterData candidate_pd = TypeManager.GetParameterData (candidate);
3379 ParameterData best_pd = TypeManager.GetParameterData (best);
3381 bool better_at_least_one = false;
3383 for (int j = 0, c_idx = 0, b_idx = 0; j < argument_count; ++j, ++c_idx, ++b_idx)
3385 Argument a = (Argument) args [j];
3387 Type ct = TypeManager.TypeToCoreType (candidate_pd.ParameterType (c_idx));
3388 Type bt = TypeManager.TypeToCoreType (best_pd.ParameterType (b_idx));
3390 if (candidate_params && candidate_pd.ParameterModifier (c_idx) == Parameter.Modifier.PARAMS)
3392 ct = TypeManager.GetElementType (ct);
3396 if (best_params && best_pd.ParameterModifier (b_idx) == Parameter.Modifier.PARAMS)
3398 bt = TypeManager.GetElementType (bt);
3406 int result = BetterExpressionConversion (ec, a, ct, bt);
3408 // for each argument, the conversion to 'ct' should be no worse than
3409 // the conversion to 'bt'.
3413 // for at least one argument, the conversion to 'ct' should be better than
3414 // the conversion to 'bt'.
3416 better_at_least_one = true;
3419 if (better_at_least_one)
3423 // This handles the case
3425 // Add (float f1, float f2, float f3);
3426 // Add (params decimal [] foo);
3428 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3429 // first candidate would've chosen as better.
3435 // The two methods have equal parameter types. Now apply tie-breaking rules
3437 if (TypeManager.IsGenericMethod (best) && !TypeManager.IsGenericMethod (candidate))
3439 if (!TypeManager.IsGenericMethod (best) && TypeManager.IsGenericMethod (candidate))
3443 // This handles the following cases:
3445 // Trim () is better than Trim (params char[] chars)
3446 // Concat (string s1, string s2, string s3) is better than
3447 // Concat (string s1, params string [] srest)
3448 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3450 if (!candidate_params && best_params)
3452 if (candidate_params && !best_params)
3455 int candidate_param_count = candidate_pd.Count;
3456 int best_param_count = best_pd.Count;
3458 if (candidate_param_count != best_param_count)
3459 // can only happen if (candidate_params && best_params)
3460 return candidate_param_count > best_param_count;
3463 // now, both methods have the same number of parameters, and the parameters have the same types
3464 // Pick the "more specific" signature
3467 MethodBase orig_candidate = TypeManager.DropGenericMethodArguments (candidate);
3468 MethodBase orig_best = TypeManager.DropGenericMethodArguments (best);
3470 ParameterData orig_candidate_pd = TypeManager.GetParameterData (orig_candidate);
3471 ParameterData orig_best_pd = TypeManager.GetParameterData (orig_best);
3473 bool specific_at_least_once = false;
3474 for (int j = 0; j < candidate_param_count; ++j)
3476 Type ct = TypeManager.TypeToCoreType (orig_candidate_pd.ParameterType (j));
3477 Type bt = TypeManager.TypeToCoreType (orig_best_pd.ParameterType (j));
3480 Type specific = MoreSpecific (ct, bt);
3484 specific_at_least_once = true;
3487 if (specific_at_least_once)
3490 // FIXME: handle lifted operators
3496 protected override MemberExpr ResolveExtensionMemberAccess (Expression left)
3499 return base.ResolveExtensionMemberAccess (left);
3502 // When left side is an expression and at least one candidate method is
3503 // static, it can be extension method
3505 InstanceExpression = left;
3509 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3510 SimpleName original)
3512 if (!(left is TypeExpr) &&
3513 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3514 IdenticalTypeName = true;
3516 return base.ResolveMemberAccess (ec, left, loc, original);
3519 public override Expression CreateExpressionTree (EmitContext ec)
3521 return new Cast (new TypeExpression (typeof (MethodInfo), loc),
3522 new TypeOfMethod ((MethodInfo)best_candidate, loc));
3525 override public Expression DoResolve (EmitContext ec)
3527 if (InstanceExpression != null) {
3528 InstanceExpression = InstanceExpression.DoResolve (ec);
3529 if (InstanceExpression == null)
3536 public void ReportUsageError ()
3538 Report.Error (654, loc, "Method `" + DeclaringType + "." +
3539 Name + "()' is referenced without parentheses");
3542 override public void Emit (EmitContext ec)
3544 ReportUsageError ();
3547 public virtual void EmitArguments (EmitContext ec, ArrayList arguments)
3549 Invocation.EmitArguments (ec, arguments, false, null);
3552 public virtual void EmitCall (EmitContext ec, ArrayList arguments)
3554 Invocation.EmitCall (ec, IsBase, InstanceExpression, best_candidate, arguments, loc);
3557 protected virtual void Error_InvalidArguments (EmitContext ec, Location loc, int idx, MethodBase method,
3558 Argument a, ParameterData expected_par, Type paramType)
3560 if (a is CollectionElementInitializer.ElementInitializerArgument) {
3561 Report.SymbolRelatedToPreviousError (method);
3562 if ((expected_par.ParameterModifier (idx) & Parameter.Modifier.ISBYREF) != 0) {
3563 Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
3564 TypeManager.CSharpSignature (method));
3567 Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
3568 TypeManager.CSharpSignature (method));
3569 } else if (delegate_type == null) {
3570 Report.SymbolRelatedToPreviousError (method);
3571 Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
3572 TypeManager.CSharpSignature (method));
3574 Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
3575 TypeManager.CSharpName (delegate_type));
3577 Parameter.Modifier mod = expected_par.ParameterModifier (idx);
3579 string index = (idx + 1).ToString ();
3580 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
3581 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
3582 if ((mod & Parameter.Modifier.ISBYREF) == 0)
3583 Report.Error (1615, loc, "Argument `{0}' should not be passed with the `{1}' keyword",
3584 index, Parameter.GetModifierSignature (a.Modifier));
3586 Report.Error (1620, loc, "Argument `{0}' must be passed with the `{1}' keyword",
3587 index, Parameter.GetModifierSignature (mod));
3589 string p1 = a.GetSignatureForError ();
3590 string p2 = TypeManager.CSharpName (paramType);
3593 Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
3594 Report.SymbolRelatedToPreviousError (a.Expr.Type);
3595 Report.SymbolRelatedToPreviousError (paramType);
3597 Report.Error (1503, loc, "Argument {0}: Cannot convert type `{1}' to `{2}'", index, p1, p2);
3601 protected virtual int GetApplicableParametersCount (MethodBase method, ParameterData parameters)
3603 return parameters.Count;
3606 public static bool IsAncestralType (Type first_type, Type second_type)
3608 return first_type != second_type &&
3609 (TypeManager.IsSubclassOf (second_type, first_type) ||
3610 TypeManager.ImplementsInterface (second_type, first_type));
3614 /// Determines if the candidate method is applicable (section 14.4.2.1)
3615 /// to the given set of arguments
3616 /// A return value rates candidate method compatibility,
3617 /// 0 = the best, int.MaxValue = the worst
3619 public int IsApplicable (EmitContext ec,
3620 ArrayList arguments, int arg_count, ref MethodBase method, ref bool params_expanded_form)
3622 MethodBase candidate = method;
3624 ParameterData pd = TypeManager.GetParameterData (candidate);
3625 int param_count = GetApplicableParametersCount (candidate, pd);
3627 if (arg_count != param_count) {
3629 return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
3630 if (arg_count < param_count - 1)
3631 return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
3636 // 1. Handle generic method using type arguments when specified or type inference
3638 if (TypeManager.IsGenericMethod (candidate)) {
3639 if (type_arguments != null) {
3640 Type [] g_args = candidate.GetGenericArguments ();
3641 if (g_args.Length != type_arguments.Count)
3642 return int.MaxValue - 20000 + Math.Abs (type_arguments.Count - g_args.Length);
3644 // TODO: Don't create new method, create Parameters only
3645 method = ((MethodInfo) candidate).MakeGenericMethod (type_arguments.Arguments);
3647 pd = TypeManager.GetParameterData (candidate);
3649 int score = TypeManager.InferTypeArguments (ec, arguments, ref candidate);
3651 return score - 20000;
3653 if (TypeManager.IsGenericMethodDefinition (candidate))
3654 throw new InternalErrorException ("A generic method `{0}' definition took part in overload resolution",
3655 TypeManager.CSharpSignature (candidate));
3657 pd = TypeManager.GetParameterData (candidate);
3660 if (type_arguments != null)
3661 return int.MaxValue - 15000;
3666 // 2. Each argument has to be implicitly convertible to method parameter
3669 Parameter.Modifier p_mod = 0;
3671 for (int i = 0; i < arg_count; i++) {
3672 Argument a = (Argument) arguments [i];
3673 Parameter.Modifier a_mod = a.Modifier &
3674 ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3676 if (p_mod != Parameter.Modifier.PARAMS) {
3677 p_mod = pd.ParameterModifier (i) & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3679 if (p_mod == Parameter.Modifier.ARGLIST) {
3680 if (a.Type == TypeManager.runtime_argument_handle_type)
3686 pt = pd.ParameterType (i);
3688 params_expanded_form = true;
3692 if (!params_expanded_form)
3693 score = IsArgumentCompatible (ec, a_mod, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
3695 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0) {
3696 // It can be applicable in expanded form
3697 score = IsArgumentCompatible (ec, a_mod, a, 0, pt.GetElementType ());
3699 params_expanded_form = true;
3703 if (params_expanded_form)
3705 return (arg_count - i) * 2 + score;
3709 if (arg_count != param_count)
3710 params_expanded_form = true;
3715 int IsArgumentCompatible (EmitContext ec, Parameter.Modifier arg_mod, Argument argument, Parameter.Modifier param_mod, Type parameter)
3718 // Types have to be identical when ref or out modifer is used
3720 if (arg_mod != 0 || param_mod != 0) {
3721 if (TypeManager.HasElementType (parameter))
3722 parameter = parameter.GetElementType ();
3724 Type a_type = argument.Type;
3725 if (TypeManager.HasElementType (a_type))
3726 a_type = a_type.GetElementType ();
3728 if (a_type != parameter)
3734 // FIXME: Kill this abomination (EmitContext.TempEc)
3735 EmitContext prevec = EmitContext.TempEc;
3736 EmitContext.TempEc = ec;
3738 if (delegate_type != null ?
3739 !Delegate.IsTypeCovariant (argument.Expr, parameter) :
3740 !Convert.ImplicitConversionExists (ec, argument.Expr, parameter))
3743 if (arg_mod != param_mod)
3747 EmitContext.TempEc = prevec;
3753 public static bool IsOverride (MethodBase cand_method, MethodBase base_method)
3755 if (!IsAncestralType (base_method.DeclaringType, cand_method.DeclaringType))
3758 ParameterData cand_pd = TypeManager.GetParameterData (cand_method);
3759 ParameterData base_pd = TypeManager.GetParameterData (base_method);
3761 if (cand_pd.Count != base_pd.Count)
3764 for (int j = 0; j < cand_pd.Count; ++j)
3766 Parameter.Modifier cm = cand_pd.ParameterModifier (j);
3767 Parameter.Modifier bm = base_pd.ParameterModifier (j);
3768 Type ct = TypeManager.TypeToCoreType (cand_pd.ParameterType (j));
3769 Type bt = TypeManager.TypeToCoreType (base_pd.ParameterType (j));
3771 if (cm != bm || ct != bt)
3778 public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2, Location loc)
3780 MemberInfo [] miset;
3781 MethodGroupExpr union;
3786 return (MethodGroupExpr) mg2;
3789 return (MethodGroupExpr) mg1;
3792 MethodGroupExpr left_set = null, right_set = null;
3793 int length1 = 0, length2 = 0;
3795 left_set = (MethodGroupExpr) mg1;
3796 length1 = left_set.Methods.Length;
3798 right_set = (MethodGroupExpr) mg2;
3799 length2 = right_set.Methods.Length;
3801 ArrayList common = new ArrayList ();
3803 foreach (MethodBase r in right_set.Methods){
3804 if (TypeManager.ArrayContainsMethod (left_set.Methods, r))
3808 miset = new MemberInfo [length1 + length2 - common.Count];
3809 left_set.Methods.CopyTo (miset, 0);
3813 foreach (MethodBase r in right_set.Methods) {
3814 if (!common.Contains (r))
3818 union = new MethodGroupExpr (miset, mg1.Type, loc);
3823 static Type MoreSpecific (Type p, Type q)
3825 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
3827 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
3830 if (TypeManager.HasElementType (p))
3832 Type pe = TypeManager.GetElementType (p);
3833 Type qe = TypeManager.GetElementType (q);
3834 Type specific = MoreSpecific (pe, qe);
3840 else if (TypeManager.IsGenericType (p))
3842 Type[] pargs = TypeManager.GetTypeArguments (p);
3843 Type[] qargs = TypeManager.GetTypeArguments (q);
3845 bool p_specific_at_least_once = false;
3846 bool q_specific_at_least_once = false;
3848 for (int i = 0; i < pargs.Length; i++)
3850 Type specific = MoreSpecific (pargs [i], qargs [i]);
3851 if (specific == pargs [i])
3852 p_specific_at_least_once = true;
3853 if (specific == qargs [i])
3854 q_specific_at_least_once = true;
3857 if (p_specific_at_least_once && !q_specific_at_least_once)
3859 if (!p_specific_at_least_once && q_specific_at_least_once)
3867 /// Find the Applicable Function Members (7.4.2.1)
3869 /// me: Method Group expression with the members to select.
3870 /// it might contain constructors or methods (or anything
3871 /// that maps to a method).
3873 /// Arguments: ArrayList containing resolved Argument objects.
3875 /// loc: The location if we want an error to be reported, or a Null
3876 /// location for "probing" purposes.
3878 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3879 /// that is the best match of me on Arguments.
3882 public virtual MethodGroupExpr OverloadResolve (EmitContext ec, ref ArrayList Arguments,
3883 bool may_fail, Location loc)
3885 bool method_params = false;
3886 Type applicable_type = null;
3888 ArrayList candidates = new ArrayList (2);
3889 ArrayList candidate_overrides = null;
3892 // Used to keep a map between the candidate
3893 // and whether it is being considered in its
3894 // normal or expanded form
3896 // false is normal form, true is expanded form
3898 Hashtable candidate_to_form = null;
3900 if (Arguments != null)
3901 arg_count = Arguments.Count;
3903 if (RootContext.Version == LanguageVersion.ISO_1 && Name == "Invoke" && TypeManager.IsDelegateType (DeclaringType)) {
3905 Report.Error (1533, loc, "Invoke cannot be called directly on a delegate");
3909 int nmethods = Methods.Length;
3913 // Methods marked 'override' don't take part in 'applicable_type'
3914 // computation, nor in the actual overload resolution.
3915 // However, they still need to be emitted instead of a base virtual method.
3916 // So, we salt them away into the 'candidate_overrides' array.
3918 // In case of reflected methods, we replace each overriding method with
3919 // its corresponding base virtual method. This is to improve compatibility
3920 // with non-C# libraries which change the visibility of overrides (#75636)
3923 for (int i = 0; i < Methods.Length; ++i) {
3924 MethodBase m = Methods [i];
3925 if (TypeManager.IsOverride (m)) {
3926 if (candidate_overrides == null)
3927 candidate_overrides = new ArrayList ();
3928 candidate_overrides.Add (m);
3929 m = TypeManager.TryGetBaseDefinition (m);
3938 // Enable message recording, it's used mainly by lambda expressions
3940 Report.IMessageRecorder msg_recorder = new Report.MessageRecorder ();
3941 Report.IMessageRecorder prev_recorder = Report.SetMessageRecorder (msg_recorder);
3944 // First we construct the set of applicable methods
3946 bool is_sorted = true;
3947 int best_candidate_rate = int.MaxValue;
3948 for (int i = 0; i < nmethods; i++) {
3949 Type decl_type = Methods [i].DeclaringType;
3952 // If we have already found an applicable method
3953 // we eliminate all base types (Section 14.5.5.1)
3955 if (applicable_type != null && IsAncestralType (decl_type, applicable_type))
3959 // Check if candidate is applicable (section 14.4.2.1)
3961 bool params_expanded_form = false;
3962 int candidate_rate = IsApplicable (ec, Arguments, arg_count, ref Methods [i], ref params_expanded_form);
3964 if (candidate_rate < best_candidate_rate) {
3965 best_candidate_rate = candidate_rate;
3966 best_candidate = Methods [i];
3969 if (params_expanded_form) {
3970 if (candidate_to_form == null)
3971 candidate_to_form = new PtrHashtable ();
3972 MethodBase candidate = Methods [i];
3973 candidate_to_form [candidate] = candidate;
3976 if (candidate_rate != 0) {
3977 if (msg_recorder != null)
3978 msg_recorder.EndSession ();
3982 msg_recorder = null;
3983 candidates.Add (Methods [i]);
3985 if (applicable_type == null)
3986 applicable_type = decl_type;
3987 else if (applicable_type != decl_type) {
3989 if (IsAncestralType (applicable_type, decl_type))
3990 applicable_type = decl_type;
3994 Report.SetMessageRecorder (prev_recorder);
3995 if (msg_recorder != null && msg_recorder.PrintMessages ())
3998 int candidate_top = candidates.Count;
4000 if (applicable_type == null) {
4002 // When we found a top level method which does not match and it's
4003 // not an extension method. We start extension methods lookup from here
4005 if (InstanceExpression != null) {
4006 ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (type, Name);
4007 if (ex_method_lookup != null) {
4008 ex_method_lookup.ExtensionExpression = InstanceExpression;
4009 ex_method_lookup.SetTypeArguments (type_arguments);
4010 return ex_method_lookup.OverloadResolve (ec, ref Arguments, may_fail, loc);
4018 // Okay so we have failed to find exact match so we
4019 // return error info about the closest match
4021 if (best_candidate != null) {
4022 if (CustomErrorHandler != null) {
4023 if (CustomErrorHandler.NoExactMatch (ec, best_candidate))
4027 ParameterData pd = TypeManager.GetParameterData (best_candidate);
4028 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4029 if (arg_count == pd.Count || pd.HasParams) {
4030 if (TypeManager.IsGenericMethodDefinition (best_candidate)) {
4031 if (type_arguments == null) {
4032 Report.Error (411, loc,
4033 "The type arguments for method `{0}' cannot be inferred from " +
4034 "the usage. Try specifying the type arguments explicitly",
4035 TypeManager.CSharpSignature (best_candidate));
4039 Type [] g_args = TypeManager.GetGenericArguments (best_candidate);
4040 if (type_arguments.Count != g_args.Length) {
4041 Report.SymbolRelatedToPreviousError (best_candidate);
4042 Report.Error (305, loc, "Using the generic method `{0}' requires `{1}' type argument(s)",
4043 TypeManager.CSharpSignature (best_candidate),
4044 g_args.Length.ToString ());
4048 if (type_arguments != null && !TypeManager.IsGenericMethod (best_candidate)) {
4049 Namespace.Error_TypeArgumentsCannotBeUsed (best_candidate, loc);
4054 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate, cand_params, may_fail, loc))
4059 if (almost_matched_members.Count != 0) {
4060 Error_MemberLookupFailed (ec.ContainerType, type, type, ".ctor",
4061 null, MemberTypes.Constructor, AllBindingFlags);
4066 // We failed to find any method with correct argument count
4068 if (Name == ConstructorInfo.ConstructorName) {
4069 Report.SymbolRelatedToPreviousError (type);
4070 Report.Error (1729, loc,
4071 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4072 TypeManager.CSharpName (type), arg_count);
4074 Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4075 Name, arg_count.ToString ());
4083 // At this point, applicable_type is _one_ of the most derived types
4084 // in the set of types containing the methods in this MethodGroup.
4085 // Filter the candidates so that they only contain methods from the
4086 // most derived types.
4089 int finalized = 0; // Number of finalized candidates
4092 // Invariant: applicable_type is a most derived type
4094 // We'll try to complete Section 14.5.5.1 for 'applicable_type' by
4095 // eliminating all it's base types. At the same time, we'll also move
4096 // every unrelated type to the end of the array, and pick the next
4097 // 'applicable_type'.
4099 Type next_applicable_type = null;
4100 int j = finalized; // where to put the next finalized candidate
4101 int k = finalized; // where to put the next undiscarded candidate
4102 for (int i = finalized; i < candidate_top; ++i) {
4103 MethodBase candidate = (MethodBase) candidates [i];
4104 Type decl_type = candidate.DeclaringType;
4106 if (decl_type == applicable_type) {
4107 candidates [k++] = candidates [j];
4108 candidates [j++] = candidates [i];
4112 if (IsAncestralType (decl_type, applicable_type))
4115 if (next_applicable_type != null &&
4116 IsAncestralType (decl_type, next_applicable_type))
4119 candidates [k++] = candidates [i];
4121 if (next_applicable_type == null ||
4122 IsAncestralType (next_applicable_type, decl_type))
4123 next_applicable_type = decl_type;
4126 applicable_type = next_applicable_type;
4129 } while (applicable_type != null);
4133 // Now we actually find the best method
4136 best_candidate = (MethodBase) candidates [0];
4137 if (delegate_type == null)
4138 method_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4140 for (int ix = 1; ix < candidate_top; ix++) {
4141 MethodBase candidate = (MethodBase) candidates [ix];
4143 if (candidate == best_candidate)
4146 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4148 if (BetterFunction (ec, Arguments, arg_count,
4149 candidate, cand_params,
4150 best_candidate, method_params)) {
4151 best_candidate = candidate;
4152 method_params = cand_params;
4156 // Now check that there are no ambiguities i.e the selected method
4157 // should be better than all the others
4159 MethodBase ambiguous = null;
4160 for (int ix = 0; ix < candidate_top; ix++) {
4161 MethodBase candidate = (MethodBase) candidates [ix];
4163 if (candidate == best_candidate)
4166 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4167 if (!BetterFunction (ec, Arguments, arg_count,
4168 best_candidate, method_params,
4169 candidate, cand_params))
4172 Report.SymbolRelatedToPreviousError (candidate);
4173 ambiguous = candidate;
4177 if (ambiguous != null) {
4178 Report.SymbolRelatedToPreviousError (best_candidate);
4179 Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4180 TypeManager.CSharpSignature (ambiguous), TypeManager.CSharpSignature (best_candidate));
4185 // If the method is a virtual function, pick an override closer to the LHS type.
4187 if (!IsBase && best_candidate.IsVirtual) {
4188 if (TypeManager.IsOverride (best_candidate))
4189 throw new InternalErrorException (
4190 "Should not happen. An 'override' method took part in overload resolution: " + best_candidate);
4192 if (candidate_overrides != null) {
4193 Type[] gen_args = null;
4194 bool gen_override = false;
4195 if (TypeManager.IsGenericMethod (best_candidate))
4196 gen_args = TypeManager.GetGenericArguments (best_candidate);
4198 foreach (MethodBase candidate in candidate_overrides) {
4199 if (TypeManager.IsGenericMethod (candidate)) {
4200 if (gen_args == null)
4203 if (gen_args.Length != TypeManager.GetGenericArguments (candidate).Length)
4206 if (gen_args != null)
4210 if (IsOverride (candidate, best_candidate)) {
4211 gen_override = true;
4212 best_candidate = candidate;
4216 if (gen_override && gen_args != null) {
4218 best_candidate = ((MethodInfo) best_candidate).MakeGenericMethod (gen_args);
4225 // And now check if the arguments are all
4226 // compatible, perform conversions if
4227 // necessary etc. and return if everything is
4230 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate,
4231 method_params, may_fail, loc))
4234 if (best_candidate == null)
4237 MethodBase the_method = TypeManager.DropGenericMethodArguments (best_candidate);
4239 if (the_method.IsGenericMethodDefinition &&
4240 !ConstraintChecker.CheckConstraints (ec, the_method, best_candidate, loc))
4244 IMethodData data = TypeManager.GetMethod (the_method);
4246 data.SetMemberIsUsed ();
4251 public override void SetTypeArguments (TypeArguments ta)
4253 type_arguments = ta;
4256 public bool VerifyArgumentsCompat (EmitContext ec, ref ArrayList arguments,
4257 int arg_count, MethodBase method,
4258 bool chose_params_expanded,
4259 bool may_fail, Location loc)
4261 ParameterData pd = TypeManager.GetParameterData (method);
4263 int errors = Report.Errors;
4264 Parameter.Modifier p_mod = 0;
4266 int a_idx = 0, a_pos = 0;
4268 ArrayList params_initializers = null;
4270 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4271 a = (Argument) arguments [a_idx];
4272 if (p_mod != Parameter.Modifier.PARAMS) {
4273 p_mod = pd.ParameterModifier (a_idx);
4274 pt = pd.ParameterType (a_idx);
4276 if (p_mod == Parameter.Modifier.ARGLIST) {
4277 if (a.Type != TypeManager.runtime_argument_handle_type)
4282 if (pt.IsPointer && !ec.InUnsafe) {
4289 if (p_mod == Parameter.Modifier.PARAMS) {
4290 if (chose_params_expanded) {
4291 params_initializers = new ArrayList (arg_count - a_idx);
4292 pt = TypeManager.GetElementType (pt);
4294 } else if (p_mod != 0) {
4295 pt = TypeManager.GetElementType (pt);
4300 // Types have to be identical when ref or out modifer is used
4302 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4303 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4306 if (!TypeManager.IsEqual (a.Expr.Type, pt))
4313 if (TypeManager.IsEqual (a.Type, pt)) {
4316 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4322 // Convert params arguments to an array initializer
4324 if (params_initializers != null) {
4325 params_initializers.Add (conv);
4326 arguments.RemoveAt (a_idx--);
4331 // Update the argument with the implicit conversion
4336 // Fill not provided arguments required by params modifier
4338 if (params_initializers == null && pd.HasParams && arg_count < pd.Count) {
4339 if (arguments == null)
4340 arguments = new ArrayList (1);
4342 pt = pd.Types [GetApplicableParametersCount (method, pd) - 1];
4343 pt = TypeManager.GetElementType (pt);
4344 params_initializers = new ArrayList (0);
4347 if (a_idx == arg_count) {
4349 // Append an array argument with all params arguments
4351 if (params_initializers != null) {
4352 arguments.Add (new Argument (
4353 new ArrayCreation (new TypeExpression (pt, loc), "[]",
4354 params_initializers, loc).Resolve (ec)));
4359 if (!may_fail && Report.Errors == errors) {
4360 if (CustomErrorHandler != null)
4361 CustomErrorHandler.NoExactMatch (ec, best_candidate);
4363 Error_InvalidArguments (ec, loc, a_pos, method, a, pd, pt);
4369 public class ConstantExpr : MemberExpr
4373 public ConstantExpr (FieldInfo constant, Location loc)
4375 this.constant = constant;
4379 public override string Name {
4380 get { throw new NotImplementedException (); }
4383 public override bool IsInstance {
4384 get { return !IsStatic; }
4387 public override bool IsStatic {
4388 get { return constant.IsStatic; }
4391 public override Type DeclaringType {
4392 get { return constant.DeclaringType; }
4395 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc, SimpleName original)
4397 constant = TypeManager.GetGenericFieldDefinition (constant);
4399 IConstant ic = TypeManager.GetConstant (constant);
4401 if (constant.IsLiteral) {
4402 ic = new ExternalConstant (constant);
4404 ic = ExternalConstant.CreateDecimal (constant);
4405 // HACK: decimal field was not resolved as constant
4407 return new FieldExpr (constant, loc).ResolveMemberAccess (ec, left, loc, original);
4409 TypeManager.RegisterConstant (constant, ic);
4412 return base.ResolveMemberAccess (ec, left, loc, original);
4415 public override Expression DoResolve (EmitContext ec)
4417 IConstant ic = TypeManager.GetConstant (constant);
4418 if (ic.ResolveValue ()) {
4419 if (!ec.IsInObsoleteScope)
4420 ic.CheckObsoleteness (loc);
4423 return ic.CreateConstantReference (loc);
4426 public override void Emit (EmitContext ec)
4428 throw new NotSupportedException ();
4431 public override string GetSignatureForError ()
4433 return TypeManager.GetFullNameSignature (constant);
4438 /// Fully resolved expression that evaluates to a Field
4440 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariable {
4441 public readonly FieldInfo FieldInfo;
4442 VariableInfo variable_info;
4444 LocalTemporary temp;
4446 bool in_initializer;
4448 public FieldExpr (FieldInfo fi, Location l, bool in_initializer):
4451 this.in_initializer = in_initializer;
4454 public FieldExpr (FieldInfo fi, Location l)
4457 eclass = ExprClass.Variable;
4458 type = TypeManager.TypeToCoreType (fi.FieldType);
4462 public override string Name {
4464 return FieldInfo.Name;
4468 public override bool IsInstance {
4470 return !FieldInfo.IsStatic;
4474 public override bool IsStatic {
4476 return FieldInfo.IsStatic;
4480 public override Type DeclaringType {
4482 return FieldInfo.DeclaringType;
4486 public override string GetSignatureForError ()
4488 return TypeManager.GetFullNameSignature (FieldInfo);
4491 public VariableInfo VariableInfo {
4493 return variable_info;
4497 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
4498 SimpleName original)
4500 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
4501 Type t = fi.FieldType;
4503 if (t.IsPointer && !ec.InUnsafe) {
4507 return base.ResolveMemberAccess (ec, left, loc, original);
4510 override public Expression DoResolve (EmitContext ec)
4512 return DoResolve (ec, false, false);
4515 Expression DoResolve (EmitContext ec, bool lvalue_instance, bool out_access)
4517 if (!FieldInfo.IsStatic){
4518 if (InstanceExpression == null){
4520 // This can happen when referencing an instance field using
4521 // a fully qualified type expression: TypeName.InstanceField = xxx
4523 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4527 // Resolve the field's instance expression while flow analysis is turned
4528 // off: when accessing a field "a.b", we must check whether the field
4529 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4531 if (lvalue_instance) {
4532 using (ec.With (EmitContext.Flags.DoFlowAnalysis, false)) {
4533 Expression right_side =
4534 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4535 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side, loc);
4538 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
4539 InstanceExpression = InstanceExpression.Resolve (ec, rf);
4542 if (InstanceExpression == null)
4545 using (ec.Set (EmitContext.Flags.OmitStructFlowAnalysis)) {
4546 InstanceExpression.CheckMarshalByRefAccess (ec);
4550 if (!in_initializer && !ec.IsInFieldInitializer) {
4551 ObsoleteAttribute oa;
4552 FieldBase f = TypeManager.GetField (FieldInfo);
4554 if (!ec.IsInObsoleteScope)
4555 f.CheckObsoleteness (loc);
4557 // To be sure that type is external because we do not register generated fields
4558 } else if (!(FieldInfo.DeclaringType is TypeBuilder)) {
4559 oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
4561 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
4565 AnonymousContainer am = ec.CurrentAnonymousMethod;
4567 if (!FieldInfo.IsStatic){
4568 if (!am.IsIterator && (ec.TypeContainer is Struct)){
4569 Report.Error (1673, loc,
4570 "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",
4577 IFixedBuffer fb = AttributeTester.GetFixedBuffer (FieldInfo);
4579 if (!ec.InFixedInitializer && ec.ContainerType.IsValueType) {
4580 Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4583 if (InstanceExpression.eclass != ExprClass.Variable) {
4584 Report.SymbolRelatedToPreviousError (FieldInfo);
4585 Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4586 TypeManager.GetFullNameSignature (FieldInfo));
4589 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4592 // If the instance expression is a local variable or parameter.
4593 IVariable var = InstanceExpression as IVariable;
4594 if ((var == null) || (var.VariableInfo == null))
4597 VariableInfo vi = var.VariableInfo;
4598 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
4601 variable_info = vi.GetSubStruct (FieldInfo.Name);
4605 static readonly int [] codes = {
4606 191, // instance, write access
4607 192, // instance, out access
4608 198, // static, write access
4609 199, // static, out access
4610 1648, // member of value instance, write access
4611 1649, // member of value instance, out access
4612 1650, // member of value static, write access
4613 1651 // member of value static, out access
4616 static readonly string [] msgs = {
4617 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4618 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4619 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4620 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4621 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4622 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4623 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4624 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4627 // The return value is always null. Returning a value simplifies calling code.
4628 Expression Report_AssignToReadonly (Expression right_side)
4631 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4635 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4637 Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4642 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4644 IVariable var = InstanceExpression as IVariable;
4645 if ((var != null) && (var.VariableInfo != null))
4646 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
4648 bool lvalue_instance = !FieldInfo.IsStatic && FieldInfo.DeclaringType.IsValueType;
4649 bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
4651 Expression e = DoResolve (ec, lvalue_instance, out_access);
4656 FieldBase fb = TypeManager.GetField (FieldInfo);
4660 if (FieldInfo.IsInitOnly) {
4661 // InitOnly fields can only be assigned in constructors or initializers
4662 if (!ec.IsInFieldInitializer && !ec.IsConstructor)
4663 return Report_AssignToReadonly (right_side);
4665 if (ec.IsConstructor) {
4666 Type ctype = ec.TypeContainer.CurrentType;
4668 ctype = ec.ContainerType;
4670 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4671 if (!TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
4672 return Report_AssignToReadonly (right_side);
4673 // static InitOnly fields cannot be assigned-to in an instance constructor
4674 if (IsStatic && !ec.IsStatic)
4675 return Report_AssignToReadonly (right_side);
4676 // instance constructors can't modify InitOnly fields of other instances of the same type
4677 if (!IsStatic && !(InstanceExpression is This))
4678 return Report_AssignToReadonly (right_side);
4682 if (right_side == EmptyExpression.OutAccess &&
4683 !IsStatic && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type)) {
4684 Report.SymbolRelatedToPreviousError (DeclaringType);
4685 Report.Warning (197, 1, loc,
4686 "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",
4687 GetSignatureForError ());
4693 public override void CheckMarshalByRefAccess (EmitContext ec)
4695 if (!IsStatic && Type.IsValueType && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type)) {
4696 Report.SymbolRelatedToPreviousError (DeclaringType);
4697 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",
4698 GetSignatureForError ());
4702 public bool VerifyFixed ()
4704 IVariable variable = InstanceExpression as IVariable;
4705 // A variable of the form V.I is fixed when V is a fixed variable of a struct type.
4706 // We defer the InstanceExpression check after the variable check to avoid a
4707 // separate null check on InstanceExpression.
4708 return variable != null && InstanceExpression.Type.IsValueType && variable.VerifyFixed ();
4711 public override int GetHashCode ()
4713 return FieldInfo.GetHashCode ();
4716 public override bool Equals (object obj)
4718 FieldExpr fe = obj as FieldExpr;
4722 if (FieldInfo != fe.FieldInfo)
4725 if (InstanceExpression == null || fe.InstanceExpression == null)
4728 return InstanceExpression.Equals (fe.InstanceExpression);
4731 public void Emit (EmitContext ec, bool leave_copy)
4733 ILGenerator ig = ec.ig;
4734 bool is_volatile = false;
4736 FieldBase f = TypeManager.GetField (FieldInfo);
4738 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4741 f.SetMemberIsUsed ();
4744 if (FieldInfo.IsStatic){
4746 ig.Emit (OpCodes.Volatile);
4748 ig.Emit (OpCodes.Ldsfld, FieldInfo);
4751 EmitInstance (ec, false);
4753 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
4755 ig.Emit (OpCodes.Ldflda, FieldInfo);
4756 ig.Emit (OpCodes.Ldflda, ff.Element);
4759 ig.Emit (OpCodes.Volatile);
4761 ig.Emit (OpCodes.Ldfld, FieldInfo);
4766 ec.ig.Emit (OpCodes.Dup);
4767 if (!FieldInfo.IsStatic) {
4768 temp = new LocalTemporary (this.Type);
4774 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4776 FieldAttributes fa = FieldInfo.Attributes;
4777 bool is_static = (fa & FieldAttributes.Static) != 0;
4778 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
4779 ILGenerator ig = ec.ig;
4781 if (is_readonly && !ec.IsConstructor){
4782 Report_AssignToReadonly (source);
4787 // String concatenation creates a new string instance
4789 prepared = prepare_for_load && !(source is StringConcat);
4790 EmitInstance (ec, prepared);
4794 ec.ig.Emit (OpCodes.Dup);
4795 if (!FieldInfo.IsStatic) {
4796 temp = new LocalTemporary (this.Type);
4801 FieldBase f = TypeManager.GetField (FieldInfo);
4803 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4804 ig.Emit (OpCodes.Volatile);
4810 ig.Emit (OpCodes.Stsfld, FieldInfo);
4812 ig.Emit (OpCodes.Stfld, FieldInfo);
4820 public override void Emit (EmitContext ec)
4825 public void AddressOf (EmitContext ec, AddressOp mode)
4827 ILGenerator ig = ec.ig;
4829 FieldBase f = TypeManager.GetField (FieldInfo);
4831 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
4832 Report.Warning (420, 1, loc, "`{0}': A volatile field references will not be treated as volatile",
4833 f.GetSignatureForError ());
4836 if ((mode & AddressOp.Store) != 0)
4838 if ((mode & AddressOp.Load) != 0)
4839 f.SetMemberIsUsed ();
4843 // Handle initonly fields specially: make a copy and then
4844 // get the address of the copy.
4847 if (FieldInfo.IsInitOnly){
4849 if (ec.IsConstructor){
4850 if (FieldInfo.IsStatic){
4862 local = ig.DeclareLocal (type);
4863 ig.Emit (OpCodes.Stloc, local);
4864 ig.Emit (OpCodes.Ldloca, local);
4869 if (FieldInfo.IsStatic){
4870 ig.Emit (OpCodes.Ldsflda, FieldInfo);
4873 EmitInstance (ec, false);
4874 ig.Emit (OpCodes.Ldflda, FieldInfo);
4881 /// Expression that evaluates to a Property. The Assign class
4882 /// might set the `Value' expression if we are in an assignment.
4884 /// This is not an LValue because we need to re-write the expression, we
4885 /// can not take data from the stack and store it.
4887 public class PropertyExpr : MemberExpr, IAssignMethod {
4888 public readonly PropertyInfo PropertyInfo;
4889 MethodInfo getter, setter;
4894 LocalTemporary temp;
4897 public PropertyExpr (Type container_type, PropertyInfo pi, Location l)
4900 eclass = ExprClass.PropertyAccess;
4904 type = TypeManager.TypeToCoreType (pi.PropertyType);
4906 ResolveAccessors (container_type);
4909 public override string Name {
4911 return PropertyInfo.Name;
4915 public override bool IsInstance {
4921 public override bool IsStatic {
4927 public override Expression CreateExpressionTree (EmitContext ec)
4929 if (IsSingleDimensionalArrayLength ()) {
4930 ArrayList args = new ArrayList (1);
4931 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
4932 return CreateExpressionFactoryCall ("ArrayLength", args);
4935 // TODO: it's waiting for PropertyExpr refactoring
4936 //ArrayList args = new ArrayList (2);
4937 //args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
4938 //args.Add (getter expression);
4939 //return CreateExpressionFactoryCall ("Property", args);
4940 return base.CreateExpressionTree (ec);
4943 public override Type DeclaringType {
4945 return PropertyInfo.DeclaringType;
4949 public override string GetSignatureForError ()
4951 return TypeManager.GetFullNameSignature (PropertyInfo);
4954 void FindAccessors (Type invocation_type)
4956 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
4957 BindingFlags.Static | BindingFlags.Instance |
4958 BindingFlags.DeclaredOnly;
4960 Type current = PropertyInfo.DeclaringType;
4961 for (; current != null; current = current.BaseType) {
4962 MemberInfo[] group = TypeManager.MemberLookup (
4963 invocation_type, invocation_type, current,
4964 MemberTypes.Property, flags, PropertyInfo.Name, null);
4969 if (group.Length != 1)
4970 // Oooops, can this ever happen ?
4973 PropertyInfo pi = (PropertyInfo) group [0];
4976 getter = pi.GetGetMethod (true);
4979 setter = pi.GetSetMethod (true);
4981 MethodInfo accessor = getter != null ? getter : setter;
4983 if (!accessor.IsVirtual)
4989 // We also perform the permission checking here, as the PropertyInfo does not
4990 // hold the information for the accessibility of its setter/getter
4992 // TODO: Refactor to use some kind of cache together with GetPropertyFromAccessor
4993 void ResolveAccessors (Type container_type)
4995 FindAccessors (container_type);
4997 if (getter != null) {
4998 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
4999 IMethodData md = TypeManager.GetMethod (the_getter);
5001 md.SetMemberIsUsed ();
5003 is_static = getter.IsStatic;
5006 if (setter != null) {
5007 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
5008 IMethodData md = TypeManager.GetMethod (the_setter);
5010 md.SetMemberIsUsed ();
5012 is_static = setter.IsStatic;
5016 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
5019 InstanceExpression = null;
5023 if (InstanceExpression == null) {
5024 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5028 InstanceExpression = InstanceExpression.DoResolve (ec);
5029 if (lvalue_instance && InstanceExpression != null)
5030 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
5032 if (InstanceExpression == null)
5035 InstanceExpression.CheckMarshalByRefAccess (ec);
5037 if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) &&
5038 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
5039 !TypeManager.IsNestedChildOf (ec.ContainerType, InstanceExpression.Type) &&
5040 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.ContainerType)) {
5041 Report.SymbolRelatedToPreviousError (PropertyInfo);
5042 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
5049 void Error_PropertyNotFound (MethodInfo mi, bool getter)
5051 // TODO: correctly we should compare arguments but it will lead to bigger changes
5052 if (mi is MethodBuilder) {
5053 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
5057 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
5059 ParameterData iparams = TypeManager.GetParameterData (mi);
5060 sig.Append (getter ? "get_" : "set_");
5062 sig.Append (iparams.GetSignatureForError ());
5064 Report.SymbolRelatedToPreviousError (mi);
5065 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
5066 Name, sig.ToString ());
5069 public bool IsAccessibleFrom (Type invocation_type, bool lvalue)
5072 MethodInfo accessor = lvalue ? setter : getter;
5073 if (accessor == null && lvalue)
5075 return accessor != null && IsAccessorAccessible (invocation_type, accessor, out dummy);
5078 bool IsSingleDimensionalArrayLength ()
5080 return DeclaringType == TypeManager.array_type && getter != null && getter.Name == "Length";
5083 override public Expression DoResolve (EmitContext ec)
5088 if (getter != null){
5089 if (TypeManager.GetParameterData (getter).Count != 0){
5090 Error_PropertyNotFound (getter, true);
5095 if (getter == null){
5097 // The following condition happens if the PropertyExpr was
5098 // created, but is invalid (ie, the property is inaccessible),
5099 // and we did not want to embed the knowledge about this in
5100 // the caller routine. This only avoids double error reporting.
5105 if (InstanceExpression != EmptyExpression.Null) {
5106 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5107 TypeManager.GetFullNameSignature (PropertyInfo));
5112 bool must_do_cs1540_check = false;
5113 if (getter != null &&
5114 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
5115 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
5116 if (pm != null && pm.HasCustomAccessModifier) {
5117 Report.SymbolRelatedToPreviousError (pm);
5118 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5119 TypeManager.CSharpSignature (getter));
5122 Report.SymbolRelatedToPreviousError (getter);
5123 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
5128 if (!InstanceResolve (ec, false, must_do_cs1540_check))
5132 // Only base will allow this invocation to happen.
5134 if (IsBase && getter.IsAbstract) {
5135 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5139 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
5149 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
5151 if (right_side == EmptyExpression.OutAccess) {
5152 if (ec.CurrentBlock.Toplevel.GetTransparentIdentifier (PropertyInfo.Name) != null) {
5153 Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5156 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as `ref' or `out' parameter",
5157 GetSignatureForError ());
5162 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5163 Error_CannotModifyIntermediateExpressionValue (ec);
5166 if (setter == null){
5168 // The following condition happens if the PropertyExpr was
5169 // created, but is invalid (ie, the property is inaccessible),
5170 // and we did not want to embed the knowledge about this in
5171 // the caller routine. This only avoids double error reporting.
5175 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
5176 GetSignatureForError ());
5180 if (TypeManager.GetParameterData (setter).Count != 1){
5181 Error_PropertyNotFound (setter, false);
5185 bool must_do_cs1540_check;
5186 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
5187 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
5188 if (pm != null && pm.HasCustomAccessModifier) {
5189 Report.SymbolRelatedToPreviousError (pm);
5190 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5191 TypeManager.CSharpSignature (setter));
5194 Report.SymbolRelatedToPreviousError (setter);
5195 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
5200 if (!InstanceResolve (ec, PropertyInfo.DeclaringType.IsValueType, must_do_cs1540_check))
5204 // Only base will allow this invocation to happen.
5206 if (IsBase && setter.IsAbstract){
5207 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5214 public override void Emit (EmitContext ec)
5219 public void Emit (EmitContext ec, bool leave_copy)
5222 // Special case: length of single dimension array property is turned into ldlen
5224 if (IsSingleDimensionalArrayLength ()) {
5226 EmitInstance (ec, false);
5227 ec.ig.Emit (OpCodes.Ldlen);
5228 ec.ig.Emit (OpCodes.Conv_I4);
5232 Invocation.EmitCall (ec, IsBase, InstanceExpression, getter, null, loc, prepared, false);
5235 ec.ig.Emit (OpCodes.Dup);
5237 temp = new LocalTemporary (this.Type);
5244 // Implements the IAssignMethod interface for assignments
5246 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5248 Expression my_source = source;
5250 if (prepare_for_load) {
5251 if (source is StringConcat)
5252 EmitInstance (ec, false);
5260 ec.ig.Emit (OpCodes.Dup);
5262 temp = new LocalTemporary (this.Type);
5266 } else if (leave_copy) {
5268 temp = new LocalTemporary (this.Type);
5273 ArrayList args = new ArrayList (1);
5274 args.Add (new Argument (my_source, Argument.AType.Expression));
5276 Invocation.EmitCall (ec, IsBase, InstanceExpression, setter, args, loc, false, prepared);
5286 /// Fully resolved expression that evaluates to an Event
5288 public class EventExpr : MemberExpr {
5289 public readonly EventInfo EventInfo;
5292 MethodInfo add_accessor, remove_accessor;
5294 public EventExpr (EventInfo ei, Location loc)
5298 eclass = ExprClass.EventAccess;
5300 add_accessor = TypeManager.GetAddMethod (ei);
5301 remove_accessor = TypeManager.GetRemoveMethod (ei);
5302 if (add_accessor.IsStatic || remove_accessor.IsStatic)
5305 if (EventInfo is MyEventBuilder){
5306 MyEventBuilder eb = (MyEventBuilder) EventInfo;
5307 type = eb.EventType;
5310 type = EventInfo.EventHandlerType;
5313 public override string Name {
5315 return EventInfo.Name;
5319 public override bool IsInstance {
5325 public override bool IsStatic {
5331 public override Type DeclaringType {
5333 return EventInfo.DeclaringType;
5337 void Error_AssignmentEventOnly ()
5339 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5340 GetSignatureForError ());
5343 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
5344 SimpleName original)
5347 // If the event is local to this class, we transform ourselves into a FieldExpr
5350 if (EventInfo.DeclaringType == ec.ContainerType ||
5351 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
5352 EventField mi = TypeManager.GetEventField (EventInfo);
5355 if (!ec.IsInObsoleteScope)
5356 mi.CheckObsoleteness (loc);
5358 if ((mi.ModFlags & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0 && !ec.IsInCompoundAssignment)
5359 Error_AssignmentEventOnly ();
5361 FieldExpr ml = new FieldExpr (mi.FieldBuilder, loc);
5363 InstanceExpression = null;
5365 return ml.ResolveMemberAccess (ec, left, loc, original);
5369 if (left is This && !ec.IsInCompoundAssignment)
5370 Error_AssignmentEventOnly ();
5372 return base.ResolveMemberAccess (ec, left, loc, original);
5376 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
5379 InstanceExpression = null;
5383 if (InstanceExpression == null) {
5384 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5388 InstanceExpression = InstanceExpression.DoResolve (ec);
5389 if (InstanceExpression == null)
5392 if (IsBase && add_accessor.IsAbstract) {
5393 Error_CannotCallAbstractBase(TypeManager.CSharpSignature(add_accessor));
5398 // This is using the same mechanism as the CS1540 check in PropertyExpr.
5399 // However, in the Event case, we reported a CS0122 instead.
5401 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
5402 InstanceExpression.Type != ec.ContainerType &&
5403 TypeManager.IsSubclassOf (ec.ContainerType, InstanceExpression.Type)) {
5404 Report.SymbolRelatedToPreviousError (EventInfo);
5405 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5412 public bool IsAccessibleFrom (Type invocation_type)
5415 return IsAccessorAccessible (invocation_type, add_accessor, out dummy) &&
5416 IsAccessorAccessible (invocation_type, remove_accessor, out dummy);
5419 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5421 return DoResolve (ec);
5424 public override Expression DoResolve (EmitContext ec)
5426 bool must_do_cs1540_check;
5427 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
5428 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
5429 Report.SymbolRelatedToPreviousError (EventInfo);
5430 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5434 if (!InstanceResolve (ec, must_do_cs1540_check))
5440 public override void Emit (EmitContext ec)
5442 Report.Error (70, loc, "The event `{0}' can only appear on the left hand side of += or -= "+
5443 "(except on the defining type)", GetSignatureForError ());
5446 public override string GetSignatureForError ()
5448 return TypeManager.CSharpSignature (EventInfo);
5451 public void EmitAddOrRemove (EmitContext ec, Expression source)
5453 BinaryDelegate source_del = source as BinaryDelegate;
5454 if (source_del == null) {
5458 Expression handler = source_del.Right;
5460 Argument arg = new Argument (handler, Argument.AType.Expression);
5461 ArrayList args = new ArrayList ();
5465 if (source_del.IsAddition)
5466 Invocation.EmitCall (
5467 ec, IsBase, InstanceExpression, add_accessor, args, loc);
5469 Invocation.EmitCall (
5470 ec, IsBase, InstanceExpression, remove_accessor, args, loc);
5474 public class TemporaryVariable : Expression, IMemoryLocation
5479 public TemporaryVariable (Type type, Location loc)
5483 eclass = ExprClass.Value;
5486 public override Expression DoResolve (EmitContext ec)
5491 TypeExpr te = new TypeExpression (type, loc);
5492 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
5493 if (!li.Resolve (ec))
5496 if (ec.MustCaptureVariable (li)) {
5497 ScopeInfo scope = li.Block.CreateScopeInfo ();
5498 var = scope.AddLocal (li);
5505 public Variable Variable {
5506 get { return var != null ? var : li.Variable; }
5509 public override void Emit (EmitContext ec)
5511 Variable.EmitInstance (ec);
5515 public void EmitLoadAddress (EmitContext ec)
5517 Variable.EmitInstance (ec);
5518 Variable.EmitAddressOf (ec);
5521 public void Store (EmitContext ec, Expression right_side)
5523 Variable.EmitInstance (ec);
5524 right_side.Emit (ec);
5525 Variable.EmitAssign (ec);
5528 public void EmitThis (EmitContext ec)
5530 Variable.EmitInstance (ec);
5533 public void EmitStore (EmitContext ec)
5535 Variable.EmitAssign (ec);
5538 public void AddressOf (EmitContext ec, AddressOp mode)
5540 EmitLoadAddress (ec);
5545 /// Handles `var' contextual keyword; var becomes a keyword only
5546 /// if no type called var exists in a variable scope
5548 public class VarExpr : SimpleName
5550 // Used for error reporting only
5551 ArrayList initializer;
5553 public VarExpr (Location loc)
5558 public ArrayList VariableInitializer {
5560 this.initializer = value;
5564 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5567 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
5569 type = right_side.Type;
5570 if (type == TypeManager.null_type || type == TypeManager.void_type || type == TypeManager.anonymous_method_type) {
5571 Report.Error (815, loc, "An implicitly typed local variable declaration cannot be initialized with `{0}'",
5572 right_side.GetSignatureForError ());
5576 eclass = ExprClass.Variable;
5580 protected override void Error_TypeOrNamespaceNotFound (IResolveContext ec)
5582 Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");
5585 public override TypeExpr ResolveAsContextualType (IResolveContext rc, bool silent)
5587 TypeExpr te = base.ResolveAsContextualType (rc, true);
5591 if (initializer == null)
5594 if (initializer.Count > 1) {
5595 Location loc = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [1]).Location;
5596 Report.Error (819, loc, "An implicitly typed local variable declaration cannot include multiple declarators");
5601 Expression variable_initializer = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [0]).expression_or_array_initializer;
5602 if (variable_initializer == null) {
5603 Report.Error (818, loc, "An implicitly typed local variable declarator must include an initializer");