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 (mi.DeclaringType.Assembly == invocation_type.Assembly ||
169 TypeManager.IsFriendAssembly (mi.DeclaringType.Assembly)) {
170 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamORAssem)
173 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamANDAssem)
177 // Family and FamANDAssem require that we derive.
178 // FamORAssem requires that we derive if in different assemblies.
179 if (!TypeManager.IsNestedFamilyAccessible (invocation_type, mi.DeclaringType))
182 if (!TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType))
183 must_do_cs1540_check = true;
188 public virtual bool IsNull {
195 /// Performs semantic analysis on the Expression
199 /// The Resolve method is invoked to perform the semantic analysis
202 /// The return value is an expression (it can be the
203 /// same expression in some cases) or a new
204 /// expression that better represents this node.
206 /// For example, optimizations of Unary (LiteralInt)
207 /// would return a new LiteralInt with a negated
210 /// If there is an error during semantic analysis,
211 /// then an error should be reported (using Report)
212 /// and a null value should be returned.
214 /// There are two side effects expected from calling
215 /// Resolve(): the the field variable "eclass" should
216 /// be set to any value of the enumeration
217 /// `ExprClass' and the type variable should be set
218 /// to a valid type (this is the type of the
221 public abstract Expression DoResolve (EmitContext ec);
223 public virtual Expression DoResolveLValue (EmitContext ec, Expression right_side)
229 // This is used if the expression should be resolved as a type or namespace name.
230 // the default implementation fails.
232 public virtual FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
238 // C# 3.0 introduced contextual keywords (var) which behaves like a type if type with
239 // same name exists or as a keyword when no type was found
241 public virtual TypeExpr ResolveAsContextualType (IResolveContext rc, bool silent)
243 return ResolveAsTypeTerminal (rc, silent);
247 // This is used to resolve the expression as a type, a null
248 // value will be returned if the expression is not a type
251 public virtual TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
253 TypeExpr te = ResolveAsBaseTerminal (ec, silent);
257 if (!silent) { // && !(te is TypeParameterExpr)) {
258 ObsoleteAttribute obsolete_attr = AttributeTester.GetObsoleteAttribute (te.Type);
259 if (obsolete_attr != null && !ec.IsInObsoleteScope) {
260 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location);
264 // Constrains don't need to be checked for overrides
265 GenericMethod gm = ec.GenericDeclContainer as GenericMethod;
266 if (gm != null && (gm.ModFlags & Modifiers.OVERRIDE) != 0) {
271 ConstructedType ct = te as ConstructedType;
272 if ((ct != null) && !ct.CheckConstraints (ec))
278 public TypeExpr ResolveAsBaseTerminal (IResolveContext ec, bool silent)
280 int errors = Report.Errors;
282 FullNamedExpression fne = ResolveAsTypeStep (ec, silent);
287 if (fne.eclass != ExprClass.Type) {
288 if (!silent && errors == Report.Errors)
289 fne.Error_UnexpectedKind (null, "type", loc);
293 TypeExpr te = fne as TypeExpr;
295 if (!te.CheckAccessLevel (ec.DeclContainer)) {
296 Report.SymbolRelatedToPreviousError (te.Type);
297 ErrorIsInaccesible (loc, TypeManager.CSharpName (te.Type));
305 public static void ErrorIsInaccesible (Location loc, string name)
307 Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", name);
310 protected static void Error_CannotAccessProtected (Location loc, MemberInfo m, Type qualifier, Type container)
312 Report.Error (1540, loc, "Cannot access protected member `{0}' via a qualifier of type `{1}'."
313 + " The qualifier must be of type `{2}' or derived from it",
314 TypeManager.GetFullNameSignature (m),
315 TypeManager.CSharpName (qualifier),
316 TypeManager.CSharpName (container));
320 public static void Error_InvalidExpressionStatement (Location loc)
322 Report.Error (201, loc, "Only assignment, call, increment, decrement, and new object " +
323 "expressions can be used as a statement");
326 public void Error_InvalidExpressionStatement ()
328 Error_InvalidExpressionStatement (loc);
331 protected void Error_CannotAssign (string to, string roContext)
333 Report.Error (1656, loc, "Cannot assign to `{0}' because it is a `{1}'",
337 public static void Error_VoidInvalidInTheContext (Location loc)
339 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
342 public virtual void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl)
344 // The error was already reported as CS1660
345 if (type == TypeManager.anonymous_method_type)
348 if (TypeManager.IsGenericParameter (Type) && TypeManager.IsGenericParameter (target) && type.Name == target.Name) {
350 string sig1 = type.DeclaringMethod == null ?
351 TypeManager.CSharpName (type.DeclaringType) :
352 TypeManager.CSharpSignature (type.DeclaringMethod);
353 string sig2 = target.DeclaringMethod == null ?
354 TypeManager.CSharpName (target.DeclaringType) :
355 TypeManager.CSharpSignature (target.DeclaringMethod);
356 Report.ExtraInformation (loc,
358 "The generic parameter `{0}' of `{1}' cannot be converted to the generic parameter `{0}' of `{2}' (in the previous ",
359 Type.Name, sig1, sig2));
361 } else if (Type.FullName == target.FullName){
362 Report.ExtraInformation (loc,
364 "The type `{0}' has two conflicting definitions, one comes from `{1}' and the other from `{2}' (in the previous ",
365 Type.FullName, Type.Assembly.FullName, target.Assembly.FullName));
369 Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
370 TypeManager.CSharpName (type), TypeManager.CSharpName (target));
374 Expression e = (this is EnumConstant) ? ((EnumConstant)this).Child : this;
375 bool b = Convert.ExplicitNumericConversion (e, target) != null;
378 Convert.ExplicitReferenceConversionExists (Type, target) ||
379 Convert.ExplicitUnsafe (e, target) != null ||
380 (ec != null && Convert.UserDefinedConversion (ec, this, target, Location.Null, true) != null))
382 Report.Error (266, loc, "Cannot implicitly convert type `{0}' to `{1}'. " +
383 "An explicit conversion exists (are you missing a cast?)",
384 TypeManager.CSharpName (Type), TypeManager.CSharpName (target));
388 if (Type != TypeManager.string_type && this is Constant && !(this is EmptyConstantCast)) {
389 Report.Error (31, loc, "Constant value `{0}' cannot be converted to a `{1}'",
390 ((Constant)(this)).GetValue ().ToString (), TypeManager.CSharpName (target));
394 Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
395 TypeManager.CSharpName (type),
396 TypeManager.CSharpName (target));
399 protected void Error_VariableIsUsedBeforeItIsDeclared (string name)
401 Report.Error (841, loc, "The variable `{0}' cannot be used before it is declared",
405 protected virtual void Error_TypeDoesNotContainDefinition (Type type, string name)
407 Error_TypeDoesNotContainDefinition (loc, type, name);
410 public static void Error_TypeDoesNotContainDefinition (Location loc, Type type, string name)
412 Report.SymbolRelatedToPreviousError (type);
413 Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
414 TypeManager.CSharpName (type), name);
417 protected static void Error_ValueAssignment (Location loc)
419 Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
422 ResolveFlags ExprClassToResolveFlags
427 case ExprClass.Namespace:
428 return ResolveFlags.Type;
430 case ExprClass.MethodGroup:
431 return ResolveFlags.MethodGroup;
433 case ExprClass.Value:
434 case ExprClass.Variable:
435 case ExprClass.PropertyAccess:
436 case ExprClass.EventAccess:
437 case ExprClass.IndexerAccess:
438 return ResolveFlags.VariableOrValue;
441 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
447 /// Resolves an expression and performs semantic analysis on it.
451 /// Currently Resolve wraps DoResolve to perform sanity
452 /// checking and assertion checking on what we expect from Resolve.
454 public Expression Resolve (EmitContext ec, ResolveFlags flags)
456 if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type)
457 return ResolveAsTypeStep (ec, false);
459 bool do_flow_analysis = ec.DoFlowAnalysis;
460 bool omit_struct_analysis = ec.OmitStructFlowAnalysis;
461 if ((flags & ResolveFlags.DisableFlowAnalysis) != 0)
462 do_flow_analysis = false;
463 if ((flags & ResolveFlags.DisableStructFlowAnalysis) != 0)
464 omit_struct_analysis = true;
467 using (ec.WithFlowAnalysis (do_flow_analysis, omit_struct_analysis)) {
468 if (this is SimpleName) {
469 bool intermediate = (flags & ResolveFlags.Intermediate) == ResolveFlags.Intermediate;
470 e = ((SimpleName) this).DoResolve (ec, intermediate);
479 if ((flags & e.ExprClassToResolveFlags) == 0) {
480 e.Error_UnexpectedKind (flags, loc);
484 if (e.type == null && !(e is Namespace)) {
485 throw new Exception (
486 "Expression " + e.GetType () +
487 " did not set its type after Resolve\n" +
488 "called from: " + this.GetType ());
495 /// Resolves an expression and performs semantic analysis on it.
497 public Expression Resolve (EmitContext ec)
499 Expression e = Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
501 if (e != null && e.eclass == ExprClass.MethodGroup && RootContext.Version == LanguageVersion.ISO_1) {
502 ((MethodGroupExpr) e).ReportUsageError ();
508 public Constant ResolveAsConstant (EmitContext ec, MemberCore mc)
510 Expression e = Resolve (ec);
514 Constant c = e as Constant;
518 Const.Error_ExpressionMustBeConstant (loc, mc.GetSignatureForError ());
523 /// Resolves an expression for LValue assignment
527 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
528 /// checking and assertion checking on what we expect from Resolve
530 public Expression ResolveLValue (EmitContext ec, Expression right_side, Location loc)
532 int errors = Report.Errors;
533 bool out_access = right_side == EmptyExpression.OutAccess;
535 Expression e = DoResolveLValue (ec, right_side);
537 if (e != null && out_access && !(e is IMemoryLocation)) {
538 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
539 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
541 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
542 // e.GetType () + " " + e.GetSignatureForError ());
547 if (errors == Report.Errors) {
549 Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
551 Error_ValueAssignment (loc);
556 if (e.eclass == ExprClass.Invalid)
557 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
559 if (e.eclass == ExprClass.MethodGroup) {
560 ((MethodGroupExpr) e).ReportUsageError ();
564 if ((e.type == null) && !(e is ConstructedType))
565 throw new Exception ("Expression " + e + " did not set its type after Resolve");
571 /// Emits the code for the expression
575 /// The Emit method is invoked to generate the code
576 /// for the expression.
578 public abstract void Emit (EmitContext ec);
580 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
583 ec.ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
587 /// Protected constructor. Only derivate types should
588 /// be able to be created
591 protected Expression ()
593 eclass = ExprClass.Invalid;
598 /// Returns a fully formed expression after a MemberLookup
601 public static Expression ExprClassFromMemberInfo (Type container_type, MemberInfo mi, Location loc)
604 return new EventExpr ((EventInfo) mi, loc);
605 else if (mi is FieldInfo) {
606 FieldInfo fi = (FieldInfo) mi;
607 if (fi.IsLiteral || (fi.IsInitOnly && fi.FieldType == TypeManager.decimal_type))
608 return new ConstantExpr (fi, loc);
609 return new FieldExpr (fi, loc);
610 } else if (mi is PropertyInfo)
611 return new PropertyExpr (container_type, (PropertyInfo) mi, loc);
612 else if (mi is Type) {
613 return new TypeExpression ((System.Type) mi, loc);
619 protected static ArrayList almost_matched_members = new ArrayList (4);
622 // FIXME: Probably implement a cache for (t,name,current_access_set)?
624 // This code could use some optimizations, but we need to do some
625 // measurements. For example, we could use a delegate to `flag' when
626 // something can not any longer be a method-group (because it is something
630 // If the return value is an Array, then it is an array of
633 // If the return value is an MemberInfo, it is anything, but a Method
637 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
638 // the arguments here and have MemberLookup return only the methods that
639 // match the argument count/type, unlike we are doing now (we delay this
642 // This is so we can catch correctly attempts to invoke instance methods
643 // from a static body (scan for error 120 in ResolveSimpleName).
646 // FIXME: Potential optimization, have a static ArrayList
649 public static Expression MemberLookup (Type container_type, Type queried_type, string name,
650 MemberTypes mt, BindingFlags bf, Location loc)
652 return MemberLookup (container_type, null, queried_type, name, mt, bf, loc);
656 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
657 // `qualifier_type' or null to lookup members in the current class.
660 public static Expression MemberLookup (Type container_type,
661 Type qualifier_type, Type queried_type,
662 string name, MemberTypes mt,
663 BindingFlags bf, Location loc)
665 almost_matched_members.Clear ();
667 MemberInfo [] mi = TypeManager.MemberLookup (container_type, qualifier_type,
668 queried_type, mt, bf, name, almost_matched_members);
674 bool is_interface = qualifier_type != null && qualifier_type.IsInterface;
675 ArrayList methods = new ArrayList (2);
676 ArrayList non_methods = null;
678 foreach (MemberInfo m in mi) {
679 if (m is MethodBase) {
684 if (non_methods == null) {
685 non_methods = new ArrayList (2);
690 foreach (MemberInfo n_m in non_methods) {
691 if (m.DeclaringType.IsInterface && TypeManager.ImplementsInterface (m.DeclaringType, n_m.DeclaringType))
694 Report.SymbolRelatedToPreviousError (m);
695 Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
696 TypeManager.GetFullNameSignature (m), TypeManager.GetFullNameSignature (n_m));
701 if (methods.Count == 0)
702 return ExprClassFromMemberInfo (container_type, (MemberInfo)non_methods [0], loc);
704 if (non_methods != null) {
705 MethodBase method = (MethodBase) methods [0];
706 MemberInfo non_method = (MemberInfo) non_methods [0];
707 if (method.DeclaringType == non_method.DeclaringType) {
708 // Cannot happen with C# code, but is valid in IL
709 Report.SymbolRelatedToPreviousError (method);
710 Report.SymbolRelatedToPreviousError (non_method);
711 Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
712 TypeManager.GetFullNameSignature (non_method),
713 TypeManager.CSharpSignature (method));
718 Report.SymbolRelatedToPreviousError (method);
719 Report.SymbolRelatedToPreviousError (non_method);
720 Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and non-method `{1}'. Using method `{0}'",
721 TypeManager.CSharpSignature (method), TypeManager.GetFullNameSignature (non_method));
725 return new MethodGroupExpr (methods, queried_type, loc);
728 if (mi [0] is MethodBase)
729 return new MethodGroupExpr (mi, queried_type, loc);
731 return ExprClassFromMemberInfo (container_type, mi [0], loc);
734 public const MemberTypes AllMemberTypes =
735 MemberTypes.Constructor |
739 MemberTypes.NestedType |
740 MemberTypes.Property;
742 public const BindingFlags AllBindingFlags =
743 BindingFlags.Public |
744 BindingFlags.Static |
745 BindingFlags.Instance;
747 public static Expression MemberLookup (Type container_type, Type queried_type,
748 string name, Location loc)
750 return MemberLookup (container_type, null, queried_type, name,
751 AllMemberTypes, AllBindingFlags, loc);
754 public static Expression MemberLookup (Type container_type, Type qualifier_type,
755 Type queried_type, string name, Location loc)
757 return MemberLookup (container_type, qualifier_type, queried_type,
758 name, AllMemberTypes, AllBindingFlags, loc);
761 public static MethodGroupExpr MethodLookup (Type container_type, Type queried_type,
762 string name, Location loc)
764 return (MethodGroupExpr)MemberLookup (container_type, null, queried_type, name,
765 MemberTypes.Method, AllBindingFlags, loc);
769 /// This is a wrapper for MemberLookup that is not used to "probe", but
770 /// to find a final definition. If the final definition is not found, we
771 /// look for private members and display a useful debugging message if we
774 protected Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
775 Type queried_type, string name,
776 MemberTypes mt, BindingFlags bf,
781 int errors = Report.Errors;
783 e = MemberLookup (ec.ContainerType, qualifier_type, queried_type, name, mt, bf, loc);
785 if (e != null || errors != Report.Errors)
788 // No errors were reported by MemberLookup, but there was an error.
789 return Error_MemberLookupFailed (ec.ContainerType, qualifier_type, queried_type,
793 protected virtual Expression Error_MemberLookupFailed (Type container_type, Type qualifier_type,
794 Type queried_type, string name, string class_name,
795 MemberTypes mt, BindingFlags bf)
797 if (almost_matched_members.Count != 0) {
798 for (int i = 0; i < almost_matched_members.Count; ++i) {
799 MemberInfo m = (MemberInfo) almost_matched_members [i];
800 for (int j = 0; j < i; ++j) {
801 if (m == almost_matched_members [j]) {
809 Type declaring_type = m.DeclaringType;
811 Report.SymbolRelatedToPreviousError (m);
812 if (qualifier_type == null) {
813 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
814 TypeManager.CSharpName (m.DeclaringType),
815 TypeManager.CSharpName (container_type));
817 } else if (qualifier_type != container_type &&
818 TypeManager.IsNestedFamilyAccessible (container_type, declaring_type)) {
819 // Although a derived class can access protected members of
820 // its base class it cannot do so through an instance of the
821 // base class (CS1540). If the qualifier_type is a base of the
822 // ec.ContainerType and the lookup succeeds with the latter one,
823 // then we are in this situation.
824 Error_CannotAccessProtected (loc, m, qualifier_type, container_type);
826 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (m));
829 almost_matched_members.Clear ();
833 MemberInfo[] lookup = null;
834 if (queried_type == null) {
835 class_name = "global::";
837 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
838 mt, (bf & ~BindingFlags.Public) | BindingFlags.NonPublic,
841 if (lookup != null) {
842 Report.SymbolRelatedToPreviousError (lookup [0]);
843 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (lookup [0]));
844 return Error_MemberLookupFailed (lookup);
847 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
848 AllMemberTypes, AllBindingFlags | BindingFlags.NonPublic,
852 if (lookup == null) {
853 if (class_name != null) {
854 Report.Error (103, loc, "The name `{0}' does not exist in the current context",
857 Error_TypeDoesNotContainDefinition (queried_type, name);
862 if (TypeManager.MemberLookup (queried_type, null, queried_type,
863 AllMemberTypes, AllBindingFlags |
864 BindingFlags.NonPublic, name, null) == null) {
865 if ((lookup.Length == 1) && (lookup [0] is Type)) {
866 Type t = (Type) lookup [0];
868 Report.Error (305, loc,
869 "Using the generic type `{0}' " +
870 "requires {1} type arguments",
871 TypeManager.CSharpName (t),
872 TypeManager.GetNumberOfTypeArguments (t).ToString ());
877 return Error_MemberLookupFailed (lookup);
880 protected virtual Expression Error_MemberLookupFailed (MemberInfo[] members)
882 for (int i = 0; i < members.Length; ++i) {
883 if (!(members [i] is MethodBase))
887 // By default propagate the closest candidates upwards
888 return new MethodGroupExpr (members, type, loc);
891 protected virtual void Error_NegativeArrayIndex (Location loc)
893 throw new NotImplementedException ();
897 /// Returns an expression that can be used to invoke operator true
898 /// on the expression if it exists.
900 static public Expression GetOperatorTrue (EmitContext ec, Expression e, Location loc)
902 return GetOperatorTrueOrFalse (ec, e, true, loc);
906 /// Returns an expression that can be used to invoke operator false
907 /// on the expression if it exists.
909 static public Expression GetOperatorFalse (EmitContext ec, Expression e, Location loc)
911 return GetOperatorTrueOrFalse (ec, e, false, loc);
914 static Expression GetOperatorTrueOrFalse (EmitContext ec, Expression e, bool is_true, Location loc)
916 MethodGroupExpr operator_group;
917 operator_group = MethodLookup (ec.ContainerType, e.Type, is_true ? "op_True" : "op_False", loc) as MethodGroupExpr;
918 if (operator_group == null)
921 ArrayList arguments = new ArrayList (1);
922 arguments.Add (new Argument (e, Argument.AType.Expression));
923 operator_group = operator_group.OverloadResolve (
924 ec, ref arguments, false, loc);
926 if (operator_group == null)
929 return new UserOperatorCall (operator_group, arguments, null, loc);
933 /// Resolves the expression `e' into a boolean expression: either through
934 /// an implicit conversion, or through an `operator true' invocation
936 public static Expression ResolveBoolean (EmitContext ec, Expression e, Location loc)
942 if (e.Type == TypeManager.bool_type)
945 Expression converted = Convert.ImplicitConversion (ec, e, TypeManager.bool_type, Location.Null);
947 if (converted != null)
951 // If no implicit conversion to bool exists, try using `operator true'
953 converted = Expression.GetOperatorTrue (ec, e, loc);
954 if (converted == null){
955 e.Error_ValueCannotBeConverted (ec, loc, TypeManager.bool_type, false);
961 public virtual string ExprClassName
965 case ExprClass.Invalid:
967 case ExprClass.Value:
969 case ExprClass.Variable:
971 case ExprClass.Namespace:
975 case ExprClass.MethodGroup:
976 return "method group";
977 case ExprClass.PropertyAccess:
978 return "property access";
979 case ExprClass.EventAccess:
980 return "event access";
981 case ExprClass.IndexerAccess:
982 return "indexer access";
983 case ExprClass.Nothing:
986 throw new Exception ("Should not happen");
991 /// Reports that we were expecting `expr' to be of class `expected'
993 public void Error_UnexpectedKind (DeclSpace ds, string expected, Location loc)
995 Error_UnexpectedKind (ds, expected, ExprClassName, loc);
998 public void Error_UnexpectedKind (DeclSpace ds, string expected, string was, Location loc)
1000 string name = GetSignatureForError ();
1002 name = ds.GetSignatureForError () + '.' + name;
1004 Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
1005 name, was, expected);
1008 public void Error_UnexpectedKind (ResolveFlags flags, Location loc)
1010 string [] valid = new string [4];
1013 if ((flags & ResolveFlags.VariableOrValue) != 0) {
1014 valid [count++] = "variable";
1015 valid [count++] = "value";
1018 if ((flags & ResolveFlags.Type) != 0)
1019 valid [count++] = "type";
1021 if ((flags & ResolveFlags.MethodGroup) != 0)
1022 valid [count++] = "method group";
1025 valid [count++] = "unknown";
1027 StringBuilder sb = new StringBuilder (valid [0]);
1028 for (int i = 1; i < count - 1; i++) {
1030 sb.Append (valid [i]);
1033 sb.Append ("' or `");
1034 sb.Append (valid [count - 1]);
1037 Report.Error (119, loc,
1038 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1041 public static void UnsafeError (Location loc)
1043 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1047 // Load the object from the pointer.
1049 public static void LoadFromPtr (ILGenerator ig, Type t)
1051 if (t == TypeManager.int32_type)
1052 ig.Emit (OpCodes.Ldind_I4);
1053 else if (t == TypeManager.uint32_type)
1054 ig.Emit (OpCodes.Ldind_U4);
1055 else if (t == TypeManager.short_type)
1056 ig.Emit (OpCodes.Ldind_I2);
1057 else if (t == TypeManager.ushort_type)
1058 ig.Emit (OpCodes.Ldind_U2);
1059 else if (t == TypeManager.char_type)
1060 ig.Emit (OpCodes.Ldind_U2);
1061 else if (t == TypeManager.byte_type)
1062 ig.Emit (OpCodes.Ldind_U1);
1063 else if (t == TypeManager.sbyte_type)
1064 ig.Emit (OpCodes.Ldind_I1);
1065 else if (t == TypeManager.uint64_type)
1066 ig.Emit (OpCodes.Ldind_I8);
1067 else if (t == TypeManager.int64_type)
1068 ig.Emit (OpCodes.Ldind_I8);
1069 else if (t == TypeManager.float_type)
1070 ig.Emit (OpCodes.Ldind_R4);
1071 else if (t == TypeManager.double_type)
1072 ig.Emit (OpCodes.Ldind_R8);
1073 else if (t == TypeManager.bool_type)
1074 ig.Emit (OpCodes.Ldind_I1);
1075 else if (t == TypeManager.intptr_type)
1076 ig.Emit (OpCodes.Ldind_I);
1077 else if (TypeManager.IsEnumType (t)) {
1078 if (t == TypeManager.enum_type)
1079 ig.Emit (OpCodes.Ldind_Ref);
1081 LoadFromPtr (ig, TypeManager.EnumToUnderlying (t));
1082 } else if (t.IsValueType || TypeManager.IsGenericParameter (t))
1083 ig.Emit (OpCodes.Ldobj, t);
1084 else if (t.IsPointer)
1085 ig.Emit (OpCodes.Ldind_I);
1087 ig.Emit (OpCodes.Ldind_Ref);
1091 // The stack contains the pointer and the value of type `type'
1093 public static void StoreFromPtr (ILGenerator ig, Type type)
1095 if (TypeManager.IsEnumType (type))
1096 type = TypeManager.EnumToUnderlying (type);
1097 if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
1098 ig.Emit (OpCodes.Stind_I4);
1099 else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
1100 ig.Emit (OpCodes.Stind_I8);
1101 else if (type == TypeManager.char_type || type == TypeManager.short_type ||
1102 type == TypeManager.ushort_type)
1103 ig.Emit (OpCodes.Stind_I2);
1104 else if (type == TypeManager.float_type)
1105 ig.Emit (OpCodes.Stind_R4);
1106 else if (type == TypeManager.double_type)
1107 ig.Emit (OpCodes.Stind_R8);
1108 else if (type == TypeManager.byte_type || type == TypeManager.sbyte_type ||
1109 type == TypeManager.bool_type)
1110 ig.Emit (OpCodes.Stind_I1);
1111 else if (type == TypeManager.intptr_type)
1112 ig.Emit (OpCodes.Stind_I);
1113 else if (type.IsValueType || TypeManager.IsGenericParameter (type))
1114 ig.Emit (OpCodes.Stobj, type);
1116 ig.Emit (OpCodes.Stind_Ref);
1120 // Returns the size of type `t' if known, otherwise, 0
1122 public static int GetTypeSize (Type t)
1124 t = TypeManager.TypeToCoreType (t);
1125 if (t == TypeManager.int32_type ||
1126 t == TypeManager.uint32_type ||
1127 t == TypeManager.float_type)
1129 else if (t == TypeManager.int64_type ||
1130 t == TypeManager.uint64_type ||
1131 t == TypeManager.double_type)
1133 else if (t == TypeManager.byte_type ||
1134 t == TypeManager.sbyte_type ||
1135 t == TypeManager.bool_type)
1137 else if (t == TypeManager.short_type ||
1138 t == TypeManager.char_type ||
1139 t == TypeManager.ushort_type)
1141 else if (t == TypeManager.decimal_type)
1147 protected void Error_CannotCallAbstractBase (string name)
1149 Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
1152 protected void Error_CannotModifyIntermediateExpressionValue (EmitContext ec)
1154 Report.SymbolRelatedToPreviousError (type);
1155 if (ec.CurrentInitializerVariable != null) {
1156 Report.Error (1918, loc, "Members of a value type property `{0}' cannot be assigned with an object initializer",
1157 GetSignatureForError ());
1159 Report.Error (1612, loc, "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
1160 GetSignatureForError ());
1165 // Converts `source' to an int, uint, long or ulong.
1167 public Expression ConvertExpressionToArrayIndex (EmitContext ec, Expression source)
1169 Expression converted;
1171 using (ec.With (EmitContext.Flags.CheckState, true)) {
1172 converted = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, source.loc);
1173 if (converted == null)
1174 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, source.loc);
1175 if (converted == null)
1176 converted = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, source.loc);
1177 if (converted == null)
1178 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, source.loc);
1180 if (converted == null) {
1181 source.Error_ValueCannotBeConverted (ec, source.loc, TypeManager.int32_type, false);
1187 // Only positive constants are allowed at compile time
1189 Constant c = converted as Constant;
1192 Error_NegativeArrayIndex (source.loc);
1197 return new ArrayIndexCast (converted).Resolve (ec);
1201 // Derived classes implement this method by cloning the fields that
1202 // could become altered during the Resolve stage
1204 // Only expressions that are created for the parser need to implement
1207 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1209 throw new NotImplementedException (
1211 "CloneTo not implemented for expression {0}", this.GetType ()));
1215 // Clones an expression created by the parser.
1217 // We only support expressions created by the parser so far, not
1218 // expressions that have been resolved (many more classes would need
1219 // to implement CloneTo).
1221 // This infrastructure is here merely for Lambda expressions which
1222 // compile the same code using different type values for the same
1223 // arguments to find the correct overload
1225 public Expression Clone (CloneContext clonectx)
1227 Expression cloned = (Expression) MemberwiseClone ();
1228 CloneTo (clonectx, cloned);
1233 public virtual Expression CreateExpressionTree (EmitContext ec)
1235 throw new NotImplementedException (
1236 "Expression tree conversion not implemented for " + GetType ());
1239 protected Expression CreateExpressionFactoryCall (string name, ArrayList args)
1241 return CreateExpressionFactoryCall (name, null, args, loc);
1244 protected Expression CreateExpressionFactoryCall (string name, TypeArguments typeArguments, ArrayList args)
1246 return CreateExpressionFactoryCall (name, typeArguments, args, loc);
1249 public static Expression CreateExpressionFactoryCall (string name, TypeArguments typeArguments, ArrayList args, Location loc)
1251 TypeExpression texpr = new TypeExpression (LinqExpression.expression_type, loc);
1252 return new Invocation (new MemberAccess (texpr, name, typeArguments, loc), args);
1257 /// This is just a base class for expressions that can
1258 /// appear on statements (invocations, object creation,
1259 /// assignments, post/pre increment and decrement). The idea
1260 /// being that they would support an extra Emition interface that
1261 /// does not leave a result on the stack.
1263 public abstract class ExpressionStatement : Expression {
1265 public virtual ExpressionStatement ResolveStatement (EmitContext ec)
1267 Expression e = Resolve (ec);
1271 ExpressionStatement es = e as ExpressionStatement;
1273 Error_InvalidExpressionStatement ();
1279 /// Requests the expression to be emitted in a `statement'
1280 /// context. This means that no new value is left on the
1281 /// stack after invoking this method (constrasted with
1282 /// Emit that will always leave a value on the stack).
1284 public abstract void EmitStatement (EmitContext ec);
1288 /// This kind of cast is used to encapsulate the child
1289 /// whose type is child.Type into an expression that is
1290 /// reported to return "return_type". This is used to encapsulate
1291 /// expressions which have compatible types, but need to be dealt
1292 /// at higher levels with.
1294 /// For example, a "byte" expression could be encapsulated in one
1295 /// of these as an "unsigned int". The type for the expression
1296 /// would be "unsigned int".
1299 public class EmptyCast : Expression
1301 protected Expression child;
1303 protected EmptyCast (Expression child, Type return_type)
1305 eclass = child.eclass;
1306 loc = child.Location;
1311 public static Expression Create (Expression child, Type type)
1313 Constant c = child as Constant;
1315 return new EmptyConstantCast (c, type);
1317 return new EmptyCast (child, type);
1320 public override Expression CreateExpressionTree (EmitContext ec)
1322 ArrayList args = new ArrayList (2);
1323 args.Add (new Argument (child.CreateExpressionTree (ec)));
1324 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1325 return CreateExpressionFactoryCall (ec.CheckState ? "ConvertChecked" : "Convert", args);
1328 public override Expression DoResolve (EmitContext ec)
1330 // This should never be invoked, we are born in fully
1331 // initialized state.
1336 public override void Emit (EmitContext ec)
1341 public override bool GetAttributableValue (Type value_type, out object value)
1343 return child.GetAttributableValue (value_type, out value);
1346 protected override void CloneTo (CloneContext clonectx, Expression t)
1348 EmptyCast target = (EmptyCast) t;
1350 target.child = child.Clone (clonectx);
1355 /// Performs a cast using an operator (op_Explicit or op_Implicit)
1357 public class OperatorCast : EmptyCast {
1358 MethodInfo conversion_operator;
1361 public OperatorCast (Expression child, Type target_type) : this (child, target_type, false) {}
1363 public OperatorCast (Expression child, Type target_type, bool find_explicit)
1364 : base (child, target_type)
1366 this.find_explicit = find_explicit;
1369 // Returns the implicit operator that converts from
1370 // 'child.Type' to our target type (type)
1371 MethodInfo GetConversionOperator (bool find_explicit)
1373 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1377 mi = TypeManager.MemberLookup (child.Type, child.Type, child.Type, MemberTypes.Method,
1378 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1381 mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1382 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1385 foreach (MethodInfo oper in mi) {
1386 ParameterData pd = TypeManager.GetParameterData (oper);
1388 if (pd.ParameterType (0) == child.Type && oper.ReturnType == type)
1396 public override void Emit (EmitContext ec)
1398 ILGenerator ig = ec.ig;
1401 conversion_operator = GetConversionOperator (find_explicit);
1403 if (conversion_operator == null)
1404 throw new InternalErrorException ("Outer conversion routine is out of sync");
1406 ig.Emit (OpCodes.Call, conversion_operator);
1412 /// This is a numeric cast to a Decimal
1414 public class CastToDecimal : EmptyCast {
1415 MethodInfo conversion_operator;
1417 public CastToDecimal (Expression child)
1418 : this (child, false)
1422 public CastToDecimal (Expression child, bool find_explicit)
1423 : base (child, TypeManager.decimal_type)
1425 conversion_operator = GetConversionOperator (find_explicit);
1427 if (conversion_operator == null)
1428 throw new InternalErrorException ("Outer conversion routine is out of sync");
1431 // Returns the implicit operator that converts from
1432 // 'child.Type' to System.Decimal.
1433 MethodInfo GetConversionOperator (bool find_explicit)
1435 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1437 MemberInfo [] mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1438 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1440 foreach (MethodInfo oper in mi) {
1441 ParameterData pd = TypeManager.GetParameterData (oper);
1443 if (pd.ParameterType (0) == child.Type && oper.ReturnType == type)
1449 public override void Emit (EmitContext ec)
1451 ILGenerator ig = ec.ig;
1454 ig.Emit (OpCodes.Call, conversion_operator);
1459 /// This is an explicit numeric cast from a Decimal
1461 public class CastFromDecimal : EmptyCast
1463 static IDictionary operators;
1465 public CastFromDecimal (Expression child, Type return_type)
1466 : base (child, return_type)
1468 if (child.Type != TypeManager.decimal_type)
1469 throw new InternalErrorException (
1470 "The expected type is Decimal, instead it is " + child.Type.FullName);
1473 // Returns the explicit operator that converts from an
1474 // express of type System.Decimal to 'type'.
1475 public Expression Resolve ()
1477 if (operators == null) {
1478 MemberInfo[] all_oper = TypeManager.MemberLookup (TypeManager.decimal_type,
1479 TypeManager.decimal_type, TypeManager.decimal_type, MemberTypes.Method,
1480 BindingFlags.Static | BindingFlags.Public, "op_Explicit", null);
1482 operators = new System.Collections.Specialized.HybridDictionary ();
1483 foreach (MethodInfo oper in all_oper) {
1484 ParameterData pd = TypeManager.GetParameterData (oper);
1485 if (pd.ParameterType (0) == TypeManager.decimal_type)
1486 operators.Add (oper.ReturnType, oper);
1490 return operators.Contains (type) ? this : null;
1493 public override void Emit (EmitContext ec)
1495 ILGenerator ig = ec.ig;
1498 ig.Emit (OpCodes.Call, (MethodInfo)operators [type]);
1504 // Constant specialization of EmptyCast.
1505 // We need to special case this since an empty cast of
1506 // a constant is still a constant.
1508 public class EmptyConstantCast : Constant
1510 public readonly Constant child;
1512 public EmptyConstantCast(Constant child, Type type)
1513 : base (child.Location)
1515 eclass = child.eclass;
1520 public override string AsString ()
1522 return child.AsString ();
1525 public override object GetValue ()
1527 return child.GetValue ();
1530 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
1532 // FIXME: check that 'type' can be converted to 'target_type' first
1533 return child.ConvertExplicitly (in_checked_context, target_type);
1536 public override Constant Increment ()
1538 return child.Increment ();
1541 public override bool IsDefaultValue {
1542 get { return child.IsDefaultValue; }
1545 public override bool IsNegative {
1546 get { return child.IsNegative; }
1549 public override bool IsNull {
1550 get { return child.IsNull; }
1553 public override bool IsZeroInteger {
1554 get { return child.IsZeroInteger; }
1557 public override void Emit (EmitContext ec)
1562 public override Constant ConvertImplicitly (Type target_type)
1564 // FIXME: Do we need to check user conversions?
1565 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1567 return child.ConvertImplicitly (target_type);
1573 /// This class is used to wrap literals which belong inside Enums
1575 public class EnumConstant : Constant {
1576 public Constant Child;
1578 public EnumConstant (Constant child, Type enum_type):
1579 base (child.Location)
1581 eclass = child.eclass;
1586 public override Expression DoResolve (EmitContext ec)
1588 // This should never be invoked, we are born in fully
1589 // initialized state.
1594 public override void Emit (EmitContext ec)
1599 public override bool GetAttributableValue (Type value_type, out object value)
1601 value = GetTypedValue ();
1605 public override string GetSignatureForError()
1607 return TypeManager.CSharpName (Type);
1610 public override object GetValue ()
1612 return Child.GetValue ();
1615 public override object GetTypedValue ()
1617 // FIXME: runtime is not ready to work with just emited enums
1618 if (!RootContext.StdLib) {
1619 return Child.GetValue ();
1622 return System.Enum.ToObject (type, Child.GetValue ());
1625 public override string AsString ()
1627 return TypeManager.CSharpEnumValue (type, Child.GetValue ());
1630 public override Constant Increment()
1632 return new EnumConstant (Child.Increment (), type);
1635 public override bool IsDefaultValue {
1637 return Child.IsDefaultValue;
1641 public override bool IsZeroInteger {
1642 get { return Child.IsZeroInteger; }
1645 public override bool IsNegative {
1647 return Child.IsNegative;
1651 public override Constant ConvertExplicitly(bool in_checked_context, Type target_type)
1653 if (Child.Type == target_type)
1656 return Child.ConvertExplicitly (in_checked_context, target_type);
1659 public override Constant ConvertImplicitly (Type type)
1661 Type this_type = TypeManager.DropGenericTypeArguments (Type);
1662 type = TypeManager.DropGenericTypeArguments (type);
1664 if (this_type == type) {
1665 // This is workaround of mono bug. It can be removed when the latest corlib spreads enough
1666 if (TypeManager.IsEnumType (type.UnderlyingSystemType))
1669 Type child_type = TypeManager.DropGenericTypeArguments (Child.Type);
1670 if (type.UnderlyingSystemType != child_type)
1671 Child = Child.ConvertImplicitly (type.UnderlyingSystemType);
1675 if (!Convert.ImplicitStandardConversionExists (this, type)){
1679 return Child.ConvertImplicitly(type);
1685 /// This kind of cast is used to encapsulate Value Types in objects.
1687 /// The effect of it is to box the value type emitted by the previous
1690 public class BoxedCast : EmptyCast {
1692 public BoxedCast (Expression expr, Type target_type)
1693 : base (expr, target_type)
1695 eclass = ExprClass.Value;
1698 public override Expression DoResolve (EmitContext ec)
1700 // This should never be invoked, we are born in fully
1701 // initialized state.
1706 public override void Emit (EmitContext ec)
1710 ec.ig.Emit (OpCodes.Box, child.Type);
1714 public class UnboxCast : EmptyCast {
1715 public UnboxCast (Expression expr, Type return_type)
1716 : base (expr, return_type)
1720 public override Expression DoResolve (EmitContext ec)
1722 // This should never be invoked, we are born in fully
1723 // initialized state.
1728 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1730 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
1731 Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
1732 return base.DoResolveLValue (ec, right_side);
1735 public override void Emit (EmitContext ec)
1738 ILGenerator ig = ec.ig;
1742 if (t.IsGenericParameter || t.IsGenericType && t.IsValueType)
1743 ig.Emit (OpCodes.Unbox_Any, t);
1747 ig.Emit (OpCodes.Unbox, t);
1749 LoadFromPtr (ig, t);
1755 /// This is used to perform explicit numeric conversions.
1757 /// Explicit numeric conversions might trigger exceptions in a checked
1758 /// context, so they should generate the conv.ovf opcodes instead of
1761 public class ConvCast : EmptyCast {
1762 public enum Mode : byte {
1763 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1765 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1766 U2_I1, U2_U1, U2_I2, U2_CH,
1767 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1768 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1769 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH,
1770 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH,
1771 CH_I1, CH_U1, CH_I2,
1772 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1773 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4
1778 public ConvCast (Expression child, Type return_type, Mode m)
1779 : base (child, return_type)
1784 public override Expression DoResolve (EmitContext ec)
1786 // This should never be invoked, we are born in fully
1787 // initialized state.
1792 public override string ToString ()
1794 return String.Format ("ConvCast ({0}, {1})", mode, child);
1797 public override void Emit (EmitContext ec)
1799 ILGenerator ig = ec.ig;
1805 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1806 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1807 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1808 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1809 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1811 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1812 case Mode.U1_CH: /* nothing */ break;
1814 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1815 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1816 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1817 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1818 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1819 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1821 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1822 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1823 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1824 case Mode.U2_CH: /* nothing */ break;
1826 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1827 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1828 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1829 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1830 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1831 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1832 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1834 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1835 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1836 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1837 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1838 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1839 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1841 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1842 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1843 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1844 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1845 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1846 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1847 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1848 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1850 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1851 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1852 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1853 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1854 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1855 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1856 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1857 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1859 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1860 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1861 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1863 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1864 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1865 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1866 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1867 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1868 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1869 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1870 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1871 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1873 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1874 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1875 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1876 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1877 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1878 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1879 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1880 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1881 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1882 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1886 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
1887 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
1888 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
1889 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
1890 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
1892 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
1893 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
1895 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
1896 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
1897 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
1898 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
1899 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
1900 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
1902 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
1903 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
1904 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
1905 case Mode.U2_CH: /* nothing */ break;
1907 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
1908 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
1909 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
1910 case Mode.I4_U4: /* nothing */ break;
1911 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
1912 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
1913 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
1915 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
1916 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
1917 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
1918 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
1919 case Mode.U4_I4: /* nothing */ break;
1920 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
1922 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
1923 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
1924 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
1925 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
1926 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
1927 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
1928 case Mode.I8_U8: /* nothing */ break;
1929 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
1931 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
1932 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
1933 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
1934 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
1935 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
1936 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
1937 case Mode.U8_I8: /* nothing */ break;
1938 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
1940 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
1941 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
1942 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
1944 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
1945 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
1946 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
1947 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
1948 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
1949 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
1950 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
1951 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
1952 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
1954 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
1955 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
1956 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
1957 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
1958 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
1959 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
1960 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
1961 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
1962 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
1963 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1969 public class OpcodeCast : EmptyCast {
1973 public OpcodeCast (Expression child, Type return_type, OpCode op)
1974 : base (child, return_type)
1978 second_valid = false;
1981 public OpcodeCast (Expression child, Type return_type, OpCode op, OpCode op2)
1982 : base (child, return_type)
1987 second_valid = true;
1990 public override Expression DoResolve (EmitContext ec)
1992 // This should never be invoked, we are born in fully
1993 // initialized state.
1998 public override void Emit (EmitContext ec)
2009 /// This kind of cast is used to encapsulate a child and cast it
2010 /// to the class requested
2012 public class ClassCast : EmptyCast {
2013 public ClassCast (Expression child, Type return_type)
2014 : base (child, return_type)
2019 public override Expression DoResolve (EmitContext ec)
2021 // This should never be invoked, we are born in fully
2022 // initialized state.
2027 public override void Emit (EmitContext ec)
2031 if (TypeManager.IsGenericParameter (child.Type))
2032 ec.ig.Emit (OpCodes.Box, child.Type);
2035 if (type.IsGenericParameter)
2036 ec.ig.Emit (OpCodes.Unbox_Any, type);
2039 ec.ig.Emit (OpCodes.Castclass, type);
2044 /// SimpleName expressions are formed of a single word and only happen at the beginning
2045 /// of a dotted-name.
2047 public class SimpleName : Expression {
2048 public readonly string Name;
2049 public readonly TypeArguments Arguments;
2052 public SimpleName (string name, Location l)
2058 public SimpleName (string name, TypeArguments args, Location l)
2065 public SimpleName (string name, TypeParameter[] type_params, Location l)
2070 Arguments = new TypeArguments (l);
2071 foreach (TypeParameter type_param in type_params)
2072 Arguments.Add (new TypeParameterExpr (type_param, l));
2075 public static string RemoveGenericArity (string name)
2078 StringBuilder sb = null;
2080 int pos = name.IndexOf ('`', start);
2085 sb.Append (name.Substring (start));
2090 sb = new StringBuilder ();
2091 sb.Append (name.Substring (start, pos-start));
2094 while ((pos < name.Length) && Char.IsNumber (name [pos]))
2098 } while (start < name.Length);
2100 return sb.ToString ();
2103 public SimpleName GetMethodGroup ()
2105 return new SimpleName (RemoveGenericArity (Name), Arguments, loc);
2108 public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
2110 if (ec.IsInFieldInitializer)
2111 Report.Error (236, l,
2112 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2116 120, l, "`{0}': An object reference is required for the nonstatic field, method or property",
2120 public bool IdenticalNameAndTypeName (EmitContext ec, Expression resolved_to, Location loc)
2122 return resolved_to != null && resolved_to.Type != null &&
2123 resolved_to.Type.Name == Name &&
2124 (ec.DeclContainer.LookupNamespaceOrType (Name, loc, /* ignore_cs0104 = */ true) != null);
2127 public override Expression DoResolve (EmitContext ec)
2129 return SimpleNameResolve (ec, null, false);
2132 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
2134 return SimpleNameResolve (ec, right_side, false);
2138 public Expression DoResolve (EmitContext ec, bool intermediate)
2140 return SimpleNameResolve (ec, null, intermediate);
2143 static bool IsNestedChild (Type t, Type parent)
2145 while (parent != null) {
2146 if (TypeManager.IsNestedChildOf (t, TypeManager.DropGenericTypeArguments (parent)))
2149 parent = parent.BaseType;
2155 FullNamedExpression ResolveNested (IResolveContext ec, Type t)
2157 if (!TypeManager.IsGenericTypeDefinition (t) && !TypeManager.IsGenericType (t))
2160 DeclSpace ds = ec.DeclContainer;
2161 while (ds != null && !IsNestedChild (t, ds.TypeBuilder))
2167 Type[] gen_params = TypeManager.GetTypeArguments (t);
2169 int arg_count = Arguments != null ? Arguments.Count : 0;
2171 for (; (ds != null) && ds.IsGeneric; ds = ds.Parent) {
2172 if (arg_count + ds.CountTypeParameters == gen_params.Length) {
2173 TypeArguments new_args = new TypeArguments (loc);
2174 foreach (TypeParameter param in ds.TypeParameters)
2175 new_args.Add (new TypeParameterExpr (param, loc));
2177 if (Arguments != null)
2178 new_args.Add (Arguments);
2180 return new ConstructedType (t, new_args, loc);
2187 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2189 FullNamedExpression fne = ec.GenericDeclContainer.LookupGeneric (Name, loc);
2191 return fne.ResolveAsTypeStep (ec, silent);
2193 int errors = Report.Errors;
2194 fne = ec.DeclContainer.LookupNamespaceOrType (Name, loc, /*ignore_cs0104=*/ false);
2197 if (fne.Type == null)
2200 FullNamedExpression nested = ResolveNested (ec, fne.Type);
2202 return nested.ResolveAsTypeStep (ec, false);
2204 if (Arguments != null) {
2205 ConstructedType ct = new ConstructedType (fne, Arguments, loc);
2206 return ct.ResolveAsTypeStep (ec, false);
2212 if (silent || errors != Report.Errors)
2215 Error_TypeOrNamespaceNotFound (ec);
2219 protected virtual void Error_TypeOrNamespaceNotFound (IResolveContext ec)
2221 MemberCore mc = ec.DeclContainer.GetDefinition (Name);
2223 Error_UnexpectedKind (ec.DeclContainer, "type", GetMemberType (mc), loc);
2227 string ns = ec.DeclContainer.NamespaceEntry.NS.Name;
2228 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2229 foreach (Assembly a in RootNamespace.Global.Assemblies) {
2230 Type type = a.GetType (fullname);
2232 Report.SymbolRelatedToPreviousError (type);
2233 Expression.ErrorIsInaccesible (loc, TypeManager.CSharpName (type));
2238 Type t = ec.DeclContainer.LookupAnyGeneric (Name);
2240 Namespace.Error_InvalidNumberOfTypeArguments (t, loc);
2244 if (Arguments != null) {
2245 FullNamedExpression retval = ec.DeclContainer.LookupNamespaceOrType (SimpleName.RemoveGenericArity (Name), loc, true);
2246 if (retval != null) {
2247 Namespace.Error_TypeArgumentsCannotBeUsed (retval.Type, loc);
2252 NamespaceEntry.Error_NamespaceNotFound (loc, Name);
2255 // TODO: I am still not convinced about this. If someone else will need it
2256 // implement this as virtual property in MemberCore hierarchy
2257 public static string GetMemberType (MemberCore mc)
2263 if (mc is FieldBase)
2265 if (mc is MethodCore)
2267 if (mc is EnumMember)
2275 Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2281 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2287 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2294 /// 7.5.2: Simple Names.
2296 /// Local Variables and Parameters are handled at
2297 /// parse time, so they never occur as SimpleNames.
2299 /// The `intermediate' flag is used by MemberAccess only
2300 /// and it is used to inform us that it is ok for us to
2301 /// avoid the static check, because MemberAccess might end
2302 /// up resolving the Name as a Type name and the access as
2303 /// a static type access.
2305 /// ie: Type Type; .... { Type.GetType (""); }
2307 /// Type is both an instance variable and a Type; Type.GetType
2308 /// is the static method not an instance method of type.
2310 Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2312 Expression e = null;
2315 // Stage 1: Performed by the parser (binding to locals or parameters).
2317 Block current_block = ec.CurrentBlock;
2318 if (current_block != null){
2319 LocalInfo vi = current_block.GetLocalInfo (Name);
2321 if (Arguments != null) {
2322 Report.Error (307, loc,
2323 "The variable `{0}' cannot be used with type arguments",
2328 LocalVariableReference var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2329 if (right_side != null) {
2330 return var.ResolveLValue (ec, right_side, loc);
2332 ResolveFlags rf = ResolveFlags.VariableOrValue;
2334 rf |= ResolveFlags.DisableFlowAnalysis;
2335 return var.Resolve (ec, rf);
2339 ParameterReference pref = current_block.Toplevel.GetParameterReference (Name, loc);
2341 if (Arguments != null) {
2342 Report.Error (307, loc,
2343 "The variable `{0}' cannot be used with type arguments",
2348 if (right_side != null)
2349 return pref.ResolveLValue (ec, right_side, loc);
2351 return pref.Resolve (ec);
2354 Expression expr = current_block.Toplevel.GetTransparentIdentifier (Name);
2356 if (right_side != null)
2357 return expr.ResolveLValue (ec, right_side, loc);
2358 return expr.Resolve (ec);
2363 // Stage 2: Lookup members
2366 Type almost_matched_type = null;
2367 ArrayList almost_matched = null;
2368 for (DeclSpace lookup_ds = ec.DeclContainer; lookup_ds != null; lookup_ds = lookup_ds.Parent) {
2369 // either RootDeclSpace or GenericMethod
2370 if (lookup_ds.TypeBuilder == null)
2373 e = MemberLookup (ec.ContainerType, lookup_ds.TypeBuilder, Name, loc);
2375 if (e is PropertyExpr) {
2376 // since TypeManager.MemberLookup doesn't know if we're doing a lvalue access or not,
2377 // it doesn't know which accessor to check permissions against
2378 if (((PropertyExpr) e).IsAccessibleFrom (ec.ContainerType, right_side != null))
2380 } else if (e is EventExpr) {
2381 if (((EventExpr) e).IsAccessibleFrom (ec.ContainerType))
2389 if (almost_matched == null && almost_matched_members.Count > 0) {
2390 almost_matched_type = lookup_ds.TypeBuilder;
2391 almost_matched = (ArrayList) almost_matched_members.Clone ();
2396 if (almost_matched == null && almost_matched_members.Count > 0) {
2397 almost_matched_type = ec.ContainerType;
2398 almost_matched = (ArrayList) almost_matched_members.Clone ();
2400 e = ResolveAsTypeStep (ec, true);
2404 if (current_block != null) {
2405 IKnownVariable ikv = current_block.Explicit.GetKnownVariable (Name);
2407 LocalInfo li = ikv as LocalInfo;
2408 // Supress CS0219 warning
2412 Error_VariableIsUsedBeforeItIsDeclared (Name);
2417 if (almost_matched != null)
2418 almost_matched_members = almost_matched;
2419 if (almost_matched_type == null)
2420 almost_matched_type = ec.ContainerType;
2421 Error_MemberLookupFailed (ec.ContainerType, null, almost_matched_type, Name,
2422 ec.DeclContainer.Name, AllMemberTypes, AllBindingFlags);
2426 if (e is TypeExpr) {
2427 if (Arguments == null)
2430 ConstructedType ct = new ConstructedType (
2431 (FullNamedExpression) e, Arguments, loc);
2432 return ct.ResolveAsTypeStep (ec, false);
2435 if (e is MemberExpr) {
2436 MemberExpr me = (MemberExpr) e;
2439 if (me.IsInstance) {
2440 if (ec.IsStatic || ec.IsInFieldInitializer) {
2442 // Note that an MemberExpr can be both IsInstance and IsStatic.
2443 // An unresolved MethodGroupExpr can contain both kinds of methods
2444 // and each predicate is true if the MethodGroupExpr contains
2445 // at least one of that kind of method.
2449 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2450 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2455 // Pass the buck to MemberAccess and Invocation.
2457 left = EmptyExpression.Null;
2459 left = ec.GetThis (loc);
2462 left = new TypeExpression (ec.ContainerType, loc);
2465 me = me.ResolveMemberAccess (ec, left, loc, null);
2469 if (Arguments != null) {
2470 Arguments.Resolve (ec);
2471 me.SetTypeArguments (Arguments);
2474 if (!me.IsStatic && (me.InstanceExpression != null) &&
2475 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2476 me.InstanceExpression.Type != me.DeclaringType &&
2477 !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2478 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2479 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2480 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2484 return (right_side != null)
2485 ? me.DoResolveLValue (ec, right_side)
2486 : me.DoResolve (ec);
2492 public override void Emit (EmitContext ec)
2494 throw new InternalErrorException ("The resolve phase was not executed");
2497 public override string ToString ()
2502 public override string GetSignatureForError ()
2504 if (Arguments != null) {
2505 return TypeManager.RemoveGenericArity (Name) + "<" +
2506 Arguments.GetSignatureForError () + ">";
2512 protected override void CloneTo (CloneContext clonectx, Expression target)
2514 // CloneTo: Nothing, we do not keep any state on this expression
2519 /// Represents a namespace or a type. The name of the class was inspired by
2520 /// section 10.8.1 (Fully Qualified Names).
2522 public abstract class FullNamedExpression : Expression {
2523 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2528 public abstract string FullName {
2534 /// Expression that evaluates to a type
2536 public abstract class TypeExpr : FullNamedExpression {
2537 override public FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2539 TypeExpr t = DoResolveAsTypeStep (ec);
2543 eclass = ExprClass.Type;
2547 override public Expression DoResolve (EmitContext ec)
2549 return ResolveAsTypeTerminal (ec, false);
2552 override public void Emit (EmitContext ec)
2554 throw new Exception ("Should never be called");
2557 public virtual bool CheckAccessLevel (DeclSpace ds)
2559 return ds.CheckAccessLevel (Type);
2562 public virtual bool AsAccessible (DeclSpace ds)
2564 return ds.IsAccessibleAs (Type);
2567 public virtual bool IsClass {
2568 get { return Type.IsClass; }
2571 public virtual bool IsValueType {
2572 get { return Type.IsValueType; }
2575 public virtual bool IsInterface {
2576 get { return Type.IsInterface; }
2579 public virtual bool IsSealed {
2580 get { return Type.IsSealed; }
2583 public virtual bool CanInheritFrom ()
2585 if (Type == TypeManager.enum_type ||
2586 (Type == TypeManager.value_type && RootContext.StdLib) ||
2587 Type == TypeManager.multicast_delegate_type ||
2588 Type == TypeManager.delegate_type ||
2589 Type == TypeManager.array_type)
2595 protected abstract TypeExpr DoResolveAsTypeStep (IResolveContext ec);
2597 public abstract string Name {
2601 public override bool Equals (object obj)
2603 TypeExpr tobj = obj as TypeExpr;
2607 return Type == tobj.Type;
2610 public override int GetHashCode ()
2612 return Type.GetHashCode ();
2615 public override string ToString ()
2622 /// Fully resolved Expression that already evaluated to a type
2624 public class TypeExpression : TypeExpr {
2625 public TypeExpression (Type t, Location l)
2628 eclass = ExprClass.Type;
2632 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2637 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2642 public override string Name {
2643 get { return Type.ToString (); }
2646 public override string FullName {
2647 get { return Type.FullName; }
2652 /// Used to create types from a fully qualified name. These are just used
2653 /// by the parser to setup the core types. A TypeLookupExpression is always
2654 /// classified as a type.
2656 public sealed class TypeLookupExpression : TypeExpr {
2657 readonly string name;
2659 public TypeLookupExpression (string name)
2662 eclass = ExprClass.Type;
2665 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2667 // It's null for corlib compilation only
2669 return DoResolveAsTypeStep (ec);
2674 private class UnexpectedType
2678 // This performes recursive type lookup, providing support for generic types.
2679 // For example, given the type:
2681 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]]
2683 // The types will be checked in the following order:
2686 // System.Collections |
2687 // System.Collections.Generic |
2689 // System | recursive call 1 |
2690 // System.Int32 _| | main method call
2692 // System | recursive call 2 |
2693 // System.String _| |
2695 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]] _|
2697 private Type TypeLookup (IResolveContext ec, string name)
2702 FullNamedExpression resolved = null;
2704 Type recursive_type = null;
2705 while (index < name.Length) {
2706 if (name[index] == '[') {
2711 if (name[index] == '[')
2713 else if (name[index] == ']')
2715 } while (braces > 0);
2716 recursive_type = TypeLookup (ec, name.Substring (open + 1, index - open - 1));
2717 if (recursive_type == null || (recursive_type == typeof(UnexpectedType)))
2718 return recursive_type;
2721 if (name[index] == ',')
2723 else if ((name[index] == '.' && !done) || (index == name.Length && name[0] != '[')) {
2724 string substring = name.Substring(dot, index - dot);
2726 if (resolved == null)
2727 resolved = RootNamespace.Global.Lookup (ec.DeclContainer, substring, Location.Null);
2728 else if (resolved is Namespace)
2729 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
2730 else if (type != null)
2731 type = TypeManager.GetNestedType (type, substring);
2735 if (resolved == null)
2737 else if (type == null && resolved is TypeExpr)
2738 type = resolved.Type;
2745 if (name[0] != '[') {
2746 string substring = name.Substring(dot, index - dot);
2749 return TypeManager.GetNestedType (type, substring);
2751 if (resolved != null) {
2752 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
2753 if (resolved is TypeExpr)
2754 return resolved.Type;
2756 if (resolved == null)
2759 resolved.Error_UnexpectedKind (ec.DeclContainer, "type", loc);
2760 return typeof (UnexpectedType);
2766 return recursive_type;
2769 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2771 Type t = TypeLookup (ec, name);
2773 NamespaceEntry.Error_NamespaceNotFound (loc, name);
2776 if (t == typeof(UnexpectedType))
2782 public override string Name {
2783 get { return name; }
2786 public override string FullName {
2787 get { return name; }
2790 protected override void CloneTo (CloneContext clonectx, Expression target)
2792 // CloneTo: Nothing, we do not keep any state on this expression
2795 public override string GetSignatureForError ()
2798 return TypeManager.CSharpName (name);
2800 return base.GetSignatureForError ();
2805 /// Represents an "unbound generic type", ie. typeof (Foo<>).
2808 public class UnboundTypeExpression : TypeExpr
2812 public UnboundTypeExpression (MemberName name, Location l)
2818 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2821 if (name.Left != null) {
2822 Expression lexpr = name.Left.GetTypeExpression ();
2823 expr = new MemberAccess (lexpr, name.Basename);
2825 expr = new SimpleName (name.Basename, loc);
2828 FullNamedExpression fne = expr.ResolveAsTypeStep (ec, false);
2833 return new TypeExpression (type, loc);
2836 public override string Name {
2837 get { return name.FullName; }
2840 public override string FullName {
2841 get { return name.FullName; }
2845 public class TypeAliasExpression : TypeExpr {
2846 FullNamedExpression alias;
2851 public TypeAliasExpression (FullNamedExpression alias, TypeArguments args, Location l)
2857 eclass = ExprClass.Type;
2859 name = alias.FullName + "<" + args.ToString () + ">";
2861 name = alias.FullName;
2864 public override string Name {
2865 get { return alias.FullName; }
2868 public override string FullName {
2869 get { return name; }
2872 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2874 texpr = alias.ResolveAsTypeTerminal (ec, false);
2878 Type type = texpr.Type;
2879 int num_args = TypeManager.GetNumberOfTypeArguments (type);
2882 if (num_args == 0) {
2883 Report.Error (308, loc,
2884 "The non-generic type `{0}' cannot " +
2885 "be used with type arguments.",
2886 TypeManager.CSharpName (type));
2890 ConstructedType ctype = new ConstructedType (type, args, loc);
2891 return ctype.ResolveAsTypeTerminal (ec, false);
2892 } else if (num_args > 0) {
2893 Report.Error (305, loc,
2894 "Using the generic type `{0}' " +
2895 "requires {1} type arguments",
2896 TypeManager.CSharpName (type), num_args.ToString ());
2903 public override bool CheckAccessLevel (DeclSpace ds)
2905 return texpr.CheckAccessLevel (ds);
2908 public override bool AsAccessible (DeclSpace ds)
2910 return texpr.AsAccessible (ds);
2913 public override bool IsClass {
2914 get { return texpr.IsClass; }
2917 public override bool IsValueType {
2918 get { return texpr.IsValueType; }
2921 public override bool IsInterface {
2922 get { return texpr.IsInterface; }
2925 public override bool IsSealed {
2926 get { return texpr.IsSealed; }
2931 /// This class denotes an expression which evaluates to a member
2932 /// of a struct or a class.
2934 public abstract class MemberExpr : Expression
2936 protected bool is_base;
2939 /// The name of this member.
2941 public abstract string Name {
2946 // When base.member is used
2948 public bool IsBase {
2949 get { return is_base; }
2950 set { is_base = value; }
2954 /// Whether this is an instance member.
2956 public abstract bool IsInstance {
2961 /// Whether this is a static member.
2963 public abstract bool IsStatic {
2968 /// The type which declares this member.
2970 public abstract Type DeclaringType {
2975 /// The instance expression associated with this member, if it's a
2976 /// non-static member.
2978 public Expression InstanceExpression;
2980 public static void error176 (Location loc, string name)
2982 Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
2983 "with an instance reference, qualify it with a type name instead", name);
2986 // TODO: possible optimalization
2987 // Cache resolved constant result in FieldBuilder <-> expression map
2988 public virtual MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
2989 SimpleName original)
2993 // original == null || original.Resolve (...) ==> left
2996 if (left is TypeExpr) {
2997 left = left.ResolveAsTypeTerminal (ec, true);
3002 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3010 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3013 return ResolveExtensionMemberAccess (left);
3016 InstanceExpression = left;
3020 protected virtual MemberExpr ResolveExtensionMemberAccess (Expression left)
3022 error176 (loc, GetSignatureForError ());
3026 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3031 if (InstanceExpression == EmptyExpression.Null) {
3032 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3036 if (InstanceExpression.Type.IsValueType) {
3037 if (InstanceExpression is IMemoryLocation) {
3038 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
3040 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
3041 InstanceExpression.Emit (ec);
3043 t.AddressOf (ec, AddressOp.Store);
3046 InstanceExpression.Emit (ec);
3048 if (prepare_for_load)
3049 ec.ig.Emit (OpCodes.Dup);
3052 public virtual void SetTypeArguments (TypeArguments ta)
3054 // TODO: need to get correct member type
3055 Report.Error (307, loc, "The property `{0}' cannot be used with type arguments",
3056 GetSignatureForError ());
3061 /// Represents group of extension methods
3063 public class ExtensionMethodGroupExpr : MethodGroupExpr
3065 readonly NamespaceEntry namespace_entry;
3066 public Expression ExtensionExpression;
3067 Argument extension_argument;
3069 public ExtensionMethodGroupExpr (ArrayList list, NamespaceEntry n, Type extensionType, Location l)
3070 : base (list, extensionType, l)
3072 this.namespace_entry = n;
3075 public override bool IsStatic {
3076 get { return true; }
3079 public bool IsTopLevel {
3080 get { return namespace_entry == null; }
3083 public override void EmitArguments (EmitContext ec, ArrayList arguments)
3085 if (arguments == null)
3086 arguments = new ArrayList (1);
3087 arguments.Insert (0, extension_argument);
3088 base.EmitArguments (ec, arguments);
3091 public override void EmitCall (EmitContext ec, ArrayList arguments)
3093 if (arguments == null)
3094 arguments = new ArrayList (1);
3095 arguments.Insert (0, extension_argument);
3096 base.EmitCall (ec, arguments);
3099 public override MethodGroupExpr OverloadResolve (EmitContext ec, ref ArrayList arguments, bool may_fail, Location loc)
3101 if (arguments == null)
3102 arguments = new ArrayList (1);
3104 arguments.Insert (0, new Argument (ExtensionExpression));
3105 MethodGroupExpr mg = ResolveOverloadExtensions (ec, arguments, namespace_entry, loc);
3107 // Store resolved argument and restore original arguments
3109 ((ExtensionMethodGroupExpr)mg).extension_argument = (Argument)arguments [0];
3110 arguments.RemoveAt (0);
3115 MethodGroupExpr ResolveOverloadExtensions (EmitContext ec, ArrayList arguments, NamespaceEntry ns, Location loc)
3117 // Use normal resolve rules
3118 MethodGroupExpr mg = base.OverloadResolve (ec, ref arguments, ns != null, loc);
3126 ExtensionMethodGroupExpr e = ns.LookupExtensionMethod (type, null, Name);
3128 return base.OverloadResolve (ec, ref arguments, false, loc);
3130 e.ExtensionExpression = ExtensionExpression;
3131 return e.ResolveOverloadExtensions (ec, arguments, e.namespace_entry, loc);
3136 /// MethodGroupExpr represents a group of method candidates which
3137 /// can be resolved to the best method overload
3139 public class MethodGroupExpr : MemberExpr
3141 public interface IErrorHandler
3143 bool NoExactMatch (EmitContext ec, MethodBase method);
3146 public IErrorHandler CustomErrorHandler;
3147 public MethodBase [] Methods;
3148 MethodBase best_candidate;
3149 // TODO: make private
3150 public TypeArguments type_arguments;
3151 bool identical_type_name;
3154 public MethodGroupExpr (MemberInfo [] mi, Type type, Location l)
3157 Methods = new MethodBase [mi.Length];
3158 mi.CopyTo (Methods, 0);
3161 public MethodGroupExpr (ArrayList list, Type type, Location l)
3165 Methods = (MethodBase[])list.ToArray (typeof (MethodBase));
3167 foreach (MemberInfo m in list){
3168 if (!(m is MethodBase)){
3169 Console.WriteLine ("Name " + m.Name);
3170 Console.WriteLine ("Found a: " + m.GetType ().FullName);
3179 protected MethodGroupExpr (Type type, Location loc)
3182 eclass = ExprClass.MethodGroup;
3186 public override Type DeclaringType {
3189 // We assume that the top-level type is in the end
3191 return Methods [Methods.Length - 1].DeclaringType;
3192 //return Methods [0].DeclaringType;
3196 public Type DelegateType {
3198 delegate_type = value;
3202 public bool IdenticalTypeName {
3204 return identical_type_name;
3208 identical_type_name = value;
3212 public override string GetSignatureForError ()
3214 if (best_candidate != null)
3215 return TypeManager.CSharpSignature (best_candidate);
3217 return TypeManager.CSharpSignature (Methods [0]);
3220 public override string Name {
3222 return Methods [0].Name;
3226 public override bool IsInstance {
3228 if (best_candidate != null)
3229 return !best_candidate.IsStatic;
3231 foreach (MethodBase mb in Methods)
3239 public override bool IsStatic {
3241 if (best_candidate != null)
3242 return best_candidate.IsStatic;
3244 foreach (MethodBase mb in Methods)
3252 public static explicit operator ConstructorInfo (MethodGroupExpr mg)
3254 return (ConstructorInfo)mg.best_candidate;
3257 public static explicit operator MethodInfo (MethodGroupExpr mg)
3259 return (MethodInfo)mg.best_candidate;
3263 // Determines "better conversion" as specified in 7.4.3
3264 // Returns : 1 if a->p is better,
3265 // 2 if a->q is better,
3266 // 0 if neither is better
3268 static int BetterConversion (EmitContext ec, Argument a, Type p, Type q)
3270 if (p == null || q == null)
3271 throw new InternalErrorException ("BetterConversion Got a null conversion");
3273 Expression argument_expr = a.Expr;
3274 if (argument_expr is NullLiteral) {
3276 // If the argument is null and one of the types to compare is 'object' and
3277 // the other is a reference type, we prefer the other.
3279 // This follows from the usual rules:
3280 // * There is an implicit conversion from 'null' to type 'object'
3281 // * There is an implicit conversion from 'null' to any reference type
3282 // * There is an implicit conversion from any reference type to type 'object'
3283 // * There is no implicit conversion from type 'object' to other reference types
3284 // => Conversion of 'null' to a reference type is better than conversion to 'object'
3286 // FIXME: This probably isn't necessary, since the type of a NullLiteral is the
3287 // null type. I think it used to be 'object' and thus needed a special
3288 // case to avoid the immediately following two checks.
3290 if (!p.IsValueType && q == TypeManager.object_type)
3292 if (!q.IsValueType && p == TypeManager.object_type)
3296 Type argument_type = TypeManager.TypeToCoreType (a.Type);
3297 if (argument_type == TypeManager.anonymous_method_type && RootContext.Version > LanguageVersion.ISO_2) {
3299 // Uwrap delegate from Expression<T>
3301 if (TypeManager.DropGenericTypeArguments (p) == TypeManager.expression_type) {
3302 p = TypeManager.GetTypeArguments (p) [0];
3303 q = TypeManager.GetTypeArguments (q) [0];
3305 p = Delegate.GetInvokeMethod (null, p).ReturnType;
3306 q = Delegate.GetInvokeMethod (null, q).ReturnType;
3308 if (argument_type == p)
3311 if (argument_type == q)
3315 Expression p_tmp = new EmptyExpression (p);
3316 Expression q_tmp = new EmptyExpression (q);
3318 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3319 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3321 if (p_to_q && !q_to_p)
3324 if (q_to_p && !p_to_q)
3327 if (p == TypeManager.sbyte_type)
3328 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3329 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3331 if (q == TypeManager.sbyte_type)
3332 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3333 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3336 if (p == TypeManager.short_type)
3337 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3338 q == TypeManager.uint64_type)
3340 if (q == TypeManager.short_type)
3341 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3342 p == TypeManager.uint64_type)
3345 if (p == TypeManager.int32_type)
3346 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3348 if (q == TypeManager.int32_type)
3349 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3352 if (p == TypeManager.int64_type)
3353 if (q == TypeManager.uint64_type)
3355 if (q == TypeManager.int64_type)
3356 if (p == TypeManager.uint64_type)
3363 /// Determines "Better function" between candidate
3364 /// and the current best match
3367 /// Returns a boolean indicating :
3368 /// false if candidate ain't better
3369 /// true if candidate is better than the current best match
3371 static bool BetterFunction (EmitContext ec, ArrayList args, int argument_count,
3372 MethodBase candidate, bool candidate_params,
3373 MethodBase best, bool best_params)
3375 ParameterData candidate_pd = TypeManager.GetParameterData (candidate);
3376 ParameterData best_pd = TypeManager.GetParameterData (best);
3378 bool better_at_least_one = false;
3380 for (int j = 0, c_idx = 0, b_idx = 0; j < argument_count; ++j, ++c_idx, ++b_idx)
3382 Argument a = (Argument) args [j];
3384 Type ct = TypeManager.TypeToCoreType (candidate_pd.ParameterType (c_idx));
3385 Type bt = TypeManager.TypeToCoreType (best_pd.ParameterType (b_idx));
3387 if (candidate_params && candidate_pd.ParameterModifier (c_idx) == Parameter.Modifier.PARAMS)
3389 ct = TypeManager.GetElementType (ct);
3393 if (best_params && best_pd.ParameterModifier (b_idx) == Parameter.Modifier.PARAMS)
3395 bt = TypeManager.GetElementType (bt);
3403 int result = BetterConversion (ec, a, ct, bt);
3405 // for each argument, the conversion to 'ct' should be no worse than
3406 // the conversion to 'bt'.
3410 // for at least one argument, the conversion to 'ct' should be better than
3411 // the conversion to 'bt'.
3413 better_at_least_one = true;
3416 if (better_at_least_one)
3420 // This handles the case
3422 // Add (float f1, float f2, float f3);
3423 // Add (params decimal [] foo);
3425 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3426 // first candidate would've chosen as better.
3432 // The two methods have equal parameter types. Now apply tie-breaking rules
3434 if (TypeManager.IsGenericMethod (best) && !TypeManager.IsGenericMethod (candidate))
3436 if (!TypeManager.IsGenericMethod (best) && TypeManager.IsGenericMethod (candidate))
3440 // This handles the following cases:
3442 // Trim () is better than Trim (params char[] chars)
3443 // Concat (string s1, string s2, string s3) is better than
3444 // Concat (string s1, params string [] srest)
3445 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3447 if (!candidate_params && best_params)
3449 if (candidate_params && !best_params)
3452 int candidate_param_count = candidate_pd.Count;
3453 int best_param_count = best_pd.Count;
3455 if (candidate_param_count != best_param_count)
3456 // can only happen if (candidate_params && best_params)
3457 return candidate_param_count > best_param_count;
3460 // now, both methods have the same number of parameters, and the parameters have the same types
3461 // Pick the "more specific" signature
3464 MethodBase orig_candidate = TypeManager.DropGenericMethodArguments (candidate);
3465 MethodBase orig_best = TypeManager.DropGenericMethodArguments (best);
3467 ParameterData orig_candidate_pd = TypeManager.GetParameterData (orig_candidate);
3468 ParameterData orig_best_pd = TypeManager.GetParameterData (orig_best);
3470 bool specific_at_least_once = false;
3471 for (int j = 0; j < candidate_param_count; ++j)
3473 Type ct = TypeManager.TypeToCoreType (orig_candidate_pd.ParameterType (j));
3474 Type bt = TypeManager.TypeToCoreType (orig_best_pd.ParameterType (j));
3477 Type specific = MoreSpecific (ct, bt);
3481 specific_at_least_once = true;
3484 if (specific_at_least_once)
3487 // FIXME: handle lifted operators
3493 protected override MemberExpr ResolveExtensionMemberAccess (Expression left)
3496 return base.ResolveExtensionMemberAccess (left);
3499 // When left side is an expression and at least one candidate method is
3500 // static, it can be extension method
3502 InstanceExpression = left;
3506 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3507 SimpleName original)
3509 if (!(left is TypeExpr) &&
3510 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3511 IdenticalTypeName = true;
3513 return base.ResolveMemberAccess (ec, left, loc, original);
3516 public override Expression CreateExpressionTree (EmitContext ec)
3518 return new Cast (new TypeExpression (typeof (MethodInfo), loc),
3519 new TypeOfMethod ((MethodInfo)best_candidate, loc));
3522 override public Expression DoResolve (EmitContext ec)
3524 if (InstanceExpression != null) {
3525 InstanceExpression = InstanceExpression.DoResolve (ec);
3526 if (InstanceExpression == null)
3533 public void ReportUsageError ()
3535 Report.Error (654, loc, "Method `" + DeclaringType + "." +
3536 Name + "()' is referenced without parentheses");
3539 override public void Emit (EmitContext ec)
3541 ReportUsageError ();
3544 public virtual void EmitArguments (EmitContext ec, ArrayList arguments)
3546 Invocation.EmitArguments (ec, arguments, false, null);
3549 public virtual void EmitCall (EmitContext ec, ArrayList arguments)
3551 Invocation.EmitCall (ec, IsBase, InstanceExpression, best_candidate, arguments, loc);
3554 protected virtual void Error_InvalidArguments (EmitContext ec, Location loc, int idx, MethodBase method,
3555 Argument a, ParameterData expected_par, Type paramType)
3557 if (a is CollectionElementInitializer.ElementInitializerArgument) {
3558 Report.SymbolRelatedToPreviousError (method);
3559 if ((expected_par.ParameterModifier (idx) & Parameter.Modifier.ISBYREF) != 0) {
3560 Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
3561 TypeManager.CSharpSignature (method));
3564 Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
3565 TypeManager.CSharpSignature (method));
3566 } else if (delegate_type == null) {
3567 Report.SymbolRelatedToPreviousError (method);
3568 Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
3569 TypeManager.CSharpSignature (method));
3571 Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
3572 TypeManager.CSharpName (delegate_type));
3574 Parameter.Modifier mod = expected_par.ParameterModifier (idx);
3576 string index = (idx + 1).ToString ();
3577 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
3578 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
3579 if ((mod & Parameter.Modifier.ISBYREF) == 0)
3580 Report.Error (1615, loc, "Argument `{0}' should not be passed with the `{1}' keyword",
3581 index, Parameter.GetModifierSignature (a.Modifier));
3583 Report.Error (1620, loc, "Argument `{0}' must be passed with the `{1}' keyword",
3584 index, Parameter.GetModifierSignature (mod));
3586 string p1 = a.GetSignatureForError ();
3587 string p2 = TypeManager.CSharpName (paramType);
3590 Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
3591 Report.SymbolRelatedToPreviousError (a.Expr.Type);
3592 Report.SymbolRelatedToPreviousError (paramType);
3594 Report.Error (1503, loc, "Argument {0}: Cannot convert type `{1}' to `{2}'", index, p1, p2);
3598 protected virtual int GetApplicableParametersCount (MethodBase method, ParameterData parameters)
3600 return parameters.Count;
3603 public static bool IsAncestralType (Type first_type, Type second_type)
3605 return first_type != second_type &&
3606 (TypeManager.IsSubclassOf (second_type, first_type) ||
3607 TypeManager.ImplementsInterface (second_type, first_type));
3611 /// Determines if the candidate method is applicable (section 14.4.2.1)
3612 /// to the given set of arguments
3613 /// A return value rates candidate method compatibility,
3614 /// 0 = the best, int.MaxValue = the worst
3616 public int IsApplicable (EmitContext ec,
3617 ArrayList arguments, int arg_count, ref MethodBase method, ref bool params_expanded_form)
3619 MethodBase candidate = method;
3621 ParameterData pd = TypeManager.GetParameterData (candidate);
3622 int param_count = GetApplicableParametersCount (candidate, pd);
3624 if (arg_count != param_count) {
3626 return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
3627 if (arg_count < param_count - 1)
3628 return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
3633 // 1. Handle generic method using type arguments when specified or type inference
3635 if (TypeManager.IsGenericMethod (candidate)) {
3636 if (type_arguments != null) {
3637 Type [] g_args = candidate.GetGenericArguments ();
3638 if (g_args.Length != type_arguments.Count)
3639 return int.MaxValue - 20000 + Math.Abs (type_arguments.Count - g_args.Length);
3641 // TODO: Don't create new method, create Parameters only
3642 method = ((MethodInfo) candidate).MakeGenericMethod (type_arguments.Arguments);
3644 pd = TypeManager.GetParameterData (candidate);
3646 int score = TypeManager.InferTypeArguments (ec, arguments, ref candidate);
3648 return score - 20000;
3650 if (TypeManager.IsGenericMethodDefinition (candidate))
3651 throw new InternalErrorException ("A generic method `{0}' definition took part in overload resolution",
3652 TypeManager.CSharpSignature (candidate));
3654 pd = TypeManager.GetParameterData (candidate);
3657 if (type_arguments != null)
3658 return int.MaxValue - 15000;
3663 // 2. Each argument has to be implicitly convertible to method parameter
3666 Parameter.Modifier p_mod = 0;
3668 for (int i = 0; i < arg_count; i++) {
3669 Argument a = (Argument) arguments [i];
3670 Parameter.Modifier a_mod = a.Modifier &
3671 ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3673 if (p_mod != Parameter.Modifier.PARAMS) {
3674 p_mod = pd.ParameterModifier (i) & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3676 if (p_mod == Parameter.Modifier.ARGLIST) {
3677 if (a.Type == TypeManager.runtime_argument_handle_type)
3683 pt = pd.ParameterType (i);
3685 params_expanded_form = true;
3689 if (!params_expanded_form)
3690 score = IsArgumentCompatible (ec, a_mod, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
3692 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0) {
3693 // It can be applicable in expanded form
3694 score = IsArgumentCompatible (ec, a_mod, a, 0, pt.GetElementType ());
3696 params_expanded_form = true;
3700 if (params_expanded_form)
3702 return (arg_count - i) * 2 + score;
3706 if (arg_count != param_count)
3707 params_expanded_form = true;
3712 int IsArgumentCompatible (EmitContext ec, Parameter.Modifier arg_mod, Argument argument, Parameter.Modifier param_mod, Type parameter)
3715 // Types have to be identical when ref or out modifer is used
3717 if (arg_mod != 0 || param_mod != 0) {
3718 if (TypeManager.HasElementType (parameter))
3719 parameter = parameter.GetElementType ();
3721 Type a_type = argument.Type;
3722 if (TypeManager.HasElementType (a_type))
3723 a_type = a_type.GetElementType ();
3725 if (a_type != parameter)
3731 // FIXME: Kill this abomination (EmitContext.TempEc)
3732 EmitContext prevec = EmitContext.TempEc;
3733 EmitContext.TempEc = ec;
3735 if (delegate_type != null ?
3736 !Delegate.IsTypeCovariant (argument.Expr, parameter) :
3737 !Convert.ImplicitConversionExists (ec, argument.Expr, parameter))
3740 if (arg_mod != param_mod)
3744 EmitContext.TempEc = prevec;
3750 public static bool IsOverride (MethodBase cand_method, MethodBase base_method)
3752 if (!IsAncestralType (base_method.DeclaringType, cand_method.DeclaringType))
3755 ParameterData cand_pd = TypeManager.GetParameterData (cand_method);
3756 ParameterData base_pd = TypeManager.GetParameterData (base_method);
3758 if (cand_pd.Count != base_pd.Count)
3761 for (int j = 0; j < cand_pd.Count; ++j)
3763 Parameter.Modifier cm = cand_pd.ParameterModifier (j);
3764 Parameter.Modifier bm = base_pd.ParameterModifier (j);
3765 Type ct = TypeManager.TypeToCoreType (cand_pd.ParameterType (j));
3766 Type bt = TypeManager.TypeToCoreType (base_pd.ParameterType (j));
3768 if (cm != bm || ct != bt)
3775 public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2, Location loc)
3777 MemberInfo [] miset;
3778 MethodGroupExpr union;
3783 return (MethodGroupExpr) mg2;
3786 return (MethodGroupExpr) mg1;
3789 MethodGroupExpr left_set = null, right_set = null;
3790 int length1 = 0, length2 = 0;
3792 left_set = (MethodGroupExpr) mg1;
3793 length1 = left_set.Methods.Length;
3795 right_set = (MethodGroupExpr) mg2;
3796 length2 = right_set.Methods.Length;
3798 ArrayList common = new ArrayList ();
3800 foreach (MethodBase r in right_set.Methods){
3801 if (TypeManager.ArrayContainsMethod (left_set.Methods, r))
3805 miset = new MemberInfo [length1 + length2 - common.Count];
3806 left_set.Methods.CopyTo (miset, 0);
3810 foreach (MethodBase r in right_set.Methods) {
3811 if (!common.Contains (r))
3815 union = new MethodGroupExpr (miset, mg1.Type, loc);
3820 static Type MoreSpecific (Type p, Type q)
3822 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
3824 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
3827 if (TypeManager.HasElementType (p))
3829 Type pe = TypeManager.GetElementType (p);
3830 Type qe = TypeManager.GetElementType (q);
3831 Type specific = MoreSpecific (pe, qe);
3837 else if (TypeManager.IsGenericType (p))
3839 Type[] pargs = TypeManager.GetTypeArguments (p);
3840 Type[] qargs = TypeManager.GetTypeArguments (q);
3842 bool p_specific_at_least_once = false;
3843 bool q_specific_at_least_once = false;
3845 for (int i = 0; i < pargs.Length; i++)
3847 Type specific = MoreSpecific (pargs [i], qargs [i]);
3848 if (specific == pargs [i])
3849 p_specific_at_least_once = true;
3850 if (specific == qargs [i])
3851 q_specific_at_least_once = true;
3854 if (p_specific_at_least_once && !q_specific_at_least_once)
3856 if (!p_specific_at_least_once && q_specific_at_least_once)
3864 /// Find the Applicable Function Members (7.4.2.1)
3866 /// me: Method Group expression with the members to select.
3867 /// it might contain constructors or methods (or anything
3868 /// that maps to a method).
3870 /// Arguments: ArrayList containing resolved Argument objects.
3872 /// loc: The location if we want an error to be reported, or a Null
3873 /// location for "probing" purposes.
3875 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3876 /// that is the best match of me on Arguments.
3879 public virtual MethodGroupExpr OverloadResolve (EmitContext ec, ref ArrayList Arguments,
3880 bool may_fail, Location loc)
3882 bool method_params = false;
3883 Type applicable_type = null;
3885 ArrayList candidates = new ArrayList (2);
3886 ArrayList candidate_overrides = null;
3889 // Used to keep a map between the candidate
3890 // and whether it is being considered in its
3891 // normal or expanded form
3893 // false is normal form, true is expanded form
3895 Hashtable candidate_to_form = null;
3897 if (Arguments != null)
3898 arg_count = Arguments.Count;
3900 if (RootContext.Version == LanguageVersion.ISO_1 && Name == "Invoke" && TypeManager.IsDelegateType (DeclaringType)) {
3902 Report.Error (1533, loc, "Invoke cannot be called directly on a delegate");
3906 int nmethods = Methods.Length;
3910 // Methods marked 'override' don't take part in 'applicable_type'
3911 // computation, nor in the actual overload resolution.
3912 // However, they still need to be emitted instead of a base virtual method.
3913 // So, we salt them away into the 'candidate_overrides' array.
3915 // In case of reflected methods, we replace each overriding method with
3916 // its corresponding base virtual method. This is to improve compatibility
3917 // with non-C# libraries which change the visibility of overrides (#75636)
3920 for (int i = 0; i < Methods.Length; ++i) {
3921 MethodBase m = Methods [i];
3922 if (TypeManager.IsOverride (m)) {
3923 if (candidate_overrides == null)
3924 candidate_overrides = new ArrayList ();
3925 candidate_overrides.Add (m);
3926 m = TypeManager.TryGetBaseDefinition (m);
3935 // Enable message recording, it's used mainly by lambda expressions
3937 Report.IMessageRecorder msg_recorder = new Report.MessageRecorder ();
3938 Report.IMessageRecorder prev_recorder = Report.SetMessageRecorder (msg_recorder);
3941 // First we construct the set of applicable methods
3943 bool is_sorted = true;
3944 int best_candidate_rate = int.MaxValue;
3945 for (int i = 0; i < nmethods; i++) {
3946 Type decl_type = Methods [i].DeclaringType;
3949 // If we have already found an applicable method
3950 // we eliminate all base types (Section 14.5.5.1)
3952 if (applicable_type != null && IsAncestralType (decl_type, applicable_type))
3956 // Check if candidate is applicable (section 14.4.2.1)
3958 bool params_expanded_form = false;
3959 int candidate_rate = IsApplicable (ec, Arguments, arg_count, ref Methods [i], ref params_expanded_form);
3961 if (candidate_rate < best_candidate_rate) {
3962 best_candidate_rate = candidate_rate;
3963 best_candidate = Methods [i];
3966 if (params_expanded_form) {
3967 if (candidate_to_form == null)
3968 candidate_to_form = new PtrHashtable ();
3969 MethodBase candidate = Methods [i];
3970 candidate_to_form [candidate] = candidate;
3973 if (candidate_rate != 0) {
3974 if (msg_recorder != null)
3975 msg_recorder.EndSession ();
3979 msg_recorder = null;
3980 candidates.Add (Methods [i]);
3982 if (applicable_type == null)
3983 applicable_type = decl_type;
3984 else if (applicable_type != decl_type) {
3986 if (IsAncestralType (applicable_type, decl_type))
3987 applicable_type = decl_type;
3991 Report.SetMessageRecorder (prev_recorder);
3992 if (msg_recorder != null && msg_recorder.PrintMessages ())
3995 int candidate_top = candidates.Count;
3997 if (applicable_type == null) {
3999 // When we found a top level method which does not match and it's
4000 // not an extension method. We start extension methods lookup from here
4002 if (InstanceExpression != null) {
4003 ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (type, Name);
4004 if (ex_method_lookup != null) {
4005 ex_method_lookup.ExtensionExpression = InstanceExpression;
4006 ex_method_lookup.SetTypeArguments (type_arguments);
4007 return ex_method_lookup.OverloadResolve (ec, ref Arguments, may_fail, loc);
4015 // Okay so we have failed to find exact match so we
4016 // return error info about the closest match
4018 if (best_candidate != null) {
4019 if (CustomErrorHandler != null) {
4020 if (CustomErrorHandler.NoExactMatch (ec, best_candidate))
4024 ParameterData pd = TypeManager.GetParameterData (best_candidate);
4025 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4026 if (arg_count == pd.Count || pd.HasParams) {
4027 if (TypeManager.IsGenericMethodDefinition (best_candidate)) {
4028 if (type_arguments == null) {
4029 Report.Error (411, loc,
4030 "The type arguments for method `{0}' cannot be inferred from " +
4031 "the usage. Try specifying the type arguments explicitly",
4032 TypeManager.CSharpSignature (best_candidate));
4036 Type [] g_args = TypeManager.GetGenericArguments (best_candidate);
4037 if (type_arguments.Count != g_args.Length) {
4038 Report.SymbolRelatedToPreviousError (best_candidate);
4039 Report.Error (305, loc, "Using the generic method `{0}' requires `{1}' type argument(s)",
4040 TypeManager.CSharpSignature (best_candidate),
4041 g_args.Length.ToString ());
4045 if (type_arguments != null && !TypeManager.IsGenericMethod (best_candidate)) {
4046 Namespace.Error_TypeArgumentsCannotBeUsed (best_candidate, loc);
4051 if (VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate, cand_params, may_fail, loc))
4052 throw new InternalErrorException ("Overload verification expected failure");
4057 if (almost_matched_members.Count != 0) {
4058 Error_MemberLookupFailed (ec.ContainerType, type, type, ".ctor",
4059 null, MemberTypes.Constructor, AllBindingFlags);
4064 // We failed to find any method with correct argument count
4066 if (Name == ConstructorInfo.ConstructorName) {
4067 Report.SymbolRelatedToPreviousError (type);
4068 Report.Error (1729, loc,
4069 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4070 TypeManager.CSharpName (type), arg_count);
4072 Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4073 Name, arg_count.ToString ());
4081 // At this point, applicable_type is _one_ of the most derived types
4082 // in the set of types containing the methods in this MethodGroup.
4083 // Filter the candidates so that they only contain methods from the
4084 // most derived types.
4087 int finalized = 0; // Number of finalized candidates
4090 // Invariant: applicable_type is a most derived type
4092 // We'll try to complete Section 14.5.5.1 for 'applicable_type' by
4093 // eliminating all it's base types. At the same time, we'll also move
4094 // every unrelated type to the end of the array, and pick the next
4095 // 'applicable_type'.
4097 Type next_applicable_type = null;
4098 int j = finalized; // where to put the next finalized candidate
4099 int k = finalized; // where to put the next undiscarded candidate
4100 for (int i = finalized; i < candidate_top; ++i) {
4101 MethodBase candidate = (MethodBase) candidates [i];
4102 Type decl_type = candidate.DeclaringType;
4104 if (decl_type == applicable_type) {
4105 candidates [k++] = candidates [j];
4106 candidates [j++] = candidates [i];
4110 if (IsAncestralType (decl_type, applicable_type))
4113 if (next_applicable_type != null &&
4114 IsAncestralType (decl_type, next_applicable_type))
4117 candidates [k++] = candidates [i];
4119 if (next_applicable_type == null ||
4120 IsAncestralType (next_applicable_type, decl_type))
4121 next_applicable_type = decl_type;
4124 applicable_type = next_applicable_type;
4127 } while (applicable_type != null);
4131 // Now we actually find the best method
4134 best_candidate = (MethodBase) candidates [0];
4135 if (delegate_type == null)
4136 method_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4138 for (int ix = 1; ix < candidate_top; ix++) {
4139 MethodBase candidate = (MethodBase) candidates [ix];
4141 if (candidate == best_candidate)
4144 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4146 if (BetterFunction (ec, Arguments, arg_count,
4147 candidate, cand_params,
4148 best_candidate, method_params)) {
4149 best_candidate = candidate;
4150 method_params = cand_params;
4154 // Now check that there are no ambiguities i.e the selected method
4155 // should be better than all the others
4157 MethodBase ambiguous = null;
4158 for (int ix = 0; ix < candidate_top; ix++) {
4159 MethodBase candidate = (MethodBase) candidates [ix];
4161 if (candidate == best_candidate)
4164 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4165 if (!BetterFunction (ec, Arguments, arg_count,
4166 best_candidate, method_params,
4167 candidate, cand_params))
4170 Report.SymbolRelatedToPreviousError (candidate);
4171 ambiguous = candidate;
4175 if (ambiguous != null) {
4176 Report.SymbolRelatedToPreviousError (best_candidate);
4177 Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4178 TypeManager.CSharpSignature (ambiguous), TypeManager.CSharpSignature (best_candidate));
4183 // If the method is a virtual function, pick an override closer to the LHS type.
4185 if (!IsBase && best_candidate.IsVirtual) {
4186 if (TypeManager.IsOverride (best_candidate))
4187 throw new InternalErrorException (
4188 "Should not happen. An 'override' method took part in overload resolution: " + best_candidate);
4190 if (candidate_overrides != null) {
4191 Type[] gen_args = null;
4192 bool gen_override = false;
4193 if (TypeManager.IsGenericMethod (best_candidate))
4194 gen_args = TypeManager.GetGenericArguments (best_candidate);
4196 foreach (MethodBase candidate in candidate_overrides) {
4197 if (TypeManager.IsGenericMethod (candidate)) {
4198 if (gen_args == null)
4201 if (gen_args.Length != TypeManager.GetGenericArguments (candidate).Length)
4204 if (gen_args != null)
4208 if (IsOverride (candidate, best_candidate)) {
4209 gen_override = true;
4210 best_candidate = candidate;
4214 if (gen_override && gen_args != null) {
4216 best_candidate = ((MethodInfo) best_candidate).MakeGenericMethod (gen_args);
4223 // And now check if the arguments are all
4224 // compatible, perform conversions if
4225 // necessary etc. and return if everything is
4228 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate,
4229 method_params, may_fail, loc))
4232 if (best_candidate == null)
4235 MethodBase the_method = TypeManager.DropGenericMethodArguments (best_candidate);
4237 if (the_method.IsGenericMethodDefinition &&
4238 !ConstraintChecker.CheckConstraints (ec, the_method, best_candidate, loc))
4242 IMethodData data = TypeManager.GetMethod (the_method);
4244 data.SetMemberIsUsed ();
4249 public override void SetTypeArguments (TypeArguments ta)
4251 type_arguments = ta;
4254 public bool VerifyArgumentsCompat (EmitContext ec, ref ArrayList arguments,
4255 int arg_count, MethodBase method,
4256 bool chose_params_expanded,
4257 bool may_fail, Location loc)
4259 ParameterData pd = TypeManager.GetParameterData (method);
4261 int errors = Report.Errors;
4262 Parameter.Modifier p_mod = 0;
4264 int a_idx = 0, a_pos = 0;
4266 ArrayList params_initializers = null;
4268 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4269 a = (Argument) arguments [a_idx];
4270 if (p_mod != Parameter.Modifier.PARAMS) {
4271 p_mod = pd.ParameterModifier (a_idx);
4272 pt = pd.ParameterType (a_idx);
4274 if (p_mod == Parameter.Modifier.ARGLIST) {
4275 if (a.Type != TypeManager.runtime_argument_handle_type)
4280 if (pt.IsPointer && !ec.InUnsafe) {
4287 if (p_mod == Parameter.Modifier.PARAMS) {
4288 if (chose_params_expanded) {
4289 params_initializers = new ArrayList (arg_count - a_idx);
4290 pt = TypeManager.GetElementType (pt);
4292 } else if (p_mod != 0) {
4293 pt = TypeManager.GetElementType (pt);
4298 // Types have to be identical when ref or out modifer is used
4300 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4301 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4304 if (!TypeManager.IsEqual (a.Expr.Type, pt))
4311 if (TypeManager.IsEqual (a.Type, pt)) {
4314 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4320 // Convert params arguments to an array initializer
4322 if (params_initializers != null) {
4323 params_initializers.Add (conv);
4324 arguments.RemoveAt (a_idx--);
4329 // Update the argument with the implicit conversion
4334 // Fill not provided arguments required by params modifier
4336 if (params_initializers == null && pd.HasParams && arg_count < pd.Count) {
4337 if (arguments == null)
4338 arguments = new ArrayList (1);
4340 pt = pd.Types [GetApplicableParametersCount (method, pd) - 1];
4341 pt = TypeManager.GetElementType (pt);
4342 params_initializers = new ArrayList (0);
4345 if (a_idx == arg_count) {
4347 // Append an array argument with all params arguments
4349 if (params_initializers != null) {
4350 arguments.Add (new Argument (
4351 new ArrayCreation (new TypeExpression (pt, loc), "[]",
4352 params_initializers, loc).Resolve (ec)));
4357 if (!may_fail && Report.Errors == errors) {
4358 if (CustomErrorHandler != null)
4359 CustomErrorHandler.NoExactMatch (ec, best_candidate);
4361 Error_InvalidArguments (ec, loc, a_pos, method, a, pd, pt);
4367 public class ConstantExpr : MemberExpr
4371 public ConstantExpr (FieldInfo constant, Location loc)
4373 this.constant = constant;
4377 public override string Name {
4378 get { throw new NotImplementedException (); }
4381 public override bool IsInstance {
4382 get { return !IsStatic; }
4385 public override bool IsStatic {
4386 get { return constant.IsStatic; }
4389 public override Type DeclaringType {
4390 get { return constant.DeclaringType; }
4393 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc, SimpleName original)
4395 constant = TypeManager.GetGenericFieldDefinition (constant);
4397 IConstant ic = TypeManager.GetConstant (constant);
4399 if (constant.IsLiteral) {
4400 ic = new ExternalConstant (constant);
4402 ic = ExternalConstant.CreateDecimal (constant);
4403 // HACK: decimal field was not resolved as constant
4405 return new FieldExpr (constant, loc).ResolveMemberAccess (ec, left, loc, original);
4407 TypeManager.RegisterConstant (constant, ic);
4410 return base.ResolveMemberAccess (ec, left, loc, original);
4413 public override Expression DoResolve (EmitContext ec)
4415 IConstant ic = TypeManager.GetConstant (constant);
4416 if (ic.ResolveValue ()) {
4417 if (!ec.IsInObsoleteScope)
4418 ic.CheckObsoleteness (loc);
4421 return ic.CreateConstantReference (loc);
4424 public override void Emit (EmitContext ec)
4426 throw new NotSupportedException ();
4429 public override string GetSignatureForError ()
4431 return TypeManager.GetFullNameSignature (constant);
4436 /// Fully resolved expression that evaluates to a Field
4438 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariable {
4439 public readonly FieldInfo FieldInfo;
4440 VariableInfo variable_info;
4442 LocalTemporary temp;
4444 bool in_initializer;
4446 public FieldExpr (FieldInfo fi, Location l, bool in_initializer):
4449 this.in_initializer = in_initializer;
4452 public FieldExpr (FieldInfo fi, Location l)
4455 eclass = ExprClass.Variable;
4456 type = TypeManager.TypeToCoreType (fi.FieldType);
4460 public override string Name {
4462 return FieldInfo.Name;
4466 public override bool IsInstance {
4468 return !FieldInfo.IsStatic;
4472 public override bool IsStatic {
4474 return FieldInfo.IsStatic;
4478 public override Type DeclaringType {
4480 return FieldInfo.DeclaringType;
4484 public override string GetSignatureForError ()
4486 return TypeManager.GetFullNameSignature (FieldInfo);
4489 public VariableInfo VariableInfo {
4491 return variable_info;
4495 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
4496 SimpleName original)
4498 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
4499 Type t = fi.FieldType;
4501 if (t.IsPointer && !ec.InUnsafe) {
4505 return base.ResolveMemberAccess (ec, left, loc, original);
4508 override public Expression DoResolve (EmitContext ec)
4510 return DoResolve (ec, false, false);
4513 Expression DoResolve (EmitContext ec, bool lvalue_instance, bool out_access)
4515 if (!FieldInfo.IsStatic){
4516 if (InstanceExpression == null){
4518 // This can happen when referencing an instance field using
4519 // a fully qualified type expression: TypeName.InstanceField = xxx
4521 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4525 // Resolve the field's instance expression while flow analysis is turned
4526 // off: when accessing a field "a.b", we must check whether the field
4527 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4529 if (lvalue_instance) {
4530 using (ec.With (EmitContext.Flags.DoFlowAnalysis, false)) {
4531 Expression right_side =
4532 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4533 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side, loc);
4536 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
4537 InstanceExpression = InstanceExpression.Resolve (ec, rf);
4540 if (InstanceExpression == null)
4543 using (ec.Set (EmitContext.Flags.OmitStructFlowAnalysis)) {
4544 InstanceExpression.CheckMarshalByRefAccess (ec);
4548 if (!in_initializer && !ec.IsInFieldInitializer) {
4549 ObsoleteAttribute oa;
4550 FieldBase f = TypeManager.GetField (FieldInfo);
4552 if (!ec.IsInObsoleteScope)
4553 f.CheckObsoleteness (loc);
4555 // To be sure that type is external because we do not register generated fields
4556 } else if (!(FieldInfo.DeclaringType is TypeBuilder)) {
4557 oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
4559 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
4563 AnonymousContainer am = ec.CurrentAnonymousMethod;
4565 if (!FieldInfo.IsStatic){
4566 if (!am.IsIterator && (ec.TypeContainer is Struct)){
4567 Report.Error (1673, loc,
4568 "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",
4575 IFixedBuffer fb = AttributeTester.GetFixedBuffer (FieldInfo);
4577 if (!ec.InFixedInitializer && ec.ContainerType.IsValueType) {
4578 Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4581 if (InstanceExpression.eclass != ExprClass.Variable) {
4582 Report.SymbolRelatedToPreviousError (FieldInfo);
4583 Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4584 TypeManager.GetFullNameSignature (FieldInfo));
4587 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4590 // If the instance expression is a local variable or parameter.
4591 IVariable var = InstanceExpression as IVariable;
4592 if ((var == null) || (var.VariableInfo == null))
4595 VariableInfo vi = var.VariableInfo;
4596 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
4599 variable_info = vi.GetSubStruct (FieldInfo.Name);
4603 static readonly int [] codes = {
4604 191, // instance, write access
4605 192, // instance, out access
4606 198, // static, write access
4607 199, // static, out access
4608 1648, // member of value instance, write access
4609 1649, // member of value instance, out access
4610 1650, // member of value static, write access
4611 1651 // member of value static, out access
4614 static readonly string [] msgs = {
4615 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4616 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4617 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4618 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4619 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4620 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4621 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4622 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4625 // The return value is always null. Returning a value simplifies calling code.
4626 Expression Report_AssignToReadonly (Expression right_side)
4629 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4633 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4635 Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4640 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4642 IVariable var = InstanceExpression as IVariable;
4643 if ((var != null) && (var.VariableInfo != null))
4644 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
4646 bool lvalue_instance = !FieldInfo.IsStatic && FieldInfo.DeclaringType.IsValueType;
4647 bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
4649 Expression e = DoResolve (ec, lvalue_instance, out_access);
4654 FieldBase fb = TypeManager.GetField (FieldInfo);
4658 if (FieldInfo.IsInitOnly) {
4659 // InitOnly fields can only be assigned in constructors or initializers
4660 if (!ec.IsInFieldInitializer && !ec.IsConstructor)
4661 return Report_AssignToReadonly (right_side);
4663 if (ec.IsConstructor) {
4664 Type ctype = ec.TypeContainer.CurrentType;
4666 ctype = ec.ContainerType;
4668 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4669 if (!TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
4670 return Report_AssignToReadonly (right_side);
4671 // static InitOnly fields cannot be assigned-to in an instance constructor
4672 if (IsStatic && !ec.IsStatic)
4673 return Report_AssignToReadonly (right_side);
4674 // instance constructors can't modify InitOnly fields of other instances of the same type
4675 if (!IsStatic && !(InstanceExpression is This))
4676 return Report_AssignToReadonly (right_side);
4680 if (right_side == EmptyExpression.OutAccess &&
4681 !IsStatic && !(InstanceExpression is This) && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type)) {
4682 Report.SymbolRelatedToPreviousError (DeclaringType);
4683 Report.Warning (197, 1, loc,
4684 "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",
4685 GetSignatureForError ());
4691 public override void CheckMarshalByRefAccess (EmitContext ec)
4693 if (!IsStatic && Type.IsValueType && !(InstanceExpression is This) && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type)) {
4694 Report.SymbolRelatedToPreviousError (DeclaringType);
4695 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",
4696 GetSignatureForError ());
4700 public bool VerifyFixed ()
4702 IVariable variable = InstanceExpression as IVariable;
4703 // A variable of the form V.I is fixed when V is a fixed variable of a struct type.
4704 // We defer the InstanceExpression check after the variable check to avoid a
4705 // separate null check on InstanceExpression.
4706 return variable != null && InstanceExpression.Type.IsValueType && variable.VerifyFixed ();
4709 public override int GetHashCode ()
4711 return FieldInfo.GetHashCode ();
4714 public override bool Equals (object obj)
4716 FieldExpr fe = obj as FieldExpr;
4720 if (FieldInfo != fe.FieldInfo)
4723 if (InstanceExpression == null || fe.InstanceExpression == null)
4726 return InstanceExpression.Equals (fe.InstanceExpression);
4729 public void Emit (EmitContext ec, bool leave_copy)
4731 ILGenerator ig = ec.ig;
4732 bool is_volatile = false;
4734 FieldBase f = TypeManager.GetField (FieldInfo);
4736 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4739 f.SetMemberIsUsed ();
4742 if (FieldInfo.IsStatic){
4744 ig.Emit (OpCodes.Volatile);
4746 ig.Emit (OpCodes.Ldsfld, FieldInfo);
4749 EmitInstance (ec, false);
4751 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
4753 ig.Emit (OpCodes.Ldflda, FieldInfo);
4754 ig.Emit (OpCodes.Ldflda, ff.Element);
4757 ig.Emit (OpCodes.Volatile);
4759 ig.Emit (OpCodes.Ldfld, FieldInfo);
4764 ec.ig.Emit (OpCodes.Dup);
4765 if (!FieldInfo.IsStatic) {
4766 temp = new LocalTemporary (this.Type);
4772 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4774 FieldAttributes fa = FieldInfo.Attributes;
4775 bool is_static = (fa & FieldAttributes.Static) != 0;
4776 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
4777 ILGenerator ig = ec.ig;
4779 if (is_readonly && !ec.IsConstructor){
4780 Report_AssignToReadonly (source);
4785 // String concatenation creates a new string instance
4787 prepared = prepare_for_load && !(source is StringConcat);
4788 EmitInstance (ec, prepared);
4792 ec.ig.Emit (OpCodes.Dup);
4793 if (!FieldInfo.IsStatic) {
4794 temp = new LocalTemporary (this.Type);
4799 FieldBase f = TypeManager.GetField (FieldInfo);
4801 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4802 ig.Emit (OpCodes.Volatile);
4808 ig.Emit (OpCodes.Stsfld, FieldInfo);
4810 ig.Emit (OpCodes.Stfld, FieldInfo);
4818 public override void Emit (EmitContext ec)
4823 public void AddressOf (EmitContext ec, AddressOp mode)
4825 ILGenerator ig = ec.ig;
4827 FieldBase f = TypeManager.GetField (FieldInfo);
4829 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
4830 Report.Warning (420, 1, loc, "`{0}': A volatile field references will not be treated as volatile",
4831 f.GetSignatureForError ());
4834 if ((mode & AddressOp.Store) != 0)
4836 if ((mode & AddressOp.Load) != 0)
4837 f.SetMemberIsUsed ();
4841 // Handle initonly fields specially: make a copy and then
4842 // get the address of the copy.
4845 if (FieldInfo.IsInitOnly){
4847 if (ec.IsConstructor){
4848 if (FieldInfo.IsStatic){
4860 local = ig.DeclareLocal (type);
4861 ig.Emit (OpCodes.Stloc, local);
4862 ig.Emit (OpCodes.Ldloca, local);
4867 if (FieldInfo.IsStatic){
4868 ig.Emit (OpCodes.Ldsflda, FieldInfo);
4871 EmitInstance (ec, false);
4872 ig.Emit (OpCodes.Ldflda, FieldInfo);
4879 /// Expression that evaluates to a Property. The Assign class
4880 /// might set the `Value' expression if we are in an assignment.
4882 /// This is not an LValue because we need to re-write the expression, we
4883 /// can not take data from the stack and store it.
4885 public class PropertyExpr : MemberExpr, IAssignMethod {
4886 public readonly PropertyInfo PropertyInfo;
4887 MethodInfo getter, setter;
4892 LocalTemporary temp;
4895 public PropertyExpr (Type container_type, PropertyInfo pi, Location l)
4898 eclass = ExprClass.PropertyAccess;
4902 type = TypeManager.TypeToCoreType (pi.PropertyType);
4904 ResolveAccessors (container_type);
4907 public override string Name {
4909 return PropertyInfo.Name;
4913 public override bool IsInstance {
4919 public override bool IsStatic {
4925 public override Expression CreateExpressionTree (EmitContext ec)
4927 if (IsSingleDimensionalArrayLength ()) {
4928 ArrayList args = new ArrayList (1);
4929 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
4930 return CreateExpressionFactoryCall ("ArrayLength", args);
4933 // TODO: it's waiting for PropertyExpr refactoring
4934 //ArrayList args = new ArrayList (2);
4935 //args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
4936 //args.Add (getter expression);
4937 //return CreateExpressionFactoryCall ("Property", args);
4938 return base.CreateExpressionTree (ec);
4941 public override Type DeclaringType {
4943 return PropertyInfo.DeclaringType;
4947 public override string GetSignatureForError ()
4949 return TypeManager.GetFullNameSignature (PropertyInfo);
4952 void FindAccessors (Type invocation_type)
4954 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
4955 BindingFlags.Static | BindingFlags.Instance |
4956 BindingFlags.DeclaredOnly;
4958 Type current = PropertyInfo.DeclaringType;
4959 for (; current != null; current = current.BaseType) {
4960 MemberInfo[] group = TypeManager.MemberLookup (
4961 invocation_type, invocation_type, current,
4962 MemberTypes.Property, flags, PropertyInfo.Name, null);
4967 if (group.Length != 1)
4968 // Oooops, can this ever happen ?
4971 PropertyInfo pi = (PropertyInfo) group [0];
4974 getter = pi.GetGetMethod (true);
4977 setter = pi.GetSetMethod (true);
4979 MethodInfo accessor = getter != null ? getter : setter;
4981 if (!accessor.IsVirtual)
4987 // We also perform the permission checking here, as the PropertyInfo does not
4988 // hold the information for the accessibility of its setter/getter
4990 // TODO: Refactor to use some kind of cache together with GetPropertyFromAccessor
4991 void ResolveAccessors (Type container_type)
4993 FindAccessors (container_type);
4995 if (getter != null) {
4996 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
4997 IMethodData md = TypeManager.GetMethod (the_getter);
4999 md.SetMemberIsUsed ();
5001 is_static = getter.IsStatic;
5004 if (setter != null) {
5005 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
5006 IMethodData md = TypeManager.GetMethod (the_setter);
5008 md.SetMemberIsUsed ();
5010 is_static = setter.IsStatic;
5014 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
5017 InstanceExpression = null;
5021 if (InstanceExpression == null) {
5022 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5026 InstanceExpression = InstanceExpression.DoResolve (ec);
5027 if (lvalue_instance && InstanceExpression != null)
5028 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
5030 if (InstanceExpression == null)
5033 InstanceExpression.CheckMarshalByRefAccess (ec);
5035 if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) &&
5036 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
5037 !TypeManager.IsNestedChildOf (ec.ContainerType, InstanceExpression.Type) &&
5038 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.ContainerType)) {
5039 Report.SymbolRelatedToPreviousError (PropertyInfo);
5040 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
5047 void Error_PropertyNotFound (MethodInfo mi, bool getter)
5049 // TODO: correctly we should compare arguments but it will lead to bigger changes
5050 if (mi is MethodBuilder) {
5051 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
5055 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
5057 ParameterData iparams = TypeManager.GetParameterData (mi);
5058 sig.Append (getter ? "get_" : "set_");
5060 sig.Append (iparams.GetSignatureForError ());
5062 Report.SymbolRelatedToPreviousError (mi);
5063 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
5064 Name, sig.ToString ());
5067 public bool IsAccessibleFrom (Type invocation_type, bool lvalue)
5070 MethodInfo accessor = lvalue ? setter : getter;
5071 if (accessor == null && lvalue)
5073 return accessor != null && IsAccessorAccessible (invocation_type, accessor, out dummy);
5076 bool IsSingleDimensionalArrayLength ()
5078 if (getter == TypeManager.system_int_array_get_length ||
5079 getter == TypeManager.int_array_get_length) {
5080 Type iet = InstanceExpression.Type;
5083 // System.Array.Length can be called, but the Type does not
5084 // support invoking GetArrayRank, so test for that case first
5086 return iet != TypeManager.array_type && (iet.GetArrayRank () == 1);
5092 override public Expression DoResolve (EmitContext ec)
5097 if (getter != null){
5098 if (TypeManager.GetParameterData (getter).Count != 0){
5099 Error_PropertyNotFound (getter, true);
5104 if (getter == null){
5106 // The following condition happens if the PropertyExpr was
5107 // created, but is invalid (ie, the property is inaccessible),
5108 // and we did not want to embed the knowledge about this in
5109 // the caller routine. This only avoids double error reporting.
5114 if (InstanceExpression != EmptyExpression.Null) {
5115 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5116 TypeManager.GetFullNameSignature (PropertyInfo));
5121 bool must_do_cs1540_check = false;
5122 if (getter != null &&
5123 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
5124 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
5125 if (pm != null && pm.HasCustomAccessModifier) {
5126 Report.SymbolRelatedToPreviousError (pm);
5127 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5128 TypeManager.CSharpSignature (getter));
5131 Report.SymbolRelatedToPreviousError (getter);
5132 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
5137 if (!InstanceResolve (ec, false, must_do_cs1540_check))
5141 // Only base will allow this invocation to happen.
5143 if (IsBase && getter.IsAbstract) {
5144 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5148 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
5158 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
5160 if (right_side == EmptyExpression.OutAccess) {
5161 if (ec.CurrentBlock.Toplevel.GetTransparentIdentifier (PropertyInfo.Name) != null) {
5162 Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5165 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as `ref' or `out' parameter",
5166 GetSignatureForError ());
5171 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5172 Error_CannotModifyIntermediateExpressionValue (ec);
5175 if (setter == null){
5177 // The following condition happens if the PropertyExpr was
5178 // created, but is invalid (ie, the property is inaccessible),
5179 // and we did not want to embed the knowledge about this in
5180 // the caller routine. This only avoids double error reporting.
5184 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
5185 GetSignatureForError ());
5189 if (TypeManager.GetParameterData (setter).Count != 1){
5190 Error_PropertyNotFound (setter, false);
5194 bool must_do_cs1540_check;
5195 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
5196 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
5197 if (pm != null && pm.HasCustomAccessModifier) {
5198 Report.SymbolRelatedToPreviousError (pm);
5199 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5200 TypeManager.CSharpSignature (setter));
5203 Report.SymbolRelatedToPreviousError (setter);
5204 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
5209 if (!InstanceResolve (ec, PropertyInfo.DeclaringType.IsValueType, must_do_cs1540_check))
5213 // Only base will allow this invocation to happen.
5215 if (IsBase && setter.IsAbstract){
5216 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5223 public override void Emit (EmitContext ec)
5228 public void Emit (EmitContext ec, bool leave_copy)
5231 // Special case: length of single dimension array property is turned into ldlen
5233 if (IsSingleDimensionalArrayLength ()) {
5235 EmitInstance (ec, false);
5236 ec.ig.Emit (OpCodes.Ldlen);
5237 ec.ig.Emit (OpCodes.Conv_I4);
5241 Invocation.EmitCall (ec, IsBase, InstanceExpression, getter, null, loc, prepared, false);
5244 ec.ig.Emit (OpCodes.Dup);
5246 temp = new LocalTemporary (this.Type);
5253 // Implements the IAssignMethod interface for assignments
5255 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5257 Expression my_source = source;
5259 if (prepare_for_load) {
5260 if (source is StringConcat)
5261 EmitInstance (ec, false);
5269 ec.ig.Emit (OpCodes.Dup);
5271 temp = new LocalTemporary (this.Type);
5275 } else if (leave_copy) {
5277 temp = new LocalTemporary (this.Type);
5282 ArrayList args = new ArrayList (1);
5283 args.Add (new Argument (my_source, Argument.AType.Expression));
5285 Invocation.EmitCall (ec, IsBase, InstanceExpression, setter, args, loc, false, prepared);
5295 /// Fully resolved expression that evaluates to an Event
5297 public class EventExpr : MemberExpr {
5298 public readonly EventInfo EventInfo;
5301 MethodInfo add_accessor, remove_accessor;
5303 public EventExpr (EventInfo ei, Location loc)
5307 eclass = ExprClass.EventAccess;
5309 add_accessor = TypeManager.GetAddMethod (ei);
5310 remove_accessor = TypeManager.GetRemoveMethod (ei);
5311 if (add_accessor.IsStatic || remove_accessor.IsStatic)
5314 if (EventInfo is MyEventBuilder){
5315 MyEventBuilder eb = (MyEventBuilder) EventInfo;
5316 type = eb.EventType;
5319 type = EventInfo.EventHandlerType;
5322 public override string Name {
5324 return EventInfo.Name;
5328 public override bool IsInstance {
5334 public override bool IsStatic {
5340 public override Type DeclaringType {
5342 return EventInfo.DeclaringType;
5346 void Error_AssignmentEventOnly ()
5348 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5349 GetSignatureForError ());
5352 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
5353 SimpleName original)
5356 // If the event is local to this class, we transform ourselves into a FieldExpr
5359 if (EventInfo.DeclaringType == ec.ContainerType ||
5360 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
5361 EventField mi = TypeManager.GetEventField (EventInfo);
5364 if (!ec.IsInObsoleteScope)
5365 mi.CheckObsoleteness (loc);
5367 if ((mi.ModFlags & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0 && !ec.IsInCompoundAssignment)
5368 Error_AssignmentEventOnly ();
5370 FieldExpr ml = new FieldExpr (mi.FieldBuilder, loc);
5372 InstanceExpression = null;
5374 return ml.ResolveMemberAccess (ec, left, loc, original);
5378 if (left is This && !ec.IsInCompoundAssignment)
5379 Error_AssignmentEventOnly ();
5381 return base.ResolveMemberAccess (ec, left, loc, original);
5385 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
5388 InstanceExpression = null;
5392 if (InstanceExpression == null) {
5393 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5397 InstanceExpression = InstanceExpression.DoResolve (ec);
5398 if (InstanceExpression == null)
5401 if (IsBase && add_accessor.IsAbstract) {
5402 Error_CannotCallAbstractBase(TypeManager.CSharpSignature(add_accessor));
5407 // This is using the same mechanism as the CS1540 check in PropertyExpr.
5408 // However, in the Event case, we reported a CS0122 instead.
5410 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
5411 InstanceExpression.Type != ec.ContainerType &&
5412 TypeManager.IsSubclassOf (ec.ContainerType, InstanceExpression.Type)) {
5413 Report.SymbolRelatedToPreviousError (EventInfo);
5414 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5421 public bool IsAccessibleFrom (Type invocation_type)
5424 return IsAccessorAccessible (invocation_type, add_accessor, out dummy) &&
5425 IsAccessorAccessible (invocation_type, remove_accessor, out dummy);
5428 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5430 return DoResolve (ec);
5433 public override Expression DoResolve (EmitContext ec)
5435 bool must_do_cs1540_check;
5436 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
5437 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
5438 Report.SymbolRelatedToPreviousError (EventInfo);
5439 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5443 if (!InstanceResolve (ec, must_do_cs1540_check))
5449 public override void Emit (EmitContext ec)
5451 Report.Error (70, loc, "The event `{0}' can only appear on the left hand side of += or -= "+
5452 "(except on the defining type)", GetSignatureForError ());
5455 public override string GetSignatureForError ()
5457 return TypeManager.CSharpSignature (EventInfo);
5460 public void EmitAddOrRemove (EmitContext ec, Expression source)
5462 BinaryDelegate source_del = source as BinaryDelegate;
5463 if (source_del == null) {
5467 Expression handler = source_del.Right;
5469 Argument arg = new Argument (handler, Argument.AType.Expression);
5470 ArrayList args = new ArrayList ();
5474 if (source_del.IsAddition)
5475 Invocation.EmitCall (
5476 ec, IsBase, InstanceExpression, add_accessor, args, loc);
5478 Invocation.EmitCall (
5479 ec, IsBase, InstanceExpression, remove_accessor, args, loc);
5483 public class TemporaryVariable : Expression, IMemoryLocation
5488 public TemporaryVariable (Type type, Location loc)
5492 eclass = ExprClass.Value;
5495 public override Expression DoResolve (EmitContext ec)
5500 TypeExpr te = new TypeExpression (type, loc);
5501 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
5502 if (!li.Resolve (ec))
5505 if (ec.MustCaptureVariable (li)) {
5506 ScopeInfo scope = li.Block.CreateScopeInfo ();
5507 var = scope.AddLocal (li);
5514 public Variable Variable {
5515 get { return var != null ? var : li.Variable; }
5518 public override void Emit (EmitContext ec)
5520 Variable.EmitInstance (ec);
5524 public void EmitLoadAddress (EmitContext ec)
5526 Variable.EmitInstance (ec);
5527 Variable.EmitAddressOf (ec);
5530 public void Store (EmitContext ec, Expression right_side)
5532 Variable.EmitInstance (ec);
5533 right_side.Emit (ec);
5534 Variable.EmitAssign (ec);
5537 public void EmitThis (EmitContext ec)
5539 Variable.EmitInstance (ec);
5542 public void EmitStore (EmitContext ec)
5544 Variable.EmitAssign (ec);
5547 public void AddressOf (EmitContext ec, AddressOp mode)
5549 EmitLoadAddress (ec);
5554 /// Handles `var' contextual keyword; var becomes a keyword only
5555 /// if no type called var exists in a variable scope
5557 public class VarExpr : SimpleName
5559 // Used for error reporting only
5560 ArrayList initializer;
5562 public VarExpr (Location loc)
5567 public ArrayList VariableInitializer {
5569 this.initializer = value;
5573 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5576 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
5578 type = right_side.Type;
5579 if (type == TypeManager.null_type || type == TypeManager.void_type || type == TypeManager.anonymous_method_type) {
5580 Report.Error (815, loc, "An implicitly typed local variable declaration cannot be initialized with `{0}'",
5581 right_side.GetSignatureForError ());
5585 eclass = ExprClass.Variable;
5589 protected override void Error_TypeOrNamespaceNotFound (IResolveContext ec)
5591 Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");
5594 public override TypeExpr ResolveAsContextualType (IResolveContext rc, bool silent)
5596 TypeExpr te = base.ResolveAsContextualType (rc, true);
5600 if (initializer == null)
5603 if (initializer.Count > 1) {
5604 Location loc = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [1]).Location;
5605 Report.Error (819, loc, "An implicitly typed local variable declaration cannot include multiple declarators");
5610 Expression variable_initializer = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [0]).expression_or_array_initializer;
5611 if (variable_initializer == null) {
5612 Report.Error (818, loc, "An implicitly typed local variable declarator must include an initializer");