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 DoResolve (EmitContext ec)
1999 // This should never be invoked, we are born in fully
2000 // initialized state.
2005 public override void Emit (EmitContext ec)
2014 public Type UnderlyingType {
2015 get { return child.Type; }
2020 /// This kind of cast is used to encapsulate a child and cast it
2021 /// to the class requested
2023 public class ClassCast : EmptyCast {
2024 public ClassCast (Expression child, Type return_type)
2025 : base (child, return_type)
2030 public override Expression DoResolve (EmitContext ec)
2032 // This should never be invoked, we are born in fully
2033 // initialized state.
2038 public override void Emit (EmitContext ec)
2042 if (TypeManager.IsGenericParameter (child.Type))
2043 ec.ig.Emit (OpCodes.Box, child.Type);
2046 if (type.IsGenericParameter)
2047 ec.ig.Emit (OpCodes.Unbox_Any, type);
2050 ec.ig.Emit (OpCodes.Castclass, type);
2055 // Used when resolved expression has different representations for
2056 // expression trees and emit phase
2058 public class ReducedExpression : Expression
2060 class ReducedConstantExpression : Constant
2062 readonly Constant expr;
2063 readonly Expression orig_expr;
2065 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2066 : base (expr.Location)
2069 this.orig_expr = orig_expr;
2070 eclass = expr.eclass;
2074 public override string AsString ()
2076 return expr.AsString ();
2079 public override Expression CreateExpressionTree (EmitContext ec)
2081 return orig_expr.CreateExpressionTree (ec);
2084 public override object GetValue ()
2086 return expr.GetValue ();
2089 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
2091 throw new NotImplementedException ();
2094 public override Expression DoResolve (EmitContext ec)
2099 public override Constant Increment ()
2101 throw new NotImplementedException ();
2104 public override bool IsDefaultValue {
2106 return expr.IsDefaultValue;
2110 public override bool IsNegative {
2112 return expr.IsNegative;
2116 public override void Emit (EmitContext ec)
2122 readonly Expression expr, orig_expr;
2124 private ReducedExpression (Expression expr, Expression orig_expr)
2127 this.orig_expr = orig_expr;
2130 public static Expression Create (Constant expr, Expression original_expr)
2132 return new ReducedConstantExpression (expr, original_expr);
2135 public static Expression Create (Expression expr, Expression original_expr)
2137 Constant c = expr as Constant;
2139 return Create (c, original_expr);
2141 return new ReducedExpression (expr, original_expr);
2144 public override Expression CreateExpressionTree (EmitContext ec)
2146 return orig_expr.CreateExpressionTree (ec);
2149 public override Expression DoResolve (EmitContext ec)
2151 eclass = expr.eclass;
2156 public override void Emit (EmitContext ec)
2161 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2163 expr.EmitBranchable (ec, target, on_true);
2168 /// SimpleName expressions are formed of a single word and only happen at the beginning
2169 /// of a dotted-name.
2171 public class SimpleName : Expression {
2172 public readonly string Name;
2173 public readonly TypeArguments Arguments;
2176 public SimpleName (string name, Location l)
2182 public SimpleName (string name, TypeArguments args, Location l)
2189 public SimpleName (string name, TypeParameter[] type_params, Location l)
2194 Arguments = new TypeArguments (l);
2195 foreach (TypeParameter type_param in type_params)
2196 Arguments.Add (new TypeParameterExpr (type_param, l));
2199 public static string RemoveGenericArity (string name)
2202 StringBuilder sb = null;
2204 int pos = name.IndexOf ('`', start);
2209 sb.Append (name.Substring (start));
2214 sb = new StringBuilder ();
2215 sb.Append (name.Substring (start, pos-start));
2218 while ((pos < name.Length) && Char.IsNumber (name [pos]))
2222 } while (start < name.Length);
2224 return sb.ToString ();
2227 public SimpleName GetMethodGroup ()
2229 return new SimpleName (RemoveGenericArity (Name), Arguments, loc);
2232 public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
2234 if (ec.IsInFieldInitializer)
2235 Report.Error (236, l,
2236 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2240 120, l, "`{0}': An object reference is required for the nonstatic field, method or property",
2244 public bool IdenticalNameAndTypeName (EmitContext ec, Expression resolved_to, Location loc)
2246 return resolved_to != null && resolved_to.Type != null &&
2247 resolved_to.Type.Name == Name &&
2248 (ec.DeclContainer.LookupNamespaceOrType (Name, loc, /* ignore_cs0104 = */ true) != null);
2251 public override Expression DoResolve (EmitContext ec)
2253 return SimpleNameResolve (ec, null, false);
2256 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
2258 return SimpleNameResolve (ec, right_side, false);
2262 public Expression DoResolve (EmitContext ec, bool intermediate)
2264 return SimpleNameResolve (ec, null, intermediate);
2267 static bool IsNestedChild (Type t, Type parent)
2269 while (parent != null) {
2270 if (TypeManager.IsNestedChildOf (t, TypeManager.DropGenericTypeArguments (parent)))
2273 parent = parent.BaseType;
2279 FullNamedExpression ResolveNested (IResolveContext ec, Type t)
2281 if (!TypeManager.IsGenericTypeDefinition (t) && !TypeManager.IsGenericType (t))
2284 DeclSpace ds = ec.DeclContainer;
2285 while (ds != null && !IsNestedChild (t, ds.TypeBuilder))
2291 Type[] gen_params = TypeManager.GetTypeArguments (t);
2293 int arg_count = Arguments != null ? Arguments.Count : 0;
2295 for (; (ds != null) && ds.IsGeneric; ds = ds.Parent) {
2296 if (arg_count + ds.CountTypeParameters == gen_params.Length) {
2297 TypeArguments new_args = new TypeArguments (loc);
2298 foreach (TypeParameter param in ds.TypeParameters)
2299 new_args.Add (new TypeParameterExpr (param, loc));
2301 if (Arguments != null)
2302 new_args.Add (Arguments);
2304 return new ConstructedType (t, new_args, loc);
2311 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2313 FullNamedExpression fne = ec.GenericDeclContainer.LookupGeneric (Name, loc);
2315 return fne.ResolveAsTypeStep (ec, silent);
2317 int errors = Report.Errors;
2318 fne = ec.DeclContainer.LookupNamespaceOrType (Name, loc, /*ignore_cs0104=*/ false);
2321 if (fne.Type == null)
2324 FullNamedExpression nested = ResolveNested (ec, fne.Type);
2326 return nested.ResolveAsTypeStep (ec, false);
2328 if (Arguments != null) {
2329 ConstructedType ct = new ConstructedType (fne, Arguments, loc);
2330 return ct.ResolveAsTypeStep (ec, false);
2336 if (silent || errors != Report.Errors)
2339 Error_TypeOrNamespaceNotFound (ec);
2343 protected virtual void Error_TypeOrNamespaceNotFound (IResolveContext ec)
2345 MemberCore mc = ec.DeclContainer.GetDefinition (Name);
2347 Error_UnexpectedKind (ec.DeclContainer, "type", GetMemberType (mc), loc);
2351 string ns = ec.DeclContainer.NamespaceEntry.NS.Name;
2352 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2353 foreach (Assembly a in RootNamespace.Global.Assemblies) {
2354 Type type = a.GetType (fullname);
2356 Report.SymbolRelatedToPreviousError (type);
2357 Expression.ErrorIsInaccesible (loc, TypeManager.CSharpName (type));
2362 Type t = ec.DeclContainer.LookupAnyGeneric (Name);
2364 Namespace.Error_InvalidNumberOfTypeArguments (t, loc);
2368 if (Arguments != null) {
2369 FullNamedExpression retval = ec.DeclContainer.LookupNamespaceOrType (SimpleName.RemoveGenericArity (Name), loc, true);
2370 if (retval != null) {
2371 Namespace.Error_TypeArgumentsCannotBeUsed (retval.Type, loc);
2376 NamespaceEntry.Error_NamespaceNotFound (loc, Name);
2379 // TODO: I am still not convinced about this. If someone else will need it
2380 // implement this as virtual property in MemberCore hierarchy
2381 public static string GetMemberType (MemberCore mc)
2387 if (mc is FieldBase)
2389 if (mc is MethodCore)
2391 if (mc is EnumMember)
2399 Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2405 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2411 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2418 /// 7.5.2: Simple Names.
2420 /// Local Variables and Parameters are handled at
2421 /// parse time, so they never occur as SimpleNames.
2423 /// The `intermediate' flag is used by MemberAccess only
2424 /// and it is used to inform us that it is ok for us to
2425 /// avoid the static check, because MemberAccess might end
2426 /// up resolving the Name as a Type name and the access as
2427 /// a static type access.
2429 /// ie: Type Type; .... { Type.GetType (""); }
2431 /// Type is both an instance variable and a Type; Type.GetType
2432 /// is the static method not an instance method of type.
2434 Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2436 Expression e = null;
2439 // Stage 1: Performed by the parser (binding to locals or parameters).
2441 Block current_block = ec.CurrentBlock;
2442 if (current_block != null){
2443 LocalInfo vi = current_block.GetLocalInfo (Name);
2445 if (Arguments != null) {
2446 Report.Error (307, loc,
2447 "The variable `{0}' cannot be used with type arguments",
2452 LocalVariableReference var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2453 if (right_side != null) {
2454 return var.ResolveLValue (ec, right_side, loc);
2456 ResolveFlags rf = ResolveFlags.VariableOrValue;
2458 rf |= ResolveFlags.DisableFlowAnalysis;
2459 return var.Resolve (ec, rf);
2463 ParameterReference pref = current_block.Toplevel.GetParameterReference (Name, loc);
2465 if (Arguments != null) {
2466 Report.Error (307, loc,
2467 "The variable `{0}' cannot be used with type arguments",
2472 if (right_side != null)
2473 return pref.ResolveLValue (ec, right_side, loc);
2475 return pref.Resolve (ec);
2478 Expression expr = current_block.Toplevel.GetTransparentIdentifier (Name);
2480 if (right_side != null)
2481 return expr.ResolveLValue (ec, right_side, loc);
2482 return expr.Resolve (ec);
2487 // Stage 2: Lookup members
2490 Type almost_matched_type = null;
2491 ArrayList almost_matched = null;
2492 for (DeclSpace lookup_ds = ec.DeclContainer; lookup_ds != null; lookup_ds = lookup_ds.Parent) {
2493 // either RootDeclSpace or GenericMethod
2494 if (lookup_ds.TypeBuilder == null)
2497 e = MemberLookup (ec.ContainerType, lookup_ds.TypeBuilder, Name, loc);
2499 if (e is PropertyExpr) {
2500 // since TypeManager.MemberLookup doesn't know if we're doing a lvalue access or not,
2501 // it doesn't know which accessor to check permissions against
2502 if (((PropertyExpr) e).IsAccessibleFrom (ec.ContainerType, right_side != null))
2504 } else if (e is EventExpr) {
2505 if (((EventExpr) e).IsAccessibleFrom (ec.ContainerType))
2513 if (almost_matched == null && almost_matched_members.Count > 0) {
2514 almost_matched_type = lookup_ds.TypeBuilder;
2515 almost_matched = (ArrayList) almost_matched_members.Clone ();
2520 if (almost_matched == null && almost_matched_members.Count > 0) {
2521 almost_matched_type = ec.ContainerType;
2522 almost_matched = (ArrayList) almost_matched_members.Clone ();
2524 e = ResolveAsTypeStep (ec, true);
2528 if (current_block != null) {
2529 IKnownVariable ikv = current_block.Explicit.GetKnownVariable (Name);
2531 LocalInfo li = ikv as LocalInfo;
2532 // Supress CS0219 warning
2536 Error_VariableIsUsedBeforeItIsDeclared (Name);
2541 if (almost_matched != null)
2542 almost_matched_members = almost_matched;
2543 if (almost_matched_type == null)
2544 almost_matched_type = ec.ContainerType;
2545 Error_MemberLookupFailed (ec.ContainerType, null, almost_matched_type, Name,
2546 ec.DeclContainer.Name, AllMemberTypes, AllBindingFlags);
2550 if (e is TypeExpr) {
2551 if (Arguments == null)
2554 ConstructedType ct = new ConstructedType (
2555 (FullNamedExpression) e, Arguments, loc);
2556 return ct.ResolveAsTypeStep (ec, false);
2559 if (e is MemberExpr) {
2560 MemberExpr me = (MemberExpr) e;
2563 if (me.IsInstance) {
2564 if (ec.IsStatic || ec.IsInFieldInitializer) {
2566 // Note that an MemberExpr can be both IsInstance and IsStatic.
2567 // An unresolved MethodGroupExpr can contain both kinds of methods
2568 // and each predicate is true if the MethodGroupExpr contains
2569 // at least one of that kind of method.
2573 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2574 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2579 // Pass the buck to MemberAccess and Invocation.
2581 left = EmptyExpression.Null;
2583 left = ec.GetThis (loc);
2586 left = new TypeExpression (ec.ContainerType, loc);
2589 me = me.ResolveMemberAccess (ec, left, loc, null);
2593 if (Arguments != null) {
2594 Arguments.Resolve (ec);
2595 me.SetTypeArguments (Arguments);
2598 if (!me.IsStatic && (me.InstanceExpression != null) &&
2599 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2600 me.InstanceExpression.Type != me.DeclaringType &&
2601 !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2602 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2603 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2604 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2608 return (right_side != null)
2609 ? me.DoResolveLValue (ec, right_side)
2610 : me.DoResolve (ec);
2616 public override void Emit (EmitContext ec)
2618 throw new InternalErrorException ("The resolve phase was not executed");
2621 public override string ToString ()
2626 public override string GetSignatureForError ()
2628 if (Arguments != null) {
2629 return TypeManager.RemoveGenericArity (Name) + "<" +
2630 Arguments.GetSignatureForError () + ">";
2636 protected override void CloneTo (CloneContext clonectx, Expression target)
2638 // CloneTo: Nothing, we do not keep any state on this expression
2643 /// Represents a namespace or a type. The name of the class was inspired by
2644 /// section 10.8.1 (Fully Qualified Names).
2646 public abstract class FullNamedExpression : Expression {
2647 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2652 public abstract string FullName {
2658 /// Expression that evaluates to a type
2660 public abstract class TypeExpr : FullNamedExpression {
2661 override public FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2663 TypeExpr t = DoResolveAsTypeStep (ec);
2667 eclass = ExprClass.Type;
2671 override public Expression DoResolve (EmitContext ec)
2673 return ResolveAsTypeTerminal (ec, false);
2676 override public void Emit (EmitContext ec)
2678 throw new Exception ("Should never be called");
2681 public virtual bool CheckAccessLevel (DeclSpace ds)
2683 return ds.CheckAccessLevel (Type);
2686 public virtual bool AsAccessible (DeclSpace ds)
2688 return ds.IsAccessibleAs (Type);
2691 public virtual bool IsClass {
2692 get { return Type.IsClass; }
2695 public virtual bool IsValueType {
2696 get { return Type.IsValueType; }
2699 public virtual bool IsInterface {
2700 get { return Type.IsInterface; }
2703 public virtual bool IsSealed {
2704 get { return Type.IsSealed; }
2707 public virtual bool CanInheritFrom ()
2709 if (Type == TypeManager.enum_type ||
2710 (Type == TypeManager.value_type && RootContext.StdLib) ||
2711 Type == TypeManager.multicast_delegate_type ||
2712 Type == TypeManager.delegate_type ||
2713 Type == TypeManager.array_type)
2719 protected abstract TypeExpr DoResolveAsTypeStep (IResolveContext ec);
2721 public abstract string Name {
2725 public override bool Equals (object obj)
2727 TypeExpr tobj = obj as TypeExpr;
2731 return Type == tobj.Type;
2734 public override int GetHashCode ()
2736 return Type.GetHashCode ();
2739 public override string ToString ()
2746 /// Fully resolved Expression that already evaluated to a type
2748 public class TypeExpression : TypeExpr {
2749 public TypeExpression (Type t, Location l)
2752 eclass = ExprClass.Type;
2756 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2761 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2766 public override string Name {
2767 get { return Type.ToString (); }
2770 public override string FullName {
2771 get { return Type.FullName; }
2776 /// Used to create types from a fully qualified name. These are just used
2777 /// by the parser to setup the core types. A TypeLookupExpression is always
2778 /// classified as a type.
2780 public sealed class TypeLookupExpression : TypeExpr {
2781 readonly string name;
2783 public TypeLookupExpression (string name)
2786 eclass = ExprClass.Type;
2789 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2791 // It's null for corlib compilation only
2793 return DoResolveAsTypeStep (ec);
2798 private class UnexpectedType
2802 // This performes recursive type lookup, providing support for generic types.
2803 // For example, given the type:
2805 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]]
2807 // The types will be checked in the following order:
2810 // System.Collections |
2811 // System.Collections.Generic |
2813 // System | recursive call 1 |
2814 // System.Int32 _| | main method call
2816 // System | recursive call 2 |
2817 // System.String _| |
2819 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]] _|
2821 private Type TypeLookup (IResolveContext ec, string name)
2826 FullNamedExpression resolved = null;
2828 Type recursive_type = null;
2829 while (index < name.Length) {
2830 if (name[index] == '[') {
2835 if (name[index] == '[')
2837 else if (name[index] == ']')
2839 } while (braces > 0);
2840 recursive_type = TypeLookup (ec, name.Substring (open + 1, index - open - 1));
2841 if (recursive_type == null || (recursive_type == typeof(UnexpectedType)))
2842 return recursive_type;
2845 if (name[index] == ',')
2847 else if ((name[index] == '.' && !done) || (index == name.Length && name[0] != '[')) {
2848 string substring = name.Substring(dot, index - dot);
2850 if (resolved == null)
2851 resolved = RootNamespace.Global.Lookup (ec.DeclContainer, substring, Location.Null);
2852 else if (resolved is Namespace)
2853 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
2854 else if (type != null)
2855 type = TypeManager.GetNestedType (type, substring);
2859 if (resolved == null)
2861 else if (type == null && resolved is TypeExpr)
2862 type = resolved.Type;
2869 if (name[0] != '[') {
2870 string substring = name.Substring(dot, index - dot);
2873 return TypeManager.GetNestedType (type, substring);
2875 if (resolved != null) {
2876 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
2877 if (resolved is TypeExpr)
2878 return resolved.Type;
2880 if (resolved == null)
2883 resolved.Error_UnexpectedKind (ec.DeclContainer, "type", loc);
2884 return typeof (UnexpectedType);
2890 return recursive_type;
2893 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2895 Type t = TypeLookup (ec, name);
2897 NamespaceEntry.Error_NamespaceNotFound (loc, name);
2900 if (t == typeof(UnexpectedType))
2906 public override string Name {
2907 get { return name; }
2910 public override string FullName {
2911 get { return name; }
2914 protected override void CloneTo (CloneContext clonectx, Expression target)
2916 // CloneTo: Nothing, we do not keep any state on this expression
2919 public override string GetSignatureForError ()
2922 return TypeManager.CSharpName (name);
2924 return base.GetSignatureForError ();
2929 /// Represents an "unbound generic type", ie. typeof (Foo<>).
2932 public class UnboundTypeExpression : TypeExpr
2936 public UnboundTypeExpression (MemberName name, Location l)
2942 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2945 if (name.Left != null) {
2946 Expression lexpr = name.Left.GetTypeExpression ();
2947 expr = new MemberAccess (lexpr, name.Basename);
2949 expr = new SimpleName (name.Basename, loc);
2952 FullNamedExpression fne = expr.ResolveAsTypeStep (ec, false);
2957 return new TypeExpression (type, loc);
2960 public override string Name {
2961 get { return name.FullName; }
2964 public override string FullName {
2965 get { return name.FullName; }
2969 public class TypeAliasExpression : TypeExpr {
2970 FullNamedExpression alias;
2975 public TypeAliasExpression (FullNamedExpression alias, TypeArguments args, Location l)
2981 eclass = ExprClass.Type;
2983 name = alias.FullName + "<" + args.ToString () + ">";
2985 name = alias.FullName;
2988 public override string Name {
2989 get { return alias.FullName; }
2992 public override string FullName {
2993 get { return name; }
2996 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2998 texpr = alias.ResolveAsTypeTerminal (ec, false);
3002 Type type = texpr.Type;
3003 int num_args = TypeManager.GetNumberOfTypeArguments (type);
3006 if (num_args == 0) {
3007 Report.Error (308, loc,
3008 "The non-generic type `{0}' cannot " +
3009 "be used with type arguments.",
3010 TypeManager.CSharpName (type));
3014 ConstructedType ctype = new ConstructedType (type, args, loc);
3015 return ctype.ResolveAsTypeTerminal (ec, false);
3016 } else if (num_args > 0) {
3017 Report.Error (305, loc,
3018 "Using the generic type `{0}' " +
3019 "requires {1} type arguments",
3020 TypeManager.CSharpName (type), num_args.ToString ());
3027 public override bool CheckAccessLevel (DeclSpace ds)
3029 return texpr.CheckAccessLevel (ds);
3032 public override bool AsAccessible (DeclSpace ds)
3034 return texpr.AsAccessible (ds);
3037 public override bool IsClass {
3038 get { return texpr.IsClass; }
3041 public override bool IsValueType {
3042 get { return texpr.IsValueType; }
3045 public override bool IsInterface {
3046 get { return texpr.IsInterface; }
3049 public override bool IsSealed {
3050 get { return texpr.IsSealed; }
3055 /// This class denotes an expression which evaluates to a member
3056 /// of a struct or a class.
3058 public abstract class MemberExpr : Expression
3060 protected bool is_base;
3063 /// The name of this member.
3065 public abstract string Name {
3070 // When base.member is used
3072 public bool IsBase {
3073 get { return is_base; }
3074 set { is_base = value; }
3078 /// Whether this is an instance member.
3080 public abstract bool IsInstance {
3085 /// Whether this is a static member.
3087 public abstract bool IsStatic {
3092 /// The type which declares this member.
3094 public abstract Type DeclaringType {
3099 /// The instance expression associated with this member, if it's a
3100 /// non-static member.
3102 public Expression InstanceExpression;
3104 public static void error176 (Location loc, string name)
3106 Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
3107 "with an instance reference, qualify it with a type name instead", name);
3110 // TODO: possible optimalization
3111 // Cache resolved constant result in FieldBuilder <-> expression map
3112 public virtual MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3113 SimpleName original)
3117 // original == null || original.Resolve (...) ==> left
3120 if (left is TypeExpr) {
3121 left = left.ResolveAsTypeTerminal (ec, true);
3126 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3134 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3137 return ResolveExtensionMemberAccess (left);
3140 InstanceExpression = left;
3144 protected virtual MemberExpr ResolveExtensionMemberAccess (Expression left)
3146 error176 (loc, GetSignatureForError ());
3150 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3155 if (InstanceExpression == EmptyExpression.Null) {
3156 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3160 if (InstanceExpression.Type.IsValueType) {
3161 if (InstanceExpression is IMemoryLocation) {
3162 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
3164 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
3165 InstanceExpression.Emit (ec);
3167 t.AddressOf (ec, AddressOp.Store);
3170 InstanceExpression.Emit (ec);
3172 if (prepare_for_load)
3173 ec.ig.Emit (OpCodes.Dup);
3176 public virtual void SetTypeArguments (TypeArguments ta)
3178 // TODO: need to get correct member type
3179 Report.Error (307, loc, "The property `{0}' cannot be used with type arguments",
3180 GetSignatureForError ());
3185 /// Represents group of extension methods
3187 public class ExtensionMethodGroupExpr : MethodGroupExpr
3189 readonly NamespaceEntry namespace_entry;
3190 public Expression ExtensionExpression;
3191 Argument extension_argument;
3193 public ExtensionMethodGroupExpr (ArrayList list, NamespaceEntry n, Type extensionType, Location l)
3194 : base (list, extensionType, l)
3196 this.namespace_entry = n;
3199 public override bool IsStatic {
3200 get { return true; }
3203 public bool IsTopLevel {
3204 get { return namespace_entry == null; }
3207 public override void EmitArguments (EmitContext ec, ArrayList arguments)
3209 if (arguments == null)
3210 arguments = new ArrayList (1);
3211 arguments.Insert (0, extension_argument);
3212 base.EmitArguments (ec, arguments);
3215 public override void EmitCall (EmitContext ec, ArrayList arguments)
3217 if (arguments == null)
3218 arguments = new ArrayList (1);
3219 arguments.Insert (0, extension_argument);
3220 base.EmitCall (ec, arguments);
3223 public override MethodGroupExpr OverloadResolve (EmitContext ec, ref ArrayList arguments, bool may_fail, Location loc)
3225 if (arguments == null)
3226 arguments = new ArrayList (1);
3228 arguments.Insert (0, new Argument (ExtensionExpression));
3229 MethodGroupExpr mg = ResolveOverloadExtensions (ec, arguments, namespace_entry, loc);
3231 // Store resolved argument and restore original arguments
3233 ((ExtensionMethodGroupExpr)mg).extension_argument = (Argument)arguments [0];
3234 arguments.RemoveAt (0);
3239 MethodGroupExpr ResolveOverloadExtensions (EmitContext ec, ArrayList arguments, NamespaceEntry ns, Location loc)
3241 // Use normal resolve rules
3242 MethodGroupExpr mg = base.OverloadResolve (ec, ref arguments, ns != null, loc);
3250 ExtensionMethodGroupExpr e = ns.LookupExtensionMethod (type, null, Name);
3252 return base.OverloadResolve (ec, ref arguments, false, loc);
3254 e.ExtensionExpression = ExtensionExpression;
3255 return e.ResolveOverloadExtensions (ec, arguments, e.namespace_entry, loc);
3260 /// MethodGroupExpr represents a group of method candidates which
3261 /// can be resolved to the best method overload
3263 public class MethodGroupExpr : MemberExpr
3265 public interface IErrorHandler
3267 bool NoExactMatch (EmitContext ec, MethodBase method);
3270 public IErrorHandler CustomErrorHandler;
3271 public MethodBase [] Methods;
3272 MethodBase best_candidate;
3273 // TODO: make private
3274 public TypeArguments type_arguments;
3275 bool identical_type_name;
3278 public MethodGroupExpr (MemberInfo [] mi, Type type, Location l)
3281 Methods = new MethodBase [mi.Length];
3282 mi.CopyTo (Methods, 0);
3285 public MethodGroupExpr (ArrayList list, Type type, Location l)
3289 Methods = (MethodBase[])list.ToArray (typeof (MethodBase));
3291 foreach (MemberInfo m in list){
3292 if (!(m is MethodBase)){
3293 Console.WriteLine ("Name " + m.Name);
3294 Console.WriteLine ("Found a: " + m.GetType ().FullName);
3303 protected MethodGroupExpr (Type type, Location loc)
3306 eclass = ExprClass.MethodGroup;
3310 public override Type DeclaringType {
3313 // We assume that the top-level type is in the end
3315 return Methods [Methods.Length - 1].DeclaringType;
3316 //return Methods [0].DeclaringType;
3320 public Type DelegateType {
3322 delegate_type = value;
3326 public bool IdenticalTypeName {
3328 return identical_type_name;
3332 identical_type_name = value;
3336 public override string GetSignatureForError ()
3338 if (best_candidate != null)
3339 return TypeManager.CSharpSignature (best_candidate);
3341 return TypeManager.CSharpSignature (Methods [0]);
3344 public override string Name {
3346 return Methods [0].Name;
3350 public override bool IsInstance {
3352 if (best_candidate != null)
3353 return !best_candidate.IsStatic;
3355 foreach (MethodBase mb in Methods)
3363 public override bool IsStatic {
3365 if (best_candidate != null)
3366 return best_candidate.IsStatic;
3368 foreach (MethodBase mb in Methods)
3376 public static explicit operator ConstructorInfo (MethodGroupExpr mg)
3378 return (ConstructorInfo)mg.best_candidate;
3381 public static explicit operator MethodInfo (MethodGroupExpr mg)
3383 return (MethodInfo)mg.best_candidate;
3387 // 7.4.3.3 Better conversion from expression
3388 // Returns : 1 if a->p is better,
3389 // 2 if a->q is better,
3390 // 0 if neither is better
3392 static int BetterExpressionConversion (EmitContext ec, Argument a, Type p, Type q)
3394 Type argument_type = TypeManager.TypeToCoreType (a.Type);
3395 if (argument_type == TypeManager.anonymous_method_type && RootContext.Version > LanguageVersion.ISO_2) {
3397 // Uwrap delegate from Expression<T>
3399 if (TypeManager.DropGenericTypeArguments (p) == TypeManager.expression_type) {
3400 p = TypeManager.GetTypeArguments (p) [0];
3401 q = TypeManager.GetTypeArguments (q) [0];
3403 p = Delegate.GetInvokeMethod (null, p).ReturnType;
3404 q = Delegate.GetInvokeMethod (null, q).ReturnType;
3406 if (argument_type == p)
3409 if (argument_type == q)
3413 return BetterTypeConversion (ec, p, q);
3417 // 7.4.3.4 Better conversion from type
3419 public static int BetterTypeConversion (EmitContext ec, Type p, Type q)
3421 if (p == null || q == null)
3422 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3424 if (p == TypeManager.int32_type) {
3425 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3427 } else if (p == TypeManager.int64_type) {
3428 if (q == TypeManager.uint64_type)
3430 } else if (p == TypeManager.sbyte_type) {
3431 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3432 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3434 } else if (p == TypeManager.short_type) {
3435 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3436 q == TypeManager.uint64_type)
3440 if (q == TypeManager.int32_type) {
3441 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3443 } if (q == TypeManager.int64_type) {
3444 if (p == TypeManager.uint64_type)
3446 } else if (q == TypeManager.sbyte_type) {
3447 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3448 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3450 } if (q == TypeManager.short_type) {
3451 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3452 p == TypeManager.uint64_type)
3456 // TODO: this is expensive
3457 Expression p_tmp = new EmptyExpression (p);
3458 Expression q_tmp = new EmptyExpression (q);
3460 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3461 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3463 if (p_to_q && !q_to_p)
3466 if (q_to_p && !p_to_q)
3473 /// Determines "Better function" between candidate
3474 /// and the current best match
3477 /// Returns a boolean indicating :
3478 /// false if candidate ain't better
3479 /// true if candidate is better than the current best match
3481 static bool BetterFunction (EmitContext ec, ArrayList args, int argument_count,
3482 MethodBase candidate, bool candidate_params,
3483 MethodBase best, bool best_params)
3485 ParameterData candidate_pd = TypeManager.GetParameterData (candidate);
3486 ParameterData best_pd = TypeManager.GetParameterData (best);
3488 bool better_at_least_one = false;
3490 for (int j = 0, c_idx = 0, b_idx = 0; j < argument_count; ++j, ++c_idx, ++b_idx)
3492 Argument a = (Argument) args [j];
3494 Type ct = TypeManager.TypeToCoreType (candidate_pd.ParameterType (c_idx));
3495 Type bt = TypeManager.TypeToCoreType (best_pd.ParameterType (b_idx));
3497 if (candidate_params && candidate_pd.ParameterModifier (c_idx) == Parameter.Modifier.PARAMS)
3499 ct = TypeManager.GetElementType (ct);
3503 if (best_params && best_pd.ParameterModifier (b_idx) == Parameter.Modifier.PARAMS)
3505 bt = TypeManager.GetElementType (bt);
3513 int result = BetterExpressionConversion (ec, a, ct, bt);
3515 // for each argument, the conversion to 'ct' should be no worse than
3516 // the conversion to 'bt'.
3520 // for at least one argument, the conversion to 'ct' should be better than
3521 // the conversion to 'bt'.
3523 better_at_least_one = true;
3526 if (better_at_least_one)
3530 // This handles the case
3532 // Add (float f1, float f2, float f3);
3533 // Add (params decimal [] foo);
3535 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3536 // first candidate would've chosen as better.
3542 // The two methods have equal parameter types. Now apply tie-breaking rules
3544 if (TypeManager.IsGenericMethod (best) && !TypeManager.IsGenericMethod (candidate))
3546 if (!TypeManager.IsGenericMethod (best) && TypeManager.IsGenericMethod (candidate))
3550 // This handles the following cases:
3552 // Trim () is better than Trim (params char[] chars)
3553 // Concat (string s1, string s2, string s3) is better than
3554 // Concat (string s1, params string [] srest)
3555 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3557 if (!candidate_params && best_params)
3559 if (candidate_params && !best_params)
3562 int candidate_param_count = candidate_pd.Count;
3563 int best_param_count = best_pd.Count;
3565 if (candidate_param_count != best_param_count)
3566 // can only happen if (candidate_params && best_params)
3567 return candidate_param_count > best_param_count;
3570 // now, both methods have the same number of parameters, and the parameters have the same types
3571 // Pick the "more specific" signature
3574 MethodBase orig_candidate = TypeManager.DropGenericMethodArguments (candidate);
3575 MethodBase orig_best = TypeManager.DropGenericMethodArguments (best);
3577 ParameterData orig_candidate_pd = TypeManager.GetParameterData (orig_candidate);
3578 ParameterData orig_best_pd = TypeManager.GetParameterData (orig_best);
3580 bool specific_at_least_once = false;
3581 for (int j = 0; j < candidate_param_count; ++j)
3583 Type ct = TypeManager.TypeToCoreType (orig_candidate_pd.ParameterType (j));
3584 Type bt = TypeManager.TypeToCoreType (orig_best_pd.ParameterType (j));
3587 Type specific = MoreSpecific (ct, bt);
3591 specific_at_least_once = true;
3594 if (specific_at_least_once)
3597 // FIXME: handle lifted operators
3603 protected override MemberExpr ResolveExtensionMemberAccess (Expression left)
3606 return base.ResolveExtensionMemberAccess (left);
3609 // When left side is an expression and at least one candidate method is
3610 // static, it can be extension method
3612 InstanceExpression = left;
3616 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3617 SimpleName original)
3619 if (!(left is TypeExpr) &&
3620 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3621 IdenticalTypeName = true;
3623 return base.ResolveMemberAccess (ec, left, loc, original);
3626 public override Expression CreateExpressionTree (EmitContext ec)
3628 return new Cast (new TypeExpression (typeof (MethodInfo), loc),
3629 new TypeOfMethod ((MethodInfo)best_candidate, loc));
3632 override public Expression DoResolve (EmitContext ec)
3634 if (InstanceExpression != null) {
3635 InstanceExpression = InstanceExpression.DoResolve (ec);
3636 if (InstanceExpression == null)
3643 public void ReportUsageError ()
3645 Report.Error (654, loc, "Method `" + DeclaringType + "." +
3646 Name + "()' is referenced without parentheses");
3649 override public void Emit (EmitContext ec)
3651 ReportUsageError ();
3654 public virtual void EmitArguments (EmitContext ec, ArrayList arguments)
3656 Invocation.EmitArguments (ec, arguments, false, null);
3659 public virtual void EmitCall (EmitContext ec, ArrayList arguments)
3661 Invocation.EmitCall (ec, IsBase, InstanceExpression, best_candidate, arguments, loc);
3664 protected virtual void Error_InvalidArguments (EmitContext ec, Location loc, int idx, MethodBase method,
3665 Argument a, ParameterData expected_par, Type paramType)
3667 if (a is CollectionElementInitializer.ElementInitializerArgument) {
3668 Report.SymbolRelatedToPreviousError (method);
3669 if ((expected_par.ParameterModifier (idx) & Parameter.Modifier.ISBYREF) != 0) {
3670 Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
3671 TypeManager.CSharpSignature (method));
3674 Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
3675 TypeManager.CSharpSignature (method));
3676 } else if (delegate_type == null) {
3677 Report.SymbolRelatedToPreviousError (method);
3678 Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
3679 TypeManager.CSharpSignature (method));
3681 Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
3682 TypeManager.CSharpName (delegate_type));
3684 Parameter.Modifier mod = expected_par.ParameterModifier (idx);
3686 string index = (idx + 1).ToString ();
3687 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
3688 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
3689 if ((mod & Parameter.Modifier.ISBYREF) == 0)
3690 Report.Error (1615, loc, "Argument `{0}' should not be passed with the `{1}' keyword",
3691 index, Parameter.GetModifierSignature (a.Modifier));
3693 Report.Error (1620, loc, "Argument `{0}' must be passed with the `{1}' keyword",
3694 index, Parameter.GetModifierSignature (mod));
3696 string p1 = a.GetSignatureForError ();
3697 string p2 = TypeManager.CSharpName (paramType);
3700 Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
3701 Report.SymbolRelatedToPreviousError (a.Expr.Type);
3702 Report.SymbolRelatedToPreviousError (paramType);
3704 Report.Error (1503, loc, "Argument {0}: Cannot convert type `{1}' to `{2}'", index, p1, p2);
3708 protected virtual int GetApplicableParametersCount (MethodBase method, ParameterData parameters)
3710 return parameters.Count;
3713 public static bool IsAncestralType (Type first_type, Type second_type)
3715 return first_type != second_type &&
3716 (TypeManager.IsSubclassOf (second_type, first_type) ||
3717 TypeManager.ImplementsInterface (second_type, first_type));
3721 /// Determines if the candidate method is applicable (section 14.4.2.1)
3722 /// to the given set of arguments
3723 /// A return value rates candidate method compatibility,
3724 /// 0 = the best, int.MaxValue = the worst
3726 public int IsApplicable (EmitContext ec,
3727 ArrayList arguments, int arg_count, ref MethodBase method, ref bool params_expanded_form)
3729 MethodBase candidate = method;
3731 ParameterData pd = TypeManager.GetParameterData (candidate);
3732 int param_count = GetApplicableParametersCount (candidate, pd);
3734 if (arg_count != param_count) {
3736 return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
3737 if (arg_count < param_count - 1)
3738 return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
3743 // 1. Handle generic method using type arguments when specified or type inference
3745 if (TypeManager.IsGenericMethod (candidate)) {
3746 if (type_arguments != null) {
3747 Type [] g_args = candidate.GetGenericArguments ();
3748 if (g_args.Length != type_arguments.Count)
3749 return int.MaxValue - 20000 + Math.Abs (type_arguments.Count - g_args.Length);
3751 // TODO: Don't create new method, create Parameters only
3752 method = ((MethodInfo) candidate).MakeGenericMethod (type_arguments.Arguments);
3754 pd = TypeManager.GetParameterData (candidate);
3756 int score = TypeManager.InferTypeArguments (ec, arguments, ref candidate);
3758 return score - 20000;
3760 if (TypeManager.IsGenericMethodDefinition (candidate))
3761 throw new InternalErrorException ("A generic method `{0}' definition took part in overload resolution",
3762 TypeManager.CSharpSignature (candidate));
3764 pd = TypeManager.GetParameterData (candidate);
3767 if (type_arguments != null)
3768 return int.MaxValue - 15000;
3773 // 2. Each argument has to be implicitly convertible to method parameter
3776 Parameter.Modifier p_mod = 0;
3778 for (int i = 0; i < arg_count; i++) {
3779 Argument a = (Argument) arguments [i];
3780 Parameter.Modifier a_mod = a.Modifier &
3781 ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3783 if (p_mod != Parameter.Modifier.PARAMS) {
3784 p_mod = pd.ParameterModifier (i) & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3786 if (p_mod == Parameter.Modifier.ARGLIST) {
3787 if (a.Type == TypeManager.runtime_argument_handle_type)
3793 pt = pd.ParameterType (i);
3795 params_expanded_form = true;
3799 if (!params_expanded_form)
3800 score = IsArgumentCompatible (ec, a_mod, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
3802 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0) {
3803 // It can be applicable in expanded form
3804 score = IsArgumentCompatible (ec, a_mod, a, 0, pt.GetElementType ());
3806 params_expanded_form = true;
3810 if (params_expanded_form)
3812 return (arg_count - i) * 2 + score;
3816 if (arg_count != param_count)
3817 params_expanded_form = true;
3822 int IsArgumentCompatible (EmitContext ec, Parameter.Modifier arg_mod, Argument argument, Parameter.Modifier param_mod, Type parameter)
3825 // Types have to be identical when ref or out modifer is used
3827 if (arg_mod != 0 || param_mod != 0) {
3828 if (TypeManager.HasElementType (parameter))
3829 parameter = parameter.GetElementType ();
3831 Type a_type = argument.Type;
3832 if (TypeManager.HasElementType (a_type))
3833 a_type = a_type.GetElementType ();
3835 if (a_type != parameter)
3841 // FIXME: Kill this abomination (EmitContext.TempEc)
3842 EmitContext prevec = EmitContext.TempEc;
3843 EmitContext.TempEc = ec;
3845 if (delegate_type != null ?
3846 !Delegate.IsTypeCovariant (argument.Expr, parameter) :
3847 !Convert.ImplicitConversionExists (ec, argument.Expr, parameter))
3850 if (arg_mod != param_mod)
3854 EmitContext.TempEc = prevec;
3860 public static bool IsOverride (MethodBase cand_method, MethodBase base_method)
3862 if (!IsAncestralType (base_method.DeclaringType, cand_method.DeclaringType))
3865 ParameterData cand_pd = TypeManager.GetParameterData (cand_method);
3866 ParameterData base_pd = TypeManager.GetParameterData (base_method);
3868 if (cand_pd.Count != base_pd.Count)
3871 for (int j = 0; j < cand_pd.Count; ++j)
3873 Parameter.Modifier cm = cand_pd.ParameterModifier (j);
3874 Parameter.Modifier bm = base_pd.ParameterModifier (j);
3875 Type ct = TypeManager.TypeToCoreType (cand_pd.ParameterType (j));
3876 Type bt = TypeManager.TypeToCoreType (base_pd.ParameterType (j));
3878 if (cm != bm || ct != bt)
3885 public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2, Location loc)
3887 MemberInfo [] miset;
3888 MethodGroupExpr union;
3893 return (MethodGroupExpr) mg2;
3896 return (MethodGroupExpr) mg1;
3899 MethodGroupExpr left_set = null, right_set = null;
3900 int length1 = 0, length2 = 0;
3902 left_set = (MethodGroupExpr) mg1;
3903 length1 = left_set.Methods.Length;
3905 right_set = (MethodGroupExpr) mg2;
3906 length2 = right_set.Methods.Length;
3908 ArrayList common = new ArrayList ();
3910 foreach (MethodBase r in right_set.Methods){
3911 if (TypeManager.ArrayContainsMethod (left_set.Methods, r))
3915 miset = new MemberInfo [length1 + length2 - common.Count];
3916 left_set.Methods.CopyTo (miset, 0);
3920 foreach (MethodBase r in right_set.Methods) {
3921 if (!common.Contains (r))
3925 union = new MethodGroupExpr (miset, mg1.Type, loc);
3930 static Type MoreSpecific (Type p, Type q)
3932 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
3934 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
3937 if (TypeManager.HasElementType (p))
3939 Type pe = TypeManager.GetElementType (p);
3940 Type qe = TypeManager.GetElementType (q);
3941 Type specific = MoreSpecific (pe, qe);
3947 else if (TypeManager.IsGenericType (p))
3949 Type[] pargs = TypeManager.GetTypeArguments (p);
3950 Type[] qargs = TypeManager.GetTypeArguments (q);
3952 bool p_specific_at_least_once = false;
3953 bool q_specific_at_least_once = false;
3955 for (int i = 0; i < pargs.Length; i++)
3957 Type specific = MoreSpecific (pargs [i], qargs [i]);
3958 if (specific == pargs [i])
3959 p_specific_at_least_once = true;
3960 if (specific == qargs [i])
3961 q_specific_at_least_once = true;
3964 if (p_specific_at_least_once && !q_specific_at_least_once)
3966 if (!p_specific_at_least_once && q_specific_at_least_once)
3974 /// Find the Applicable Function Members (7.4.2.1)
3976 /// me: Method Group expression with the members to select.
3977 /// it might contain constructors or methods (or anything
3978 /// that maps to a method).
3980 /// Arguments: ArrayList containing resolved Argument objects.
3982 /// loc: The location if we want an error to be reported, or a Null
3983 /// location for "probing" purposes.
3985 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3986 /// that is the best match of me on Arguments.
3989 public virtual MethodGroupExpr OverloadResolve (EmitContext ec, ref ArrayList Arguments,
3990 bool may_fail, Location loc)
3992 bool method_params = false;
3993 Type applicable_type = null;
3995 ArrayList candidates = new ArrayList (2);
3996 ArrayList candidate_overrides = null;
3999 // Used to keep a map between the candidate
4000 // and whether it is being considered in its
4001 // normal or expanded form
4003 // false is normal form, true is expanded form
4005 Hashtable candidate_to_form = null;
4007 if (Arguments != null)
4008 arg_count = Arguments.Count;
4010 if (RootContext.Version == LanguageVersion.ISO_1 && Name == "Invoke" && TypeManager.IsDelegateType (DeclaringType)) {
4012 Report.Error (1533, loc, "Invoke cannot be called directly on a delegate");
4016 int nmethods = Methods.Length;
4020 // Methods marked 'override' don't take part in 'applicable_type'
4021 // computation, nor in the actual overload resolution.
4022 // However, they still need to be emitted instead of a base virtual method.
4023 // So, we salt them away into the 'candidate_overrides' array.
4025 // In case of reflected methods, we replace each overriding method with
4026 // its corresponding base virtual method. This is to improve compatibility
4027 // with non-C# libraries which change the visibility of overrides (#75636)
4030 for (int i = 0; i < Methods.Length; ++i) {
4031 MethodBase m = Methods [i];
4032 if (TypeManager.IsOverride (m)) {
4033 if (candidate_overrides == null)
4034 candidate_overrides = new ArrayList ();
4035 candidate_overrides.Add (m);
4036 m = TypeManager.TryGetBaseDefinition (m);
4045 // Enable message recording, it's used mainly by lambda expressions
4047 Report.IMessageRecorder msg_recorder = new Report.MessageRecorder ();
4048 Report.IMessageRecorder prev_recorder = Report.SetMessageRecorder (msg_recorder);
4051 // First we construct the set of applicable methods
4053 bool is_sorted = true;
4054 int best_candidate_rate = int.MaxValue;
4055 for (int i = 0; i < nmethods; i++) {
4056 Type decl_type = Methods [i].DeclaringType;
4059 // If we have already found an applicable method
4060 // we eliminate all base types (Section 14.5.5.1)
4062 if (applicable_type != null && IsAncestralType (decl_type, applicable_type))
4066 // Check if candidate is applicable (section 14.4.2.1)
4068 bool params_expanded_form = false;
4069 int candidate_rate = IsApplicable (ec, Arguments, arg_count, ref Methods [i], ref params_expanded_form);
4071 if (candidate_rate < best_candidate_rate) {
4072 best_candidate_rate = candidate_rate;
4073 best_candidate = Methods [i];
4076 if (params_expanded_form) {
4077 if (candidate_to_form == null)
4078 candidate_to_form = new PtrHashtable ();
4079 MethodBase candidate = Methods [i];
4080 candidate_to_form [candidate] = candidate;
4083 if (candidate_rate != 0) {
4084 if (msg_recorder != null)
4085 msg_recorder.EndSession ();
4089 msg_recorder = null;
4090 candidates.Add (Methods [i]);
4092 if (applicable_type == null)
4093 applicable_type = decl_type;
4094 else if (applicable_type != decl_type) {
4096 if (IsAncestralType (applicable_type, decl_type))
4097 applicable_type = decl_type;
4101 Report.SetMessageRecorder (prev_recorder);
4102 if (msg_recorder != null && msg_recorder.PrintMessages ())
4105 int candidate_top = candidates.Count;
4107 if (applicable_type == null) {
4109 // When we found a top level method which does not match and it's
4110 // not an extension method. We start extension methods lookup from here
4112 if (InstanceExpression != null) {
4113 ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (type, Name);
4114 if (ex_method_lookup != null) {
4115 ex_method_lookup.ExtensionExpression = InstanceExpression;
4116 ex_method_lookup.SetTypeArguments (type_arguments);
4117 return ex_method_lookup.OverloadResolve (ec, ref Arguments, may_fail, loc);
4125 // Okay so we have failed to find exact match so we
4126 // return error info about the closest match
4128 if (best_candidate != null) {
4129 if (CustomErrorHandler != null) {
4130 if (CustomErrorHandler.NoExactMatch (ec, best_candidate))
4134 ParameterData pd = TypeManager.GetParameterData (best_candidate);
4135 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4136 if (arg_count == pd.Count || pd.HasParams) {
4137 if (TypeManager.IsGenericMethodDefinition (best_candidate)) {
4138 if (type_arguments == null) {
4139 Report.Error (411, loc,
4140 "The type arguments for method `{0}' cannot be inferred from " +
4141 "the usage. Try specifying the type arguments explicitly",
4142 TypeManager.CSharpSignature (best_candidate));
4146 Type [] g_args = TypeManager.GetGenericArguments (best_candidate);
4147 if (type_arguments.Count != g_args.Length) {
4148 Report.SymbolRelatedToPreviousError (best_candidate);
4149 Report.Error (305, loc, "Using the generic method `{0}' requires `{1}' type argument(s)",
4150 TypeManager.CSharpSignature (best_candidate),
4151 g_args.Length.ToString ());
4155 if (type_arguments != null && !TypeManager.IsGenericMethod (best_candidate)) {
4156 Namespace.Error_TypeArgumentsCannotBeUsed (best_candidate, loc);
4161 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate, cand_params, may_fail, loc))
4166 if (almost_matched_members.Count != 0) {
4167 Error_MemberLookupFailed (ec.ContainerType, type, type, ".ctor",
4168 null, MemberTypes.Constructor, AllBindingFlags);
4173 // We failed to find any method with correct argument count
4175 if (Name == ConstructorInfo.ConstructorName) {
4176 Report.SymbolRelatedToPreviousError (type);
4177 Report.Error (1729, loc,
4178 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4179 TypeManager.CSharpName (type), arg_count);
4181 Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4182 Name, arg_count.ToString ());
4190 // At this point, applicable_type is _one_ of the most derived types
4191 // in the set of types containing the methods in this MethodGroup.
4192 // Filter the candidates so that they only contain methods from the
4193 // most derived types.
4196 int finalized = 0; // Number of finalized candidates
4199 // Invariant: applicable_type is a most derived type
4201 // We'll try to complete Section 14.5.5.1 for 'applicable_type' by
4202 // eliminating all it's base types. At the same time, we'll also move
4203 // every unrelated type to the end of the array, and pick the next
4204 // 'applicable_type'.
4206 Type next_applicable_type = null;
4207 int j = finalized; // where to put the next finalized candidate
4208 int k = finalized; // where to put the next undiscarded candidate
4209 for (int i = finalized; i < candidate_top; ++i) {
4210 MethodBase candidate = (MethodBase) candidates [i];
4211 Type decl_type = candidate.DeclaringType;
4213 if (decl_type == applicable_type) {
4214 candidates [k++] = candidates [j];
4215 candidates [j++] = candidates [i];
4219 if (IsAncestralType (decl_type, applicable_type))
4222 if (next_applicable_type != null &&
4223 IsAncestralType (decl_type, next_applicable_type))
4226 candidates [k++] = candidates [i];
4228 if (next_applicable_type == null ||
4229 IsAncestralType (next_applicable_type, decl_type))
4230 next_applicable_type = decl_type;
4233 applicable_type = next_applicable_type;
4236 } while (applicable_type != null);
4240 // Now we actually find the best method
4243 best_candidate = (MethodBase) candidates [0];
4244 if (delegate_type == null)
4245 method_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4247 for (int ix = 1; ix < candidate_top; ix++) {
4248 MethodBase candidate = (MethodBase) candidates [ix];
4250 if (candidate == best_candidate)
4253 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4255 if (BetterFunction (ec, Arguments, arg_count,
4256 candidate, cand_params,
4257 best_candidate, method_params)) {
4258 best_candidate = candidate;
4259 method_params = cand_params;
4263 // Now check that there are no ambiguities i.e the selected method
4264 // should be better than all the others
4266 MethodBase ambiguous = null;
4267 for (int ix = 1; ix < candidate_top; ix++) {
4268 MethodBase candidate = (MethodBase) candidates [ix];
4270 if (candidate == best_candidate)
4273 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4274 if (!BetterFunction (ec, Arguments, arg_count,
4275 best_candidate, method_params,
4276 candidate, cand_params))
4279 Report.SymbolRelatedToPreviousError (candidate);
4280 ambiguous = candidate;
4284 if (ambiguous != null) {
4285 Report.SymbolRelatedToPreviousError (best_candidate);
4286 Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4287 TypeManager.CSharpSignature (ambiguous), TypeManager.CSharpSignature (best_candidate));
4292 // If the method is a virtual function, pick an override closer to the LHS type.
4294 if (!IsBase && best_candidate.IsVirtual) {
4295 if (TypeManager.IsOverride (best_candidate))
4296 throw new InternalErrorException (
4297 "Should not happen. An 'override' method took part in overload resolution: " + best_candidate);
4299 if (candidate_overrides != null) {
4300 Type[] gen_args = null;
4301 bool gen_override = false;
4302 if (TypeManager.IsGenericMethod (best_candidate))
4303 gen_args = TypeManager.GetGenericArguments (best_candidate);
4305 foreach (MethodBase candidate in candidate_overrides) {
4306 if (TypeManager.IsGenericMethod (candidate)) {
4307 if (gen_args == null)
4310 if (gen_args.Length != TypeManager.GetGenericArguments (candidate).Length)
4313 if (gen_args != null)
4317 if (IsOverride (candidate, best_candidate)) {
4318 gen_override = true;
4319 best_candidate = candidate;
4323 if (gen_override && gen_args != null) {
4325 best_candidate = ((MethodInfo) best_candidate).MakeGenericMethod (gen_args);
4332 // And now check if the arguments are all
4333 // compatible, perform conversions if
4334 // necessary etc. and return if everything is
4337 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate,
4338 method_params, may_fail, loc))
4341 if (best_candidate == null)
4344 MethodBase the_method = TypeManager.DropGenericMethodArguments (best_candidate);
4346 if (the_method.IsGenericMethodDefinition &&
4347 !ConstraintChecker.CheckConstraints (ec, the_method, best_candidate, loc))
4351 IMethodData data = TypeManager.GetMethod (the_method);
4353 data.SetMemberIsUsed ();
4358 public override void SetTypeArguments (TypeArguments ta)
4360 type_arguments = ta;
4363 public bool VerifyArgumentsCompat (EmitContext ec, ref ArrayList arguments,
4364 int arg_count, MethodBase method,
4365 bool chose_params_expanded,
4366 bool may_fail, Location loc)
4368 ParameterData pd = TypeManager.GetParameterData (method);
4370 int errors = Report.Errors;
4371 Parameter.Modifier p_mod = 0;
4373 int a_idx = 0, a_pos = 0;
4375 ArrayList params_initializers = null;
4377 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4378 a = (Argument) arguments [a_idx];
4379 if (p_mod != Parameter.Modifier.PARAMS) {
4380 p_mod = pd.ParameterModifier (a_idx);
4381 pt = pd.ParameterType (a_idx);
4383 if (p_mod == Parameter.Modifier.ARGLIST) {
4384 if (a.Type != TypeManager.runtime_argument_handle_type)
4389 if (pt.IsPointer && !ec.InUnsafe) {
4396 if (p_mod == Parameter.Modifier.PARAMS) {
4397 if (chose_params_expanded) {
4398 params_initializers = new ArrayList (arg_count - a_idx);
4399 pt = TypeManager.GetElementType (pt);
4401 } else if (p_mod != 0) {
4402 pt = TypeManager.GetElementType (pt);
4407 // Types have to be identical when ref or out modifer is used
4409 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4410 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4413 if (!TypeManager.IsEqual (a.Expr.Type, pt))
4420 if (TypeManager.IsEqual (a.Type, pt)) {
4423 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4429 // Convert params arguments to an array initializer
4431 if (params_initializers != null) {
4432 params_initializers.Add (conv);
4433 arguments.RemoveAt (a_idx--);
4438 // Update the argument with the implicit conversion
4443 // Fill not provided arguments required by params modifier
4445 if (params_initializers == null && pd.HasParams && arg_count < pd.Count && a_idx + 1 == pd.Count) {
4446 if (arguments == null)
4447 arguments = new ArrayList (1);
4449 pt = pd.Types [GetApplicableParametersCount (method, pd) - 1];
4450 pt = TypeManager.GetElementType (pt);
4451 params_initializers = new ArrayList (0);
4454 if (a_idx == arg_count) {
4456 // Append an array argument with all params arguments
4458 if (params_initializers != null) {
4459 arguments.Add (new Argument (
4460 new ArrayCreation (new TypeExpression (pt, loc), "[]",
4461 params_initializers, loc).Resolve (ec)));
4466 if (!may_fail && Report.Errors == errors) {
4467 if (CustomErrorHandler != null)
4468 CustomErrorHandler.NoExactMatch (ec, best_candidate);
4470 Error_InvalidArguments (ec, loc, a_pos, method, a, pd, pt);
4476 public class ConstantExpr : MemberExpr
4480 public ConstantExpr (FieldInfo constant, Location loc)
4482 this.constant = constant;
4486 public override string Name {
4487 get { throw new NotImplementedException (); }
4490 public override bool IsInstance {
4491 get { return !IsStatic; }
4494 public override bool IsStatic {
4495 get { return constant.IsStatic; }
4498 public override Type DeclaringType {
4499 get { return constant.DeclaringType; }
4502 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc, SimpleName original)
4504 constant = TypeManager.GetGenericFieldDefinition (constant);
4506 IConstant ic = TypeManager.GetConstant (constant);
4508 if (constant.IsLiteral) {
4509 ic = new ExternalConstant (constant);
4511 ic = ExternalConstant.CreateDecimal (constant);
4512 // HACK: decimal field was not resolved as constant
4514 return new FieldExpr (constant, loc).ResolveMemberAccess (ec, left, loc, original);
4516 TypeManager.RegisterConstant (constant, ic);
4519 return base.ResolveMemberAccess (ec, left, loc, original);
4522 public override Expression DoResolve (EmitContext ec)
4524 IConstant ic = TypeManager.GetConstant (constant);
4525 if (ic.ResolveValue ()) {
4526 if (!ec.IsInObsoleteScope)
4527 ic.CheckObsoleteness (loc);
4530 return ic.CreateConstantReference (loc);
4533 public override void Emit (EmitContext ec)
4535 throw new NotSupportedException ();
4538 public override string GetSignatureForError ()
4540 return TypeManager.GetFullNameSignature (constant);
4545 /// Fully resolved expression that evaluates to a Field
4547 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariable {
4548 public readonly FieldInfo FieldInfo;
4549 VariableInfo variable_info;
4551 LocalTemporary temp;
4553 bool in_initializer;
4555 public FieldExpr (FieldInfo fi, Location l, bool in_initializer):
4558 this.in_initializer = in_initializer;
4561 public FieldExpr (FieldInfo fi, Location l)
4564 eclass = ExprClass.Variable;
4565 type = TypeManager.TypeToCoreType (fi.FieldType);
4569 public override string Name {
4571 return FieldInfo.Name;
4575 public override bool IsInstance {
4577 return !FieldInfo.IsStatic;
4581 public override bool IsStatic {
4583 return FieldInfo.IsStatic;
4587 public override Type DeclaringType {
4589 return FieldInfo.DeclaringType;
4593 public override string GetSignatureForError ()
4595 return TypeManager.GetFullNameSignature (FieldInfo);
4598 public VariableInfo VariableInfo {
4600 return variable_info;
4604 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
4605 SimpleName original)
4607 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
4608 Type t = fi.FieldType;
4610 if (t.IsPointer && !ec.InUnsafe) {
4614 return base.ResolveMemberAccess (ec, left, loc, original);
4617 override public Expression DoResolve (EmitContext ec)
4619 return DoResolve (ec, false, false);
4622 Expression DoResolve (EmitContext ec, bool lvalue_instance, bool out_access)
4624 if (!FieldInfo.IsStatic){
4625 if (InstanceExpression == null){
4627 // This can happen when referencing an instance field using
4628 // a fully qualified type expression: TypeName.InstanceField = xxx
4630 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4634 // Resolve the field's instance expression while flow analysis is turned
4635 // off: when accessing a field "a.b", we must check whether the field
4636 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4638 if (lvalue_instance) {
4639 using (ec.With (EmitContext.Flags.DoFlowAnalysis, false)) {
4640 Expression right_side =
4641 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4642 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side, loc);
4645 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
4646 InstanceExpression = InstanceExpression.Resolve (ec, rf);
4649 if (InstanceExpression == null)
4652 using (ec.Set (EmitContext.Flags.OmitStructFlowAnalysis)) {
4653 InstanceExpression.CheckMarshalByRefAccess (ec);
4657 if (!in_initializer && !ec.IsInFieldInitializer) {
4658 ObsoleteAttribute oa;
4659 FieldBase f = TypeManager.GetField (FieldInfo);
4661 if (!ec.IsInObsoleteScope)
4662 f.CheckObsoleteness (loc);
4664 // To be sure that type is external because we do not register generated fields
4665 } else if (!(FieldInfo.DeclaringType is TypeBuilder)) {
4666 oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
4668 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
4672 AnonymousContainer am = ec.CurrentAnonymousMethod;
4674 if (!FieldInfo.IsStatic){
4675 if (!am.IsIterator && (ec.TypeContainer is Struct)){
4676 Report.Error (1673, loc,
4677 "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",
4684 IFixedBuffer fb = AttributeTester.GetFixedBuffer (FieldInfo);
4686 if (!ec.InFixedInitializer && ec.ContainerType.IsValueType) {
4687 Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4690 if (InstanceExpression.eclass != ExprClass.Variable) {
4691 Report.SymbolRelatedToPreviousError (FieldInfo);
4692 Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4693 TypeManager.GetFullNameSignature (FieldInfo));
4696 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4699 // If the instance expression is a local variable or parameter.
4700 IVariable var = InstanceExpression as IVariable;
4701 if ((var == null) || (var.VariableInfo == null))
4704 VariableInfo vi = var.VariableInfo;
4705 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
4708 variable_info = vi.GetSubStruct (FieldInfo.Name);
4712 static readonly int [] codes = {
4713 191, // instance, write access
4714 192, // instance, out access
4715 198, // static, write access
4716 199, // static, out access
4717 1648, // member of value instance, write access
4718 1649, // member of value instance, out access
4719 1650, // member of value static, write access
4720 1651 // member of value static, out access
4723 static readonly string [] msgs = {
4724 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4725 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4726 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4727 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4728 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4729 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4730 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4731 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4734 // The return value is always null. Returning a value simplifies calling code.
4735 Expression Report_AssignToReadonly (Expression right_side)
4738 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4742 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4744 Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4749 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4751 IVariable var = InstanceExpression as IVariable;
4752 if ((var != null) && (var.VariableInfo != null))
4753 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
4755 bool lvalue_instance = !FieldInfo.IsStatic && FieldInfo.DeclaringType.IsValueType;
4756 bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
4758 Expression e = DoResolve (ec, lvalue_instance, out_access);
4763 FieldBase fb = TypeManager.GetField (FieldInfo);
4767 if (FieldInfo.IsInitOnly) {
4768 // InitOnly fields can only be assigned in constructors or initializers
4769 if (!ec.IsInFieldInitializer && !ec.IsConstructor)
4770 return Report_AssignToReadonly (right_side);
4772 if (ec.IsConstructor) {
4773 Type ctype = ec.TypeContainer.CurrentType;
4775 ctype = ec.ContainerType;
4777 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4778 if (!TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
4779 return Report_AssignToReadonly (right_side);
4780 // static InitOnly fields cannot be assigned-to in an instance constructor
4781 if (IsStatic && !ec.IsStatic)
4782 return Report_AssignToReadonly (right_side);
4783 // instance constructors can't modify InitOnly fields of other instances of the same type
4784 if (!IsStatic && !(InstanceExpression is This))
4785 return Report_AssignToReadonly (right_side);
4789 if (right_side == EmptyExpression.OutAccess &&
4790 !IsStatic && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type)) {
4791 Report.SymbolRelatedToPreviousError (DeclaringType);
4792 Report.Warning (197, 1, loc,
4793 "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",
4794 GetSignatureForError ());
4800 public override void CheckMarshalByRefAccess (EmitContext ec)
4802 if (!IsStatic && Type.IsValueType && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type)) {
4803 Report.SymbolRelatedToPreviousError (DeclaringType);
4804 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",
4805 GetSignatureForError ());
4809 public bool VerifyFixed ()
4811 IVariable variable = InstanceExpression as IVariable;
4812 // A variable of the form V.I is fixed when V is a fixed variable of a struct type.
4813 // We defer the InstanceExpression check after the variable check to avoid a
4814 // separate null check on InstanceExpression.
4815 return variable != null && InstanceExpression.Type.IsValueType && variable.VerifyFixed ();
4818 public override int GetHashCode ()
4820 return FieldInfo.GetHashCode ();
4823 public override bool Equals (object obj)
4825 FieldExpr fe = obj as FieldExpr;
4829 if (FieldInfo != fe.FieldInfo)
4832 if (InstanceExpression == null || fe.InstanceExpression == null)
4835 return InstanceExpression.Equals (fe.InstanceExpression);
4838 public void Emit (EmitContext ec, bool leave_copy)
4840 ILGenerator ig = ec.ig;
4841 bool is_volatile = false;
4843 FieldBase f = TypeManager.GetField (FieldInfo);
4845 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4848 f.SetMemberIsUsed ();
4851 if (FieldInfo.IsStatic){
4853 ig.Emit (OpCodes.Volatile);
4855 ig.Emit (OpCodes.Ldsfld, FieldInfo);
4858 EmitInstance (ec, false);
4860 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
4862 ig.Emit (OpCodes.Ldflda, FieldInfo);
4863 ig.Emit (OpCodes.Ldflda, ff.Element);
4866 ig.Emit (OpCodes.Volatile);
4868 ig.Emit (OpCodes.Ldfld, FieldInfo);
4873 ec.ig.Emit (OpCodes.Dup);
4874 if (!FieldInfo.IsStatic) {
4875 temp = new LocalTemporary (this.Type);
4881 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4883 FieldAttributes fa = FieldInfo.Attributes;
4884 bool is_static = (fa & FieldAttributes.Static) != 0;
4885 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
4886 ILGenerator ig = ec.ig;
4888 if (is_readonly && !ec.IsConstructor){
4889 Report_AssignToReadonly (source);
4894 // String concatenation creates a new string instance
4896 prepared = prepare_for_load && !(source is StringConcat);
4897 EmitInstance (ec, prepared);
4901 ec.ig.Emit (OpCodes.Dup);
4902 if (!FieldInfo.IsStatic) {
4903 temp = new LocalTemporary (this.Type);
4908 FieldBase f = TypeManager.GetField (FieldInfo);
4910 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4911 ig.Emit (OpCodes.Volatile);
4917 ig.Emit (OpCodes.Stsfld, FieldInfo);
4919 ig.Emit (OpCodes.Stfld, FieldInfo);
4927 public override void Emit (EmitContext ec)
4932 public void AddressOf (EmitContext ec, AddressOp mode)
4934 ILGenerator ig = ec.ig;
4936 FieldBase f = TypeManager.GetField (FieldInfo);
4938 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
4939 Report.Warning (420, 1, loc, "`{0}': A volatile field references will not be treated as volatile",
4940 f.GetSignatureForError ());
4943 if ((mode & AddressOp.Store) != 0)
4945 if ((mode & AddressOp.Load) != 0)
4946 f.SetMemberIsUsed ();
4950 // Handle initonly fields specially: make a copy and then
4951 // get the address of the copy.
4954 if (FieldInfo.IsInitOnly){
4956 if (ec.IsConstructor){
4957 if (FieldInfo.IsStatic){
4969 local = ig.DeclareLocal (type);
4970 ig.Emit (OpCodes.Stloc, local);
4971 ig.Emit (OpCodes.Ldloca, local);
4976 if (FieldInfo.IsStatic){
4977 ig.Emit (OpCodes.Ldsflda, FieldInfo);
4980 EmitInstance (ec, false);
4981 ig.Emit (OpCodes.Ldflda, FieldInfo);
4988 /// Expression that evaluates to a Property. The Assign class
4989 /// might set the `Value' expression if we are in an assignment.
4991 /// This is not an LValue because we need to re-write the expression, we
4992 /// can not take data from the stack and store it.
4994 public class PropertyExpr : MemberExpr, IAssignMethod {
4995 public readonly PropertyInfo PropertyInfo;
4996 MethodInfo getter, setter;
5001 LocalTemporary temp;
5004 public PropertyExpr (Type container_type, PropertyInfo pi, Location l)
5007 eclass = ExprClass.PropertyAccess;
5011 type = TypeManager.TypeToCoreType (pi.PropertyType);
5013 ResolveAccessors (container_type);
5016 public override string Name {
5018 return PropertyInfo.Name;
5022 public override bool IsInstance {
5028 public override bool IsStatic {
5034 public override Expression CreateExpressionTree (EmitContext ec)
5036 if (IsSingleDimensionalArrayLength ()) {
5037 ArrayList args = new ArrayList (1);
5038 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5039 return CreateExpressionFactoryCall ("ArrayLength", args);
5042 // TODO: it's waiting for PropertyExpr refactoring
5043 //ArrayList args = new ArrayList (2);
5044 //args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5045 //args.Add (getter expression);
5046 //return CreateExpressionFactoryCall ("Property", args);
5047 return base.CreateExpressionTree (ec);
5050 public override Type DeclaringType {
5052 return PropertyInfo.DeclaringType;
5056 public override string GetSignatureForError ()
5058 return TypeManager.GetFullNameSignature (PropertyInfo);
5061 void FindAccessors (Type invocation_type)
5063 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
5064 BindingFlags.Static | BindingFlags.Instance |
5065 BindingFlags.DeclaredOnly;
5067 Type current = PropertyInfo.DeclaringType;
5068 for (; current != null; current = current.BaseType) {
5069 MemberInfo[] group = TypeManager.MemberLookup (
5070 invocation_type, invocation_type, current,
5071 MemberTypes.Property, flags, PropertyInfo.Name, null);
5076 if (group.Length != 1)
5077 // Oooops, can this ever happen ?
5080 PropertyInfo pi = (PropertyInfo) group [0];
5083 getter = pi.GetGetMethod (true);
5086 setter = pi.GetSetMethod (true);
5088 MethodInfo accessor = getter != null ? getter : setter;
5090 if (!accessor.IsVirtual)
5096 // We also perform the permission checking here, as the PropertyInfo does not
5097 // hold the information for the accessibility of its setter/getter
5099 // TODO: Refactor to use some kind of cache together with GetPropertyFromAccessor
5100 void ResolveAccessors (Type container_type)
5102 FindAccessors (container_type);
5104 if (getter != null) {
5105 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
5106 IMethodData md = TypeManager.GetMethod (the_getter);
5108 md.SetMemberIsUsed ();
5110 is_static = getter.IsStatic;
5113 if (setter != null) {
5114 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
5115 IMethodData md = TypeManager.GetMethod (the_setter);
5117 md.SetMemberIsUsed ();
5119 is_static = setter.IsStatic;
5123 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
5126 InstanceExpression = null;
5130 if (InstanceExpression == null) {
5131 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5135 InstanceExpression = InstanceExpression.DoResolve (ec);
5136 if (lvalue_instance && InstanceExpression != null)
5137 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
5139 if (InstanceExpression == null)
5142 InstanceExpression.CheckMarshalByRefAccess (ec);
5144 if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) &&
5145 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
5146 !TypeManager.IsNestedChildOf (ec.ContainerType, InstanceExpression.Type) &&
5147 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.ContainerType)) {
5148 Report.SymbolRelatedToPreviousError (PropertyInfo);
5149 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
5156 void Error_PropertyNotFound (MethodInfo mi, bool getter)
5158 // TODO: correctly we should compare arguments but it will lead to bigger changes
5159 if (mi is MethodBuilder) {
5160 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
5164 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
5166 ParameterData iparams = TypeManager.GetParameterData (mi);
5167 sig.Append (getter ? "get_" : "set_");
5169 sig.Append (iparams.GetSignatureForError ());
5171 Report.SymbolRelatedToPreviousError (mi);
5172 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
5173 Name, sig.ToString ());
5176 public bool IsAccessibleFrom (Type invocation_type, bool lvalue)
5179 MethodInfo accessor = lvalue ? setter : getter;
5180 if (accessor == null && lvalue)
5182 return accessor != null && IsAccessorAccessible (invocation_type, accessor, out dummy);
5185 bool IsSingleDimensionalArrayLength ()
5187 if (DeclaringType != TypeManager.array_type || getter == null || Name != "Length")
5190 string t_name = InstanceExpression.Type.Name;
5191 int t_name_len = t_name.Length;
5192 return t_name_len > 2 && t_name [t_name_len - 2] == '[' && t_name [t_name_len - 3] != ']';
5195 override public Expression DoResolve (EmitContext ec)
5200 if (getter != null){
5201 if (TypeManager.GetParameterData (getter).Count != 0){
5202 Error_PropertyNotFound (getter, true);
5207 if (getter == null){
5209 // The following condition happens if the PropertyExpr was
5210 // created, but is invalid (ie, the property is inaccessible),
5211 // and we did not want to embed the knowledge about this in
5212 // the caller routine. This only avoids double error reporting.
5217 if (InstanceExpression != EmptyExpression.Null) {
5218 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5219 TypeManager.GetFullNameSignature (PropertyInfo));
5224 bool must_do_cs1540_check = false;
5225 if (getter != null &&
5226 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
5227 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
5228 if (pm != null && pm.HasCustomAccessModifier) {
5229 Report.SymbolRelatedToPreviousError (pm);
5230 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5231 TypeManager.CSharpSignature (getter));
5234 Report.SymbolRelatedToPreviousError (getter);
5235 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
5240 if (!InstanceResolve (ec, false, must_do_cs1540_check))
5244 // Only base will allow this invocation to happen.
5246 if (IsBase && getter.IsAbstract) {
5247 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5251 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
5261 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
5263 if (right_side == EmptyExpression.OutAccess) {
5264 if (ec.CurrentBlock.Toplevel.GetTransparentIdentifier (PropertyInfo.Name) != null) {
5265 Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5268 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as `ref' or `out' parameter",
5269 GetSignatureForError ());
5274 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5275 Error_CannotModifyIntermediateExpressionValue (ec);
5278 if (setter == null){
5280 // The following condition happens if the PropertyExpr was
5281 // created, but is invalid (ie, the property is inaccessible),
5282 // and we did not want to embed the knowledge about this in
5283 // the caller routine. This only avoids double error reporting.
5287 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
5288 GetSignatureForError ());
5292 if (TypeManager.GetParameterData (setter).Count != 1){
5293 Error_PropertyNotFound (setter, false);
5297 bool must_do_cs1540_check;
5298 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
5299 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
5300 if (pm != null && pm.HasCustomAccessModifier) {
5301 Report.SymbolRelatedToPreviousError (pm);
5302 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5303 TypeManager.CSharpSignature (setter));
5306 Report.SymbolRelatedToPreviousError (setter);
5307 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
5312 if (!InstanceResolve (ec, PropertyInfo.DeclaringType.IsValueType, must_do_cs1540_check))
5316 // Only base will allow this invocation to happen.
5318 if (IsBase && setter.IsAbstract){
5319 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5326 public override void Emit (EmitContext ec)
5331 public void Emit (EmitContext ec, bool leave_copy)
5334 // Special case: length of single dimension array property is turned into ldlen
5336 if (IsSingleDimensionalArrayLength ()) {
5338 EmitInstance (ec, false);
5339 ec.ig.Emit (OpCodes.Ldlen);
5340 ec.ig.Emit (OpCodes.Conv_I4);
5344 Invocation.EmitCall (ec, IsBase, InstanceExpression, getter, null, loc, prepared, false);
5347 ec.ig.Emit (OpCodes.Dup);
5349 temp = new LocalTemporary (this.Type);
5356 // Implements the IAssignMethod interface for assignments
5358 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5360 Expression my_source = source;
5362 if (prepare_for_load) {
5363 if (source is StringConcat)
5364 EmitInstance (ec, false);
5372 ec.ig.Emit (OpCodes.Dup);
5374 temp = new LocalTemporary (this.Type);
5378 } else if (leave_copy) {
5380 temp = new LocalTemporary (this.Type);
5385 ArrayList args = new ArrayList (1);
5386 args.Add (new Argument (my_source, Argument.AType.Expression));
5388 Invocation.EmitCall (ec, IsBase, InstanceExpression, setter, args, loc, false, prepared);
5398 /// Fully resolved expression that evaluates to an Event
5400 public class EventExpr : MemberExpr {
5401 public readonly EventInfo EventInfo;
5404 MethodInfo add_accessor, remove_accessor;
5406 public EventExpr (EventInfo ei, Location loc)
5410 eclass = ExprClass.EventAccess;
5412 add_accessor = TypeManager.GetAddMethod (ei);
5413 remove_accessor = TypeManager.GetRemoveMethod (ei);
5414 if (add_accessor.IsStatic || remove_accessor.IsStatic)
5417 if (EventInfo is MyEventBuilder){
5418 MyEventBuilder eb = (MyEventBuilder) EventInfo;
5419 type = eb.EventType;
5422 type = EventInfo.EventHandlerType;
5425 public override string Name {
5427 return EventInfo.Name;
5431 public override bool IsInstance {
5437 public override bool IsStatic {
5443 public override Type DeclaringType {
5445 return EventInfo.DeclaringType;
5449 void Error_AssignmentEventOnly ()
5451 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5452 GetSignatureForError ());
5455 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
5456 SimpleName original)
5459 // If the event is local to this class, we transform ourselves into a FieldExpr
5462 if (EventInfo.DeclaringType == ec.ContainerType ||
5463 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
5464 EventField mi = TypeManager.GetEventField (EventInfo);
5467 if (!ec.IsInObsoleteScope)
5468 mi.CheckObsoleteness (loc);
5470 if ((mi.ModFlags & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0 && !ec.IsInCompoundAssignment)
5471 Error_AssignmentEventOnly ();
5473 FieldExpr ml = new FieldExpr (mi.FieldBuilder, loc);
5475 InstanceExpression = null;
5477 return ml.ResolveMemberAccess (ec, left, loc, original);
5481 if (left is This && !ec.IsInCompoundAssignment)
5482 Error_AssignmentEventOnly ();
5484 return base.ResolveMemberAccess (ec, left, loc, original);
5488 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
5491 InstanceExpression = null;
5495 if (InstanceExpression == null) {
5496 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5500 InstanceExpression = InstanceExpression.DoResolve (ec);
5501 if (InstanceExpression == null)
5504 if (IsBase && add_accessor.IsAbstract) {
5505 Error_CannotCallAbstractBase(TypeManager.CSharpSignature(add_accessor));
5510 // This is using the same mechanism as the CS1540 check in PropertyExpr.
5511 // However, in the Event case, we reported a CS0122 instead.
5513 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
5514 InstanceExpression.Type != ec.ContainerType &&
5515 TypeManager.IsSubclassOf (ec.ContainerType, InstanceExpression.Type)) {
5516 Report.SymbolRelatedToPreviousError (EventInfo);
5517 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5524 public bool IsAccessibleFrom (Type invocation_type)
5527 return IsAccessorAccessible (invocation_type, add_accessor, out dummy) &&
5528 IsAccessorAccessible (invocation_type, remove_accessor, out dummy);
5531 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5533 return DoResolve (ec);
5536 public override Expression DoResolve (EmitContext ec)
5538 bool must_do_cs1540_check;
5539 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
5540 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
5541 Report.SymbolRelatedToPreviousError (EventInfo);
5542 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5546 if (!InstanceResolve (ec, must_do_cs1540_check))
5552 public override void Emit (EmitContext ec)
5554 Report.Error (70, loc, "The event `{0}' can only appear on the left hand side of += or -= "+
5555 "(except on the defining type)", GetSignatureForError ());
5558 public override string GetSignatureForError ()
5560 return TypeManager.CSharpSignature (EventInfo);
5563 public void EmitAddOrRemove (EmitContext ec, Expression source)
5565 BinaryDelegate source_del = source as BinaryDelegate;
5566 if (source_del == null) {
5570 Expression handler = source_del.Right;
5572 Argument arg = new Argument (handler, Argument.AType.Expression);
5573 ArrayList args = new ArrayList ();
5577 if (source_del.IsAddition)
5578 Invocation.EmitCall (
5579 ec, IsBase, InstanceExpression, add_accessor, args, loc);
5581 Invocation.EmitCall (
5582 ec, IsBase, InstanceExpression, remove_accessor, args, loc);
5586 public class TemporaryVariable : Expression, IMemoryLocation
5591 public TemporaryVariable (Type type, Location loc)
5595 eclass = ExprClass.Value;
5598 public override Expression DoResolve (EmitContext ec)
5603 TypeExpr te = new TypeExpression (type, loc);
5604 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
5605 if (!li.Resolve (ec))
5608 if (ec.MustCaptureVariable (li)) {
5609 ScopeInfo scope = li.Block.CreateScopeInfo ();
5610 var = scope.AddLocal (li);
5617 public Variable Variable {
5618 get { return var != null ? var : li.Variable; }
5621 public override void Emit (EmitContext ec)
5623 Variable.EmitInstance (ec);
5627 public void EmitLoadAddress (EmitContext ec)
5629 Variable.EmitInstance (ec);
5630 Variable.EmitAddressOf (ec);
5633 public void Store (EmitContext ec, Expression right_side)
5635 Variable.EmitInstance (ec);
5636 right_side.Emit (ec);
5637 Variable.EmitAssign (ec);
5640 public void EmitThis (EmitContext ec)
5642 Variable.EmitInstance (ec);
5645 public void EmitStore (EmitContext ec)
5647 Variable.EmitAssign (ec);
5650 public void AddressOf (EmitContext ec, AddressOp mode)
5652 EmitLoadAddress (ec);
5657 /// Handles `var' contextual keyword; var becomes a keyword only
5658 /// if no type called var exists in a variable scope
5660 public class VarExpr : SimpleName
5662 // Used for error reporting only
5663 ArrayList initializer;
5665 public VarExpr (Location loc)
5670 public ArrayList VariableInitializer {
5672 this.initializer = value;
5676 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5679 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
5681 type = right_side.Type;
5682 if (type == TypeManager.null_type || type == TypeManager.void_type || type == TypeManager.anonymous_method_type) {
5683 Report.Error (815, loc, "An implicitly typed local variable declaration cannot be initialized with `{0}'",
5684 right_side.GetSignatureForError ());
5688 eclass = ExprClass.Variable;
5692 protected override void Error_TypeOrNamespaceNotFound (IResolveContext ec)
5694 Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");
5697 public override TypeExpr ResolveAsContextualType (IResolveContext rc, bool silent)
5699 TypeExpr te = base.ResolveAsContextualType (rc, true);
5703 if (initializer == null)
5706 if (initializer.Count > 1) {
5707 Location loc = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [1]).Location;
5708 Report.Error (819, loc, "An implicitly typed local variable declaration cannot include multiple declarators");
5713 Expression variable_initializer = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [0]).expression_or_array_initializer;
5714 if (variable_initializer == null) {
5715 Report.Error (818, loc, "An implicitly typed local variable declarator must include an initializer");