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 return (arg_count - i) * 2 + score;
3703 if (arg_count != param_count)
3704 params_expanded_form = true;
3709 int IsArgumentCompatible (EmitContext ec, Parameter.Modifier arg_mod, Argument argument, Parameter.Modifier param_mod, Type parameter)
3712 // Types have to be identical when ref or out modifer is used
3714 if (arg_mod != 0 || param_mod != 0) {
3715 if (TypeManager.HasElementType (parameter))
3716 parameter = parameter.GetElementType ();
3718 Type a_type = argument.Type;
3719 if (TypeManager.HasElementType (a_type))
3720 a_type = a_type.GetElementType ();
3722 if (a_type != parameter)
3728 // FIXME: Kill this abomination (EmitContext.TempEc)
3729 EmitContext prevec = EmitContext.TempEc;
3730 EmitContext.TempEc = ec;
3732 if (delegate_type != null ?
3733 !Delegate.IsTypeCovariant (argument.Expr, parameter) :
3734 !Convert.ImplicitConversionExists (ec, argument.Expr, parameter))
3737 if (arg_mod != param_mod)
3741 EmitContext.TempEc = prevec;
3747 public static bool IsOverride (MethodBase cand_method, MethodBase base_method)
3749 if (!IsAncestralType (base_method.DeclaringType, cand_method.DeclaringType))
3752 ParameterData cand_pd = TypeManager.GetParameterData (cand_method);
3753 ParameterData base_pd = TypeManager.GetParameterData (base_method);
3755 if (cand_pd.Count != base_pd.Count)
3758 for (int j = 0; j < cand_pd.Count; ++j)
3760 Parameter.Modifier cm = cand_pd.ParameterModifier (j);
3761 Parameter.Modifier bm = base_pd.ParameterModifier (j);
3762 Type ct = TypeManager.TypeToCoreType (cand_pd.ParameterType (j));
3763 Type bt = TypeManager.TypeToCoreType (base_pd.ParameterType (j));
3765 if (cm != bm || ct != bt)
3772 public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2, Location loc)
3774 MemberInfo [] miset;
3775 MethodGroupExpr union;
3780 return (MethodGroupExpr) mg2;
3783 return (MethodGroupExpr) mg1;
3786 MethodGroupExpr left_set = null, right_set = null;
3787 int length1 = 0, length2 = 0;
3789 left_set = (MethodGroupExpr) mg1;
3790 length1 = left_set.Methods.Length;
3792 right_set = (MethodGroupExpr) mg2;
3793 length2 = right_set.Methods.Length;
3795 ArrayList common = new ArrayList ();
3797 foreach (MethodBase r in right_set.Methods){
3798 if (TypeManager.ArrayContainsMethod (left_set.Methods, r))
3802 miset = new MemberInfo [length1 + length2 - common.Count];
3803 left_set.Methods.CopyTo (miset, 0);
3807 foreach (MethodBase r in right_set.Methods) {
3808 if (!common.Contains (r))
3812 union = new MethodGroupExpr (miset, mg1.Type, loc);
3817 static Type MoreSpecific (Type p, Type q)
3819 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
3821 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
3824 if (TypeManager.HasElementType (p))
3826 Type pe = TypeManager.GetElementType (p);
3827 Type qe = TypeManager.GetElementType (q);
3828 Type specific = MoreSpecific (pe, qe);
3834 else if (TypeManager.IsGenericType (p))
3836 Type[] pargs = TypeManager.GetTypeArguments (p);
3837 Type[] qargs = TypeManager.GetTypeArguments (q);
3839 bool p_specific_at_least_once = false;
3840 bool q_specific_at_least_once = false;
3842 for (int i = 0; i < pargs.Length; i++)
3844 Type specific = MoreSpecific (pargs [i], qargs [i]);
3845 if (specific == pargs [i])
3846 p_specific_at_least_once = true;
3847 if (specific == qargs [i])
3848 q_specific_at_least_once = true;
3851 if (p_specific_at_least_once && !q_specific_at_least_once)
3853 if (!p_specific_at_least_once && q_specific_at_least_once)
3861 /// Find the Applicable Function Members (7.4.2.1)
3863 /// me: Method Group expression with the members to select.
3864 /// it might contain constructors or methods (or anything
3865 /// that maps to a method).
3867 /// Arguments: ArrayList containing resolved Argument objects.
3869 /// loc: The location if we want an error to be reported, or a Null
3870 /// location for "probing" purposes.
3872 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3873 /// that is the best match of me on Arguments.
3876 public virtual MethodGroupExpr OverloadResolve (EmitContext ec, ref ArrayList Arguments,
3877 bool may_fail, Location loc)
3879 bool method_params = false;
3880 Type applicable_type = null;
3882 ArrayList candidates = new ArrayList (2);
3883 ArrayList candidate_overrides = null;
3886 // Used to keep a map between the candidate
3887 // and whether it is being considered in its
3888 // normal or expanded form
3890 // false is normal form, true is expanded form
3892 Hashtable candidate_to_form = null;
3894 if (Arguments != null)
3895 arg_count = Arguments.Count;
3897 if (RootContext.Version == LanguageVersion.ISO_1 && Name == "Invoke" && TypeManager.IsDelegateType (DeclaringType)) {
3899 Report.Error (1533, loc, "Invoke cannot be called directly on a delegate");
3903 int nmethods = Methods.Length;
3907 // Methods marked 'override' don't take part in 'applicable_type'
3908 // computation, nor in the actual overload resolution.
3909 // However, they still need to be emitted instead of a base virtual method.
3910 // So, we salt them away into the 'candidate_overrides' array.
3912 // In case of reflected methods, we replace each overriding method with
3913 // its corresponding base virtual method. This is to improve compatibility
3914 // with non-C# libraries which change the visibility of overrides (#75636)
3917 for (int i = 0; i < Methods.Length; ++i) {
3918 MethodBase m = Methods [i];
3919 if (TypeManager.IsOverride (m)) {
3920 if (candidate_overrides == null)
3921 candidate_overrides = new ArrayList ();
3922 candidate_overrides.Add (m);
3923 m = TypeManager.TryGetBaseDefinition (m);
3932 // Enable message recording, it's used mainly by lambda expressions
3934 Report.IMessageRecorder msg_recorder = new Report.MessageRecorder ();
3935 Report.IMessageRecorder prev_recorder = Report.SetMessageRecorder (msg_recorder);
3938 // First we construct the set of applicable methods
3940 bool is_sorted = true;
3941 int best_candidate_rate = int.MaxValue;
3942 for (int i = 0; i < nmethods; i++) {
3943 Type decl_type = Methods [i].DeclaringType;
3946 // If we have already found an applicable method
3947 // we eliminate all base types (Section 14.5.5.1)
3949 if (applicable_type != null && IsAncestralType (decl_type, applicable_type))
3953 // Check if candidate is applicable (section 14.4.2.1)
3955 bool params_expanded_form = false;
3956 int candidate_rate = IsApplicable (ec, Arguments, arg_count, ref Methods [i], ref params_expanded_form);
3958 if (candidate_rate < best_candidate_rate) {
3959 best_candidate_rate = candidate_rate;
3960 best_candidate = Methods [i];
3963 if (params_expanded_form) {
3964 if (candidate_to_form == null)
3965 candidate_to_form = new PtrHashtable ();
3966 MethodBase candidate = Methods [i];
3967 candidate_to_form [candidate] = candidate;
3970 if (candidate_rate != 0) {
3971 if (msg_recorder != null)
3972 msg_recorder.EndSession ();
3976 msg_recorder = null;
3977 candidates.Add (Methods [i]);
3979 if (applicable_type == null)
3980 applicable_type = decl_type;
3981 else if (applicable_type != decl_type) {
3983 if (IsAncestralType (applicable_type, decl_type))
3984 applicable_type = decl_type;
3988 Report.SetMessageRecorder (prev_recorder);
3989 if (msg_recorder != null && msg_recorder.PrintMessages ())
3992 int candidate_top = candidates.Count;
3994 if (applicable_type == null) {
3996 // When we found a top level method which does not match and it's
3997 // not an extension method. We start extension methods lookup from here
3999 if (InstanceExpression != null) {
4000 ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (type, Name);
4001 if (ex_method_lookup != null) {
4002 ex_method_lookup.ExtensionExpression = InstanceExpression;
4003 ex_method_lookup.SetTypeArguments (type_arguments);
4004 return ex_method_lookup.OverloadResolve (ec, ref Arguments, may_fail, loc);
4012 // Okay so we have failed to find exact match so we
4013 // return error info about the closest match
4015 if (best_candidate != null) {
4016 if (CustomErrorHandler != null) {
4017 if (CustomErrorHandler.NoExactMatch (ec, best_candidate))
4021 ParameterData pd = TypeManager.GetParameterData (best_candidate);
4022 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4023 if (arg_count == pd.Count || pd.HasParams) {
4024 if (TypeManager.IsGenericMethodDefinition (best_candidate)) {
4025 if (type_arguments == null) {
4026 Report.Error (411, loc,
4027 "The type arguments for method `{0}' cannot be inferred from " +
4028 "the usage. Try specifying the type arguments explicitly",
4029 TypeManager.CSharpSignature (best_candidate));
4033 Type [] g_args = TypeManager.GetGenericArguments (best_candidate);
4034 if (type_arguments.Count != g_args.Length) {
4035 Report.SymbolRelatedToPreviousError (best_candidate);
4036 Report.Error (305, loc, "Using the generic method `{0}' requires `{1}' type argument(s)",
4037 TypeManager.CSharpSignature (best_candidate),
4038 g_args.Length.ToString ());
4042 if (type_arguments != null && !TypeManager.IsGenericMethod (best_candidate)) {
4043 Namespace.Error_TypeArgumentsCannotBeUsed (best_candidate, loc);
4048 if (VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate, cand_params, may_fail, loc))
4049 throw new InternalErrorException ("Overload verification expected failure");
4054 if (almost_matched_members.Count != 0) {
4055 Error_MemberLookupFailed (ec.ContainerType, type, type, ".ctor",
4056 null, MemberTypes.Constructor, AllBindingFlags);
4061 // We failed to find any method with correct argument count
4063 if (Name == ConstructorInfo.ConstructorName) {
4064 Report.SymbolRelatedToPreviousError (type);
4065 Report.Error (1729, loc,
4066 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4067 TypeManager.CSharpName (type), arg_count);
4069 Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4070 Name, arg_count.ToString ());
4078 // At this point, applicable_type is _one_ of the most derived types
4079 // in the set of types containing the methods in this MethodGroup.
4080 // Filter the candidates so that they only contain methods from the
4081 // most derived types.
4084 int finalized = 0; // Number of finalized candidates
4087 // Invariant: applicable_type is a most derived type
4089 // We'll try to complete Section 14.5.5.1 for 'applicable_type' by
4090 // eliminating all it's base types. At the same time, we'll also move
4091 // every unrelated type to the end of the array, and pick the next
4092 // 'applicable_type'.
4094 Type next_applicable_type = null;
4095 int j = finalized; // where to put the next finalized candidate
4096 int k = finalized; // where to put the next undiscarded candidate
4097 for (int i = finalized; i < candidate_top; ++i) {
4098 MethodBase candidate = (MethodBase) candidates [i];
4099 Type decl_type = candidate.DeclaringType;
4101 if (decl_type == applicable_type) {
4102 candidates [k++] = candidates [j];
4103 candidates [j++] = candidates [i];
4107 if (IsAncestralType (decl_type, applicable_type))
4110 if (next_applicable_type != null &&
4111 IsAncestralType (decl_type, next_applicable_type))
4114 candidates [k++] = candidates [i];
4116 if (next_applicable_type == null ||
4117 IsAncestralType (next_applicable_type, decl_type))
4118 next_applicable_type = decl_type;
4121 applicable_type = next_applicable_type;
4124 } while (applicable_type != null);
4128 // Now we actually find the best method
4131 best_candidate = (MethodBase) candidates [0];
4132 if (delegate_type == null)
4133 method_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4135 for (int ix = 1; ix < candidate_top; ix++) {
4136 MethodBase candidate = (MethodBase) candidates [ix];
4138 if (candidate == best_candidate)
4141 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4143 if (BetterFunction (ec, Arguments, arg_count,
4144 candidate, cand_params,
4145 best_candidate, method_params)) {
4146 best_candidate = candidate;
4147 method_params = cand_params;
4151 // Now check that there are no ambiguities i.e the selected method
4152 // should be better than all the others
4154 MethodBase ambiguous = null;
4155 for (int ix = 0; ix < candidate_top; ix++) {
4156 MethodBase candidate = (MethodBase) candidates [ix];
4158 if (candidate == best_candidate)
4161 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4162 if (!BetterFunction (ec, Arguments, arg_count,
4163 best_candidate, method_params,
4164 candidate, cand_params))
4167 Report.SymbolRelatedToPreviousError (candidate);
4168 ambiguous = candidate;
4172 if (ambiguous != null) {
4173 Report.SymbolRelatedToPreviousError (best_candidate);
4174 Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4175 TypeManager.CSharpSignature (ambiguous), TypeManager.CSharpSignature (best_candidate));
4180 // If the method is a virtual function, pick an override closer to the LHS type.
4182 if (!IsBase && best_candidate.IsVirtual) {
4183 if (TypeManager.IsOverride (best_candidate))
4184 throw new InternalErrorException (
4185 "Should not happen. An 'override' method took part in overload resolution: " + best_candidate);
4187 if (candidate_overrides != null) {
4188 Type[] gen_args = null;
4189 bool gen_override = false;
4190 if (TypeManager.IsGenericMethod (best_candidate))
4191 gen_args = TypeManager.GetGenericArguments (best_candidate);
4193 foreach (MethodBase candidate in candidate_overrides) {
4194 if (TypeManager.IsGenericMethod (candidate)) {
4195 if (gen_args == null)
4198 if (gen_args.Length != TypeManager.GetGenericArguments (candidate).Length)
4201 if (gen_args != null)
4205 if (IsOverride (candidate, best_candidate)) {
4206 gen_override = true;
4207 best_candidate = candidate;
4211 if (gen_override && gen_args != null) {
4213 best_candidate = ((MethodInfo) best_candidate).MakeGenericMethod (gen_args);
4220 // And now check if the arguments are all
4221 // compatible, perform conversions if
4222 // necessary etc. and return if everything is
4225 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate,
4226 method_params, may_fail, loc))
4229 if (best_candidate == null)
4232 MethodBase the_method = TypeManager.DropGenericMethodArguments (best_candidate);
4234 if (the_method.IsGenericMethodDefinition &&
4235 !ConstraintChecker.CheckConstraints (ec, the_method, best_candidate, loc))
4239 IMethodData data = TypeManager.GetMethod (the_method);
4241 data.SetMemberIsUsed ();
4246 public override void SetTypeArguments (TypeArguments ta)
4248 type_arguments = ta;
4251 public bool VerifyArgumentsCompat (EmitContext ec, ref ArrayList arguments,
4252 int arg_count, MethodBase method,
4253 bool chose_params_expanded,
4254 bool may_fail, Location loc)
4256 ParameterData pd = TypeManager.GetParameterData (method);
4258 int errors = Report.Errors;
4259 Parameter.Modifier p_mod = 0;
4261 int a_idx = 0, a_pos = 0;
4263 ArrayList params_initializers = null;
4265 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4266 a = (Argument) arguments [a_idx];
4267 if (p_mod != Parameter.Modifier.PARAMS) {
4268 p_mod = pd.ParameterModifier (a_idx);
4269 pt = pd.ParameterType (a_idx);
4271 if (p_mod == Parameter.Modifier.ARGLIST) {
4272 if (a.Type != TypeManager.runtime_argument_handle_type)
4277 if (pt.IsPointer && !ec.InUnsafe) {
4284 if (p_mod == Parameter.Modifier.PARAMS) {
4285 if (chose_params_expanded) {
4286 params_initializers = new ArrayList (arg_count - a_idx);
4287 pt = TypeManager.GetElementType (pt);
4289 } else if (p_mod != 0) {
4290 pt = TypeManager.GetElementType (pt);
4295 // Types have to be identical when ref or out modifer is used
4297 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4298 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4301 if (!TypeManager.IsEqual (a.Expr.Type, pt))
4308 if (TypeManager.IsEqual (a.Type, pt)) {
4311 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4317 // Convert params arguments to an array initializer
4319 if (params_initializers != null) {
4320 params_initializers.Add (conv);
4321 arguments.RemoveAt (a_idx--);
4326 // Update the argument with the implicit conversion
4331 // Fill not provided arguments required by params modifier
4333 if (params_initializers == null && pd.HasParams && arg_count < pd.Count) {
4334 if (arguments == null)
4335 arguments = new ArrayList (1);
4337 pt = pd.Types [GetApplicableParametersCount (method, pd) - 1];
4338 pt = TypeManager.GetElementType (pt);
4339 params_initializers = new ArrayList (0);
4342 if (a_idx == arg_count) {
4344 // Append an array argument with all params arguments
4346 if (params_initializers != null) {
4347 arguments.Add (new Argument (
4348 new ArrayCreation (new TypeExpression (pt, loc), "[]",
4349 params_initializers, loc).Resolve (ec)));
4354 if (!may_fail && Report.Errors == errors) {
4355 if (CustomErrorHandler != null)
4356 CustomErrorHandler.NoExactMatch (ec, best_candidate);
4358 Error_InvalidArguments (ec, loc, a_pos, method, a, pd, pt);
4364 public class ConstantExpr : MemberExpr
4368 public ConstantExpr (FieldInfo constant, Location loc)
4370 this.constant = constant;
4374 public override string Name {
4375 get { throw new NotImplementedException (); }
4378 public override bool IsInstance {
4379 get { return !IsStatic; }
4382 public override bool IsStatic {
4383 get { return constant.IsStatic; }
4386 public override Type DeclaringType {
4387 get { return constant.DeclaringType; }
4390 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc, SimpleName original)
4392 constant = TypeManager.GetGenericFieldDefinition (constant);
4394 IConstant ic = TypeManager.GetConstant (constant);
4396 if (constant.IsLiteral) {
4397 ic = new ExternalConstant (constant);
4399 ic = ExternalConstant.CreateDecimal (constant);
4400 // HACK: decimal field was not resolved as constant
4402 return new FieldExpr (constant, loc).ResolveMemberAccess (ec, left, loc, original);
4404 TypeManager.RegisterConstant (constant, ic);
4407 return base.ResolveMemberAccess (ec, left, loc, original);
4410 public override Expression DoResolve (EmitContext ec)
4412 IConstant ic = TypeManager.GetConstant (constant);
4413 if (ic.ResolveValue ()) {
4414 if (!ec.IsInObsoleteScope)
4415 ic.CheckObsoleteness (loc);
4418 return ic.CreateConstantReference (loc);
4421 public override void Emit (EmitContext ec)
4423 throw new NotSupportedException ();
4426 public override string GetSignatureForError ()
4428 return TypeManager.GetFullNameSignature (constant);
4433 /// Fully resolved expression that evaluates to a Field
4435 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariable {
4436 public readonly FieldInfo FieldInfo;
4437 VariableInfo variable_info;
4439 LocalTemporary temp;
4441 bool in_initializer;
4443 public FieldExpr (FieldInfo fi, Location l, bool in_initializer):
4446 this.in_initializer = in_initializer;
4449 public FieldExpr (FieldInfo fi, Location l)
4452 eclass = ExprClass.Variable;
4453 type = TypeManager.TypeToCoreType (fi.FieldType);
4457 public override string Name {
4459 return FieldInfo.Name;
4463 public override bool IsInstance {
4465 return !FieldInfo.IsStatic;
4469 public override bool IsStatic {
4471 return FieldInfo.IsStatic;
4475 public override Type DeclaringType {
4477 return FieldInfo.DeclaringType;
4481 public override string GetSignatureForError ()
4483 return TypeManager.GetFullNameSignature (FieldInfo);
4486 public VariableInfo VariableInfo {
4488 return variable_info;
4492 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
4493 SimpleName original)
4495 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
4496 Type t = fi.FieldType;
4498 if (t.IsPointer && !ec.InUnsafe) {
4502 return base.ResolveMemberAccess (ec, left, loc, original);
4505 override public Expression DoResolve (EmitContext ec)
4507 return DoResolve (ec, false, false);
4510 Expression DoResolve (EmitContext ec, bool lvalue_instance, bool out_access)
4512 if (!FieldInfo.IsStatic){
4513 if (InstanceExpression == null){
4515 // This can happen when referencing an instance field using
4516 // a fully qualified type expression: TypeName.InstanceField = xxx
4518 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4522 // Resolve the field's instance expression while flow analysis is turned
4523 // off: when accessing a field "a.b", we must check whether the field
4524 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4526 if (lvalue_instance) {
4527 using (ec.With (EmitContext.Flags.DoFlowAnalysis, false)) {
4528 Expression right_side =
4529 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4530 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side, loc);
4533 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
4534 InstanceExpression = InstanceExpression.Resolve (ec, rf);
4537 if (InstanceExpression == null)
4540 using (ec.Set (EmitContext.Flags.OmitStructFlowAnalysis)) {
4541 InstanceExpression.CheckMarshalByRefAccess (ec);
4545 if (!in_initializer && !ec.IsInFieldInitializer) {
4546 ObsoleteAttribute oa;
4547 FieldBase f = TypeManager.GetField (FieldInfo);
4549 if (!ec.IsInObsoleteScope)
4550 f.CheckObsoleteness (loc);
4552 // To be sure that type is external because we do not register generated fields
4553 } else if (!(FieldInfo.DeclaringType is TypeBuilder)) {
4554 oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
4556 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
4560 AnonymousContainer am = ec.CurrentAnonymousMethod;
4562 if (!FieldInfo.IsStatic){
4563 if (!am.IsIterator && (ec.TypeContainer is Struct)){
4564 Report.Error (1673, loc,
4565 "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",
4572 IFixedBuffer fb = AttributeTester.GetFixedBuffer (FieldInfo);
4574 if (!ec.InFixedInitializer && ec.ContainerType.IsValueType) {
4575 Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4578 if (InstanceExpression.eclass != ExprClass.Variable) {
4579 Report.SymbolRelatedToPreviousError (FieldInfo);
4580 Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4581 TypeManager.GetFullNameSignature (FieldInfo));
4584 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4587 // If the instance expression is a local variable or parameter.
4588 IVariable var = InstanceExpression as IVariable;
4589 if ((var == null) || (var.VariableInfo == null))
4592 VariableInfo vi = var.VariableInfo;
4593 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
4596 variable_info = vi.GetSubStruct (FieldInfo.Name);
4600 static readonly int [] codes = {
4601 191, // instance, write access
4602 192, // instance, out access
4603 198, // static, write access
4604 199, // static, out access
4605 1648, // member of value instance, write access
4606 1649, // member of value instance, out access
4607 1650, // member of value static, write access
4608 1651 // member of value static, out access
4611 static readonly string [] msgs = {
4612 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4613 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4614 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4615 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4616 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4617 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4618 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4619 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4622 // The return value is always null. Returning a value simplifies calling code.
4623 Expression Report_AssignToReadonly (Expression right_side)
4626 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4630 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4632 Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4637 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4639 IVariable var = InstanceExpression as IVariable;
4640 if ((var != null) && (var.VariableInfo != null))
4641 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
4643 bool lvalue_instance = !FieldInfo.IsStatic && FieldInfo.DeclaringType.IsValueType;
4644 bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
4646 Expression e = DoResolve (ec, lvalue_instance, out_access);
4651 FieldBase fb = TypeManager.GetField (FieldInfo);
4655 if (FieldInfo.IsInitOnly) {
4656 // InitOnly fields can only be assigned in constructors or initializers
4657 if (!ec.IsInFieldInitializer && !ec.IsConstructor)
4658 return Report_AssignToReadonly (right_side);
4660 if (ec.IsConstructor) {
4661 Type ctype = ec.TypeContainer.CurrentType;
4663 ctype = ec.ContainerType;
4665 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4666 if (!TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
4667 return Report_AssignToReadonly (right_side);
4668 // static InitOnly fields cannot be assigned-to in an instance constructor
4669 if (IsStatic && !ec.IsStatic)
4670 return Report_AssignToReadonly (right_side);
4671 // instance constructors can't modify InitOnly fields of other instances of the same type
4672 if (!IsStatic && !(InstanceExpression is This))
4673 return Report_AssignToReadonly (right_side);
4677 if (right_side == EmptyExpression.OutAccess &&
4678 !IsStatic && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
4679 Report.SymbolRelatedToPreviousError (DeclaringType);
4680 Report.Warning (197, 1, loc,
4681 "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",
4682 GetSignatureForError ());
4688 public override void CheckMarshalByRefAccess (EmitContext ec)
4690 if (!IsStatic && Type.IsValueType && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
4691 Report.SymbolRelatedToPreviousError (DeclaringType);
4692 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",
4693 GetSignatureForError ());
4697 public bool VerifyFixed ()
4699 IVariable variable = InstanceExpression as IVariable;
4700 // A variable of the form V.I is fixed when V is a fixed variable of a struct type.
4701 // We defer the InstanceExpression check after the variable check to avoid a
4702 // separate null check on InstanceExpression.
4703 return variable != null && InstanceExpression.Type.IsValueType && variable.VerifyFixed ();
4706 public override int GetHashCode ()
4708 return FieldInfo.GetHashCode ();
4711 public override bool Equals (object obj)
4713 FieldExpr fe = obj as FieldExpr;
4717 if (FieldInfo != fe.FieldInfo)
4720 if (InstanceExpression == null || fe.InstanceExpression == null)
4723 return InstanceExpression.Equals (fe.InstanceExpression);
4726 public void Emit (EmitContext ec, bool leave_copy)
4728 ILGenerator ig = ec.ig;
4729 bool is_volatile = false;
4731 FieldBase f = TypeManager.GetField (FieldInfo);
4733 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4736 f.SetMemberIsUsed ();
4739 if (FieldInfo.IsStatic){
4741 ig.Emit (OpCodes.Volatile);
4743 ig.Emit (OpCodes.Ldsfld, FieldInfo);
4746 EmitInstance (ec, false);
4748 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
4750 ig.Emit (OpCodes.Ldflda, FieldInfo);
4751 ig.Emit (OpCodes.Ldflda, ff.Element);
4754 ig.Emit (OpCodes.Volatile);
4756 ig.Emit (OpCodes.Ldfld, FieldInfo);
4761 ec.ig.Emit (OpCodes.Dup);
4762 if (!FieldInfo.IsStatic) {
4763 temp = new LocalTemporary (this.Type);
4769 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4771 FieldAttributes fa = FieldInfo.Attributes;
4772 bool is_static = (fa & FieldAttributes.Static) != 0;
4773 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
4774 ILGenerator ig = ec.ig;
4776 if (is_readonly && !ec.IsConstructor){
4777 Report_AssignToReadonly (source);
4782 // String concatenation creates a new string instance
4784 prepared = prepare_for_load && !(source is StringConcat);
4785 EmitInstance (ec, prepared);
4789 ec.ig.Emit (OpCodes.Dup);
4790 if (!FieldInfo.IsStatic) {
4791 temp = new LocalTemporary (this.Type);
4796 FieldBase f = TypeManager.GetField (FieldInfo);
4798 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4799 ig.Emit (OpCodes.Volatile);
4805 ig.Emit (OpCodes.Stsfld, FieldInfo);
4807 ig.Emit (OpCodes.Stfld, FieldInfo);
4815 public override void Emit (EmitContext ec)
4820 public void AddressOf (EmitContext ec, AddressOp mode)
4822 ILGenerator ig = ec.ig;
4824 FieldBase f = TypeManager.GetField (FieldInfo);
4826 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
4827 Report.Warning (420, 1, loc, "`{0}': A volatile field references will not be treated as volatile",
4828 f.GetSignatureForError ());
4831 if ((mode & AddressOp.Store) != 0)
4833 if ((mode & AddressOp.Load) != 0)
4834 f.SetMemberIsUsed ();
4838 // Handle initonly fields specially: make a copy and then
4839 // get the address of the copy.
4842 if (FieldInfo.IsInitOnly){
4844 if (ec.IsConstructor){
4845 if (FieldInfo.IsStatic){
4857 local = ig.DeclareLocal (type);
4858 ig.Emit (OpCodes.Stloc, local);
4859 ig.Emit (OpCodes.Ldloca, local);
4864 if (FieldInfo.IsStatic){
4865 ig.Emit (OpCodes.Ldsflda, FieldInfo);
4868 EmitInstance (ec, false);
4869 ig.Emit (OpCodes.Ldflda, FieldInfo);
4876 /// Expression that evaluates to a Property. The Assign class
4877 /// might set the `Value' expression if we are in an assignment.
4879 /// This is not an LValue because we need to re-write the expression, we
4880 /// can not take data from the stack and store it.
4882 public class PropertyExpr : MemberExpr, IAssignMethod {
4883 public readonly PropertyInfo PropertyInfo;
4884 MethodInfo getter, setter;
4889 LocalTemporary temp;
4892 public PropertyExpr (Type container_type, PropertyInfo pi, Location l)
4895 eclass = ExprClass.PropertyAccess;
4899 type = TypeManager.TypeToCoreType (pi.PropertyType);
4901 ResolveAccessors (container_type);
4904 public override string Name {
4906 return PropertyInfo.Name;
4910 public override bool IsInstance {
4916 public override bool IsStatic {
4922 public override Expression CreateExpressionTree (EmitContext ec)
4924 if (IsSingleDimensionalArrayLength ()) {
4925 ArrayList args = new ArrayList (1);
4926 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
4927 return CreateExpressionFactoryCall ("ArrayLength", args);
4930 // TODO: it's waiting for PropertyExpr refactoring
4931 //ArrayList args = new ArrayList (2);
4932 //args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
4933 //args.Add (getter expression);
4934 //return CreateExpressionFactoryCall ("Property", args);
4935 return base.CreateExpressionTree (ec);
4938 public override Type DeclaringType {
4940 return PropertyInfo.DeclaringType;
4944 public override string GetSignatureForError ()
4946 return TypeManager.GetFullNameSignature (PropertyInfo);
4949 void FindAccessors (Type invocation_type)
4951 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
4952 BindingFlags.Static | BindingFlags.Instance |
4953 BindingFlags.DeclaredOnly;
4955 Type current = PropertyInfo.DeclaringType;
4956 for (; current != null; current = current.BaseType) {
4957 MemberInfo[] group = TypeManager.MemberLookup (
4958 invocation_type, invocation_type, current,
4959 MemberTypes.Property, flags, PropertyInfo.Name, null);
4964 if (group.Length != 1)
4965 // Oooops, can this ever happen ?
4968 PropertyInfo pi = (PropertyInfo) group [0];
4971 getter = pi.GetGetMethod (true);
4974 setter = pi.GetSetMethod (true);
4976 MethodInfo accessor = getter != null ? getter : setter;
4978 if (!accessor.IsVirtual)
4984 // We also perform the permission checking here, as the PropertyInfo does not
4985 // hold the information for the accessibility of its setter/getter
4987 // TODO: Refactor to use some kind of cache together with GetPropertyFromAccessor
4988 void ResolveAccessors (Type container_type)
4990 FindAccessors (container_type);
4992 if (getter != null) {
4993 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
4994 IMethodData md = TypeManager.GetMethod (the_getter);
4996 md.SetMemberIsUsed ();
4998 is_static = getter.IsStatic;
5001 if (setter != null) {
5002 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
5003 IMethodData md = TypeManager.GetMethod (the_setter);
5005 md.SetMemberIsUsed ();
5007 is_static = setter.IsStatic;
5011 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
5014 InstanceExpression = null;
5018 if (InstanceExpression == null) {
5019 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5023 InstanceExpression = InstanceExpression.DoResolve (ec);
5024 if (lvalue_instance && InstanceExpression != null)
5025 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
5027 if (InstanceExpression == null)
5030 InstanceExpression.CheckMarshalByRefAccess (ec);
5032 if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) &&
5033 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
5034 !TypeManager.IsNestedChildOf (ec.ContainerType, InstanceExpression.Type) &&
5035 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.ContainerType)) {
5036 Report.SymbolRelatedToPreviousError (PropertyInfo);
5037 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
5044 void Error_PropertyNotFound (MethodInfo mi, bool getter)
5046 // TODO: correctly we should compare arguments but it will lead to bigger changes
5047 if (mi is MethodBuilder) {
5048 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
5052 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
5054 ParameterData iparams = TypeManager.GetParameterData (mi);
5055 sig.Append (getter ? "get_" : "set_");
5057 sig.Append (iparams.GetSignatureForError ());
5059 Report.SymbolRelatedToPreviousError (mi);
5060 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
5061 Name, sig.ToString ());
5064 public bool IsAccessibleFrom (Type invocation_type, bool lvalue)
5067 MethodInfo accessor = lvalue ? setter : getter;
5068 if (accessor == null && lvalue)
5070 return accessor != null && IsAccessorAccessible (invocation_type, accessor, out dummy);
5073 bool IsSingleDimensionalArrayLength ()
5075 if (getter == TypeManager.system_int_array_get_length ||
5076 getter == TypeManager.int_array_get_length) {
5077 Type iet = InstanceExpression.Type;
5080 // System.Array.Length can be called, but the Type does not
5081 // support invoking GetArrayRank, so test for that case first
5083 return iet != TypeManager.array_type && (iet.GetArrayRank () == 1);
5089 override public Expression DoResolve (EmitContext ec)
5094 if (getter != null){
5095 if (TypeManager.GetParameterData (getter).Count != 0){
5096 Error_PropertyNotFound (getter, true);
5101 if (getter == null){
5103 // The following condition happens if the PropertyExpr was
5104 // created, but is invalid (ie, the property is inaccessible),
5105 // and we did not want to embed the knowledge about this in
5106 // the caller routine. This only avoids double error reporting.
5111 if (InstanceExpression != EmptyExpression.Null) {
5112 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5113 TypeManager.GetFullNameSignature (PropertyInfo));
5118 bool must_do_cs1540_check = false;
5119 if (getter != null &&
5120 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
5121 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
5122 if (pm != null && pm.HasCustomAccessModifier) {
5123 Report.SymbolRelatedToPreviousError (pm);
5124 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5125 TypeManager.CSharpSignature (getter));
5128 Report.SymbolRelatedToPreviousError (getter);
5129 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
5134 if (!InstanceResolve (ec, false, must_do_cs1540_check))
5138 // Only base will allow this invocation to happen.
5140 if (IsBase && getter.IsAbstract) {
5141 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5145 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
5155 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
5157 if (right_side == EmptyExpression.OutAccess) {
5158 if (ec.CurrentBlock.Toplevel.GetTransparentIdentifier (PropertyInfo.Name) != null) {
5159 Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5162 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as `ref' or `out' parameter",
5163 GetSignatureForError ());
5168 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5169 Error_CannotModifyIntermediateExpressionValue (ec);
5172 if (setter == null){
5174 // The following condition happens if the PropertyExpr was
5175 // created, but is invalid (ie, the property is inaccessible),
5176 // and we did not want to embed the knowledge about this in
5177 // the caller routine. This only avoids double error reporting.
5181 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
5182 GetSignatureForError ());
5186 if (TypeManager.GetParameterData (setter).Count != 1){
5187 Error_PropertyNotFound (setter, false);
5191 bool must_do_cs1540_check;
5192 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
5193 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
5194 if (pm != null && pm.HasCustomAccessModifier) {
5195 Report.SymbolRelatedToPreviousError (pm);
5196 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5197 TypeManager.CSharpSignature (setter));
5200 Report.SymbolRelatedToPreviousError (setter);
5201 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
5206 if (!InstanceResolve (ec, PropertyInfo.DeclaringType.IsValueType, must_do_cs1540_check))
5210 // Only base will allow this invocation to happen.
5212 if (IsBase && setter.IsAbstract){
5213 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5220 public override void Emit (EmitContext ec)
5225 public void Emit (EmitContext ec, bool leave_copy)
5228 // Special case: length of single dimension array property is turned into ldlen
5230 if (IsSingleDimensionalArrayLength ()) {
5232 EmitInstance (ec, false);
5233 ec.ig.Emit (OpCodes.Ldlen);
5234 ec.ig.Emit (OpCodes.Conv_I4);
5238 Invocation.EmitCall (ec, IsBase, InstanceExpression, getter, null, loc, prepared, false);
5241 ec.ig.Emit (OpCodes.Dup);
5243 temp = new LocalTemporary (this.Type);
5250 // Implements the IAssignMethod interface for assignments
5252 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5254 Expression my_source = source;
5256 if (prepare_for_load) {
5257 if (source is StringConcat)
5258 EmitInstance (ec, false);
5266 ec.ig.Emit (OpCodes.Dup);
5268 temp = new LocalTemporary (this.Type);
5272 } else if (leave_copy) {
5274 temp = new LocalTemporary (this.Type);
5279 ArrayList args = new ArrayList (1);
5280 args.Add (new Argument (my_source, Argument.AType.Expression));
5282 Invocation.EmitCall (ec, IsBase, InstanceExpression, setter, args, loc, false, prepared);
5292 /// Fully resolved expression that evaluates to an Event
5294 public class EventExpr : MemberExpr {
5295 public readonly EventInfo EventInfo;
5298 MethodInfo add_accessor, remove_accessor;
5300 public EventExpr (EventInfo ei, Location loc)
5304 eclass = ExprClass.EventAccess;
5306 add_accessor = TypeManager.GetAddMethod (ei);
5307 remove_accessor = TypeManager.GetRemoveMethod (ei);
5308 if (add_accessor.IsStatic || remove_accessor.IsStatic)
5311 if (EventInfo is MyEventBuilder){
5312 MyEventBuilder eb = (MyEventBuilder) EventInfo;
5313 type = eb.EventType;
5316 type = EventInfo.EventHandlerType;
5319 public override string Name {
5321 return EventInfo.Name;
5325 public override bool IsInstance {
5331 public override bool IsStatic {
5337 public override Type DeclaringType {
5339 return EventInfo.DeclaringType;
5343 void Error_AssignmentEventOnly ()
5345 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5346 GetSignatureForError ());
5349 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
5350 SimpleName original)
5353 // If the event is local to this class, we transform ourselves into a FieldExpr
5356 if (EventInfo.DeclaringType == ec.ContainerType ||
5357 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
5358 EventField mi = TypeManager.GetEventField (EventInfo);
5361 if (!ec.IsInObsoleteScope)
5362 mi.CheckObsoleteness (loc);
5364 if ((mi.ModFlags & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0 && !ec.IsInCompoundAssignment)
5365 Error_AssignmentEventOnly ();
5367 FieldExpr ml = new FieldExpr (mi.FieldBuilder, loc);
5369 InstanceExpression = null;
5371 return ml.ResolveMemberAccess (ec, left, loc, original);
5375 if (left is This && !ec.IsInCompoundAssignment)
5376 Error_AssignmentEventOnly ();
5378 return base.ResolveMemberAccess (ec, left, loc, original);
5382 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
5385 InstanceExpression = null;
5389 if (InstanceExpression == null) {
5390 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5394 InstanceExpression = InstanceExpression.DoResolve (ec);
5395 if (InstanceExpression == null)
5398 if (IsBase && add_accessor.IsAbstract) {
5399 Error_CannotCallAbstractBase(TypeManager.CSharpSignature(add_accessor));
5404 // This is using the same mechanism as the CS1540 check in PropertyExpr.
5405 // However, in the Event case, we reported a CS0122 instead.
5407 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
5408 InstanceExpression.Type != ec.ContainerType &&
5409 ec.ContainerType.IsSubclassOf (InstanceExpression.Type)) {
5410 Report.SymbolRelatedToPreviousError (EventInfo);
5411 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5418 public bool IsAccessibleFrom (Type invocation_type)
5421 return IsAccessorAccessible (invocation_type, add_accessor, out dummy) &&
5422 IsAccessorAccessible (invocation_type, remove_accessor, out dummy);
5425 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5427 return DoResolve (ec);
5430 public override Expression DoResolve (EmitContext ec)
5432 bool must_do_cs1540_check;
5433 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
5434 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
5435 Report.SymbolRelatedToPreviousError (EventInfo);
5436 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5440 if (!InstanceResolve (ec, must_do_cs1540_check))
5446 public override void Emit (EmitContext ec)
5448 Report.Error (70, loc, "The event `{0}' can only appear on the left hand side of += or -= "+
5449 "(except on the defining type)", GetSignatureForError ());
5452 public override string GetSignatureForError ()
5454 return TypeManager.CSharpSignature (EventInfo);
5457 public void EmitAddOrRemove (EmitContext ec, Expression source)
5459 BinaryDelegate source_del = source as BinaryDelegate;
5460 if (source_del == null) {
5464 Expression handler = source_del.Right;
5466 Argument arg = new Argument (handler, Argument.AType.Expression);
5467 ArrayList args = new ArrayList ();
5471 if (source_del.IsAddition)
5472 Invocation.EmitCall (
5473 ec, IsBase, InstanceExpression, add_accessor, args, loc);
5475 Invocation.EmitCall (
5476 ec, IsBase, InstanceExpression, remove_accessor, args, loc);
5480 public class TemporaryVariable : Expression, IMemoryLocation
5485 public TemporaryVariable (Type type, Location loc)
5489 eclass = ExprClass.Value;
5492 public override Expression DoResolve (EmitContext ec)
5497 TypeExpr te = new TypeExpression (type, loc);
5498 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
5499 if (!li.Resolve (ec))
5502 if (ec.MustCaptureVariable (li)) {
5503 ScopeInfo scope = li.Block.CreateScopeInfo ();
5504 var = scope.AddLocal (li);
5511 public Variable Variable {
5512 get { return var != null ? var : li.Variable; }
5515 public override void Emit (EmitContext ec)
5517 Variable.EmitInstance (ec);
5521 public void EmitLoadAddress (EmitContext ec)
5523 Variable.EmitInstance (ec);
5524 Variable.EmitAddressOf (ec);
5527 public void Store (EmitContext ec, Expression right_side)
5529 Variable.EmitInstance (ec);
5530 right_side.Emit (ec);
5531 Variable.EmitAssign (ec);
5534 public void EmitThis (EmitContext ec)
5536 Variable.EmitInstance (ec);
5539 public void EmitStore (EmitContext ec)
5541 Variable.EmitAssign (ec);
5544 public void AddressOf (EmitContext ec, AddressOp mode)
5546 EmitLoadAddress (ec);
5551 /// Handles `var' contextual keyword; var becomes a keyword only
5552 /// if no type called var exists in a variable scope
5554 public class VarExpr : SimpleName
5556 // Used for error reporting only
5557 ArrayList initializer;
5559 public VarExpr (Location loc)
5564 public ArrayList VariableInitializer {
5566 this.initializer = value;
5570 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5573 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
5575 type = right_side.Type;
5576 if (type == TypeManager.null_type || type == TypeManager.void_type || type == TypeManager.anonymous_method_type) {
5577 Report.Error (815, loc, "An implicitly typed local variable declaration cannot be initialized with `{0}'",
5578 right_side.GetSignatureForError ());
5582 eclass = ExprClass.Variable;
5586 protected override void Error_TypeOrNamespaceNotFound (IResolveContext ec)
5588 Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");
5591 public override TypeExpr ResolveAsContextualType (IResolveContext rc, bool silent)
5593 TypeExpr te = base.ResolveAsContextualType (rc, true);
5597 if (initializer == null)
5600 if (initializer.Count > 1) {
5601 Location loc = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [1]).Location;
5602 Report.Error (819, loc, "An implicitly typed local variable declaration cannot include multiple declarators");
5607 Expression variable_initializer = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [0]).expression_or_array_initializer;
5608 if (variable_initializer == null) {
5609 Report.Error (818, loc, "An implicitly typed local variable declarator must include an initializer");