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 CreateExpressionTree (EmitContext ec)
1992 // This has no expresion tree representation
1996 public override Expression DoResolve (EmitContext ec)
1998 // This should never be invoked, we are born in fully
1999 // initialized state.
2004 public override void Emit (EmitContext ec)
2013 public Type UnderlyingType {
2014 get { return child.Type; }
2019 /// This kind of cast is used to encapsulate a child and cast it
2020 /// to the class requested
2022 public class ClassCast : EmptyCast {
2023 public ClassCast (Expression child, Type return_type)
2024 : base (child, return_type)
2029 public override Expression DoResolve (EmitContext ec)
2031 // This should never be invoked, we are born in fully
2032 // initialized state.
2037 public override void Emit (EmitContext ec)
2041 if (TypeManager.IsGenericParameter (child.Type))
2042 ec.ig.Emit (OpCodes.Box, child.Type);
2045 if (type.IsGenericParameter)
2046 ec.ig.Emit (OpCodes.Unbox_Any, type);
2049 ec.ig.Emit (OpCodes.Castclass, type);
2054 /// SimpleName expressions are formed of a single word and only happen at the beginning
2055 /// of a dotted-name.
2057 public class SimpleName : Expression {
2058 public readonly string Name;
2059 public readonly TypeArguments Arguments;
2062 public SimpleName (string name, Location l)
2068 public SimpleName (string name, TypeArguments args, Location l)
2075 public SimpleName (string name, TypeParameter[] type_params, Location l)
2080 Arguments = new TypeArguments (l);
2081 foreach (TypeParameter type_param in type_params)
2082 Arguments.Add (new TypeParameterExpr (type_param, l));
2085 public static string RemoveGenericArity (string name)
2088 StringBuilder sb = null;
2090 int pos = name.IndexOf ('`', start);
2095 sb.Append (name.Substring (start));
2100 sb = new StringBuilder ();
2101 sb.Append (name.Substring (start, pos-start));
2104 while ((pos < name.Length) && Char.IsNumber (name [pos]))
2108 } while (start < name.Length);
2110 return sb.ToString ();
2113 public SimpleName GetMethodGroup ()
2115 return new SimpleName (RemoveGenericArity (Name), Arguments, loc);
2118 public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
2120 if (ec.IsInFieldInitializer)
2121 Report.Error (236, l,
2122 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2126 120, l, "`{0}': An object reference is required for the nonstatic field, method or property",
2130 public bool IdenticalNameAndTypeName (EmitContext ec, Expression resolved_to, Location loc)
2132 return resolved_to != null && resolved_to.Type != null &&
2133 resolved_to.Type.Name == Name &&
2134 (ec.DeclContainer.LookupNamespaceOrType (Name, loc, /* ignore_cs0104 = */ true) != null);
2137 public override Expression DoResolve (EmitContext ec)
2139 return SimpleNameResolve (ec, null, false);
2142 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
2144 return SimpleNameResolve (ec, right_side, false);
2148 public Expression DoResolve (EmitContext ec, bool intermediate)
2150 return SimpleNameResolve (ec, null, intermediate);
2153 static bool IsNestedChild (Type t, Type parent)
2155 while (parent != null) {
2156 if (TypeManager.IsNestedChildOf (t, TypeManager.DropGenericTypeArguments (parent)))
2159 parent = parent.BaseType;
2165 FullNamedExpression ResolveNested (IResolveContext ec, Type t)
2167 if (!TypeManager.IsGenericTypeDefinition (t) && !TypeManager.IsGenericType (t))
2170 DeclSpace ds = ec.DeclContainer;
2171 while (ds != null && !IsNestedChild (t, ds.TypeBuilder))
2177 Type[] gen_params = TypeManager.GetTypeArguments (t);
2179 int arg_count = Arguments != null ? Arguments.Count : 0;
2181 for (; (ds != null) && ds.IsGeneric; ds = ds.Parent) {
2182 if (arg_count + ds.CountTypeParameters == gen_params.Length) {
2183 TypeArguments new_args = new TypeArguments (loc);
2184 foreach (TypeParameter param in ds.TypeParameters)
2185 new_args.Add (new TypeParameterExpr (param, loc));
2187 if (Arguments != null)
2188 new_args.Add (Arguments);
2190 return new ConstructedType (t, new_args, loc);
2197 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2199 FullNamedExpression fne = ec.GenericDeclContainer.LookupGeneric (Name, loc);
2201 return fne.ResolveAsTypeStep (ec, silent);
2203 int errors = Report.Errors;
2204 fne = ec.DeclContainer.LookupNamespaceOrType (Name, loc, /*ignore_cs0104=*/ false);
2207 if (fne.Type == null)
2210 FullNamedExpression nested = ResolveNested (ec, fne.Type);
2212 return nested.ResolveAsTypeStep (ec, false);
2214 if (Arguments != null) {
2215 ConstructedType ct = new ConstructedType (fne, Arguments, loc);
2216 return ct.ResolveAsTypeStep (ec, false);
2222 if (silent || errors != Report.Errors)
2225 Error_TypeOrNamespaceNotFound (ec);
2229 protected virtual void Error_TypeOrNamespaceNotFound (IResolveContext ec)
2231 MemberCore mc = ec.DeclContainer.GetDefinition (Name);
2233 Error_UnexpectedKind (ec.DeclContainer, "type", GetMemberType (mc), loc);
2237 string ns = ec.DeclContainer.NamespaceEntry.NS.Name;
2238 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2239 foreach (Assembly a in RootNamespace.Global.Assemblies) {
2240 Type type = a.GetType (fullname);
2242 Report.SymbolRelatedToPreviousError (type);
2243 Expression.ErrorIsInaccesible (loc, TypeManager.CSharpName (type));
2248 Type t = ec.DeclContainer.LookupAnyGeneric (Name);
2250 Namespace.Error_InvalidNumberOfTypeArguments (t, loc);
2254 if (Arguments != null) {
2255 FullNamedExpression retval = ec.DeclContainer.LookupNamespaceOrType (SimpleName.RemoveGenericArity (Name), loc, true);
2256 if (retval != null) {
2257 Namespace.Error_TypeArgumentsCannotBeUsed (retval.Type, loc);
2262 NamespaceEntry.Error_NamespaceNotFound (loc, Name);
2265 // TODO: I am still not convinced about this. If someone else will need it
2266 // implement this as virtual property in MemberCore hierarchy
2267 public static string GetMemberType (MemberCore mc)
2273 if (mc is FieldBase)
2275 if (mc is MethodCore)
2277 if (mc is EnumMember)
2285 Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2291 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2297 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2304 /// 7.5.2: Simple Names.
2306 /// Local Variables and Parameters are handled at
2307 /// parse time, so they never occur as SimpleNames.
2309 /// The `intermediate' flag is used by MemberAccess only
2310 /// and it is used to inform us that it is ok for us to
2311 /// avoid the static check, because MemberAccess might end
2312 /// up resolving the Name as a Type name and the access as
2313 /// a static type access.
2315 /// ie: Type Type; .... { Type.GetType (""); }
2317 /// Type is both an instance variable and a Type; Type.GetType
2318 /// is the static method not an instance method of type.
2320 Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2322 Expression e = null;
2325 // Stage 1: Performed by the parser (binding to locals or parameters).
2327 Block current_block = ec.CurrentBlock;
2328 if (current_block != null){
2329 LocalInfo vi = current_block.GetLocalInfo (Name);
2331 if (Arguments != null) {
2332 Report.Error (307, loc,
2333 "The variable `{0}' cannot be used with type arguments",
2338 LocalVariableReference var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2339 if (right_side != null) {
2340 return var.ResolveLValue (ec, right_side, loc);
2342 ResolveFlags rf = ResolveFlags.VariableOrValue;
2344 rf |= ResolveFlags.DisableFlowAnalysis;
2345 return var.Resolve (ec, rf);
2349 ParameterReference pref = current_block.Toplevel.GetParameterReference (Name, loc);
2351 if (Arguments != null) {
2352 Report.Error (307, loc,
2353 "The variable `{0}' cannot be used with type arguments",
2358 if (right_side != null)
2359 return pref.ResolveLValue (ec, right_side, loc);
2361 return pref.Resolve (ec);
2364 Expression expr = current_block.Toplevel.GetTransparentIdentifier (Name);
2366 if (right_side != null)
2367 return expr.ResolveLValue (ec, right_side, loc);
2368 return expr.Resolve (ec);
2373 // Stage 2: Lookup members
2376 Type almost_matched_type = null;
2377 ArrayList almost_matched = null;
2378 for (DeclSpace lookup_ds = ec.DeclContainer; lookup_ds != null; lookup_ds = lookup_ds.Parent) {
2379 // either RootDeclSpace or GenericMethod
2380 if (lookup_ds.TypeBuilder == null)
2383 e = MemberLookup (ec.ContainerType, lookup_ds.TypeBuilder, Name, loc);
2385 if (e is PropertyExpr) {
2386 // since TypeManager.MemberLookup doesn't know if we're doing a lvalue access or not,
2387 // it doesn't know which accessor to check permissions against
2388 if (((PropertyExpr) e).IsAccessibleFrom (ec.ContainerType, right_side != null))
2390 } else if (e is EventExpr) {
2391 if (((EventExpr) e).IsAccessibleFrom (ec.ContainerType))
2399 if (almost_matched == null && almost_matched_members.Count > 0) {
2400 almost_matched_type = lookup_ds.TypeBuilder;
2401 almost_matched = (ArrayList) almost_matched_members.Clone ();
2406 if (almost_matched == null && almost_matched_members.Count > 0) {
2407 almost_matched_type = ec.ContainerType;
2408 almost_matched = (ArrayList) almost_matched_members.Clone ();
2410 e = ResolveAsTypeStep (ec, true);
2414 if (current_block != null) {
2415 IKnownVariable ikv = current_block.Explicit.GetKnownVariable (Name);
2417 LocalInfo li = ikv as LocalInfo;
2418 // Supress CS0219 warning
2422 Error_VariableIsUsedBeforeItIsDeclared (Name);
2427 if (almost_matched != null)
2428 almost_matched_members = almost_matched;
2429 if (almost_matched_type == null)
2430 almost_matched_type = ec.ContainerType;
2431 Error_MemberLookupFailed (ec.ContainerType, null, almost_matched_type, Name,
2432 ec.DeclContainer.Name, AllMemberTypes, AllBindingFlags);
2436 if (e is TypeExpr) {
2437 if (Arguments == null)
2440 ConstructedType ct = new ConstructedType (
2441 (FullNamedExpression) e, Arguments, loc);
2442 return ct.ResolveAsTypeStep (ec, false);
2445 if (e is MemberExpr) {
2446 MemberExpr me = (MemberExpr) e;
2449 if (me.IsInstance) {
2450 if (ec.IsStatic || ec.IsInFieldInitializer) {
2452 // Note that an MemberExpr can be both IsInstance and IsStatic.
2453 // An unresolved MethodGroupExpr can contain both kinds of methods
2454 // and each predicate is true if the MethodGroupExpr contains
2455 // at least one of that kind of method.
2459 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2460 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2465 // Pass the buck to MemberAccess and Invocation.
2467 left = EmptyExpression.Null;
2469 left = ec.GetThis (loc);
2472 left = new TypeExpression (ec.ContainerType, loc);
2475 me = me.ResolveMemberAccess (ec, left, loc, null);
2479 if (Arguments != null) {
2480 Arguments.Resolve (ec);
2481 me.SetTypeArguments (Arguments);
2484 if (!me.IsStatic && (me.InstanceExpression != null) &&
2485 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2486 me.InstanceExpression.Type != me.DeclaringType &&
2487 !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2488 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2489 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2490 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2494 return (right_side != null)
2495 ? me.DoResolveLValue (ec, right_side)
2496 : me.DoResolve (ec);
2502 public override void Emit (EmitContext ec)
2504 throw new InternalErrorException ("The resolve phase was not executed");
2507 public override string ToString ()
2512 public override string GetSignatureForError ()
2514 if (Arguments != null) {
2515 return TypeManager.RemoveGenericArity (Name) + "<" +
2516 Arguments.GetSignatureForError () + ">";
2522 protected override void CloneTo (CloneContext clonectx, Expression target)
2524 // CloneTo: Nothing, we do not keep any state on this expression
2529 /// Represents a namespace or a type. The name of the class was inspired by
2530 /// section 10.8.1 (Fully Qualified Names).
2532 public abstract class FullNamedExpression : Expression {
2533 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2538 public abstract string FullName {
2544 /// Expression that evaluates to a type
2546 public abstract class TypeExpr : FullNamedExpression {
2547 override public FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2549 TypeExpr t = DoResolveAsTypeStep (ec);
2553 eclass = ExprClass.Type;
2557 override public Expression DoResolve (EmitContext ec)
2559 return ResolveAsTypeTerminal (ec, false);
2562 override public void Emit (EmitContext ec)
2564 throw new Exception ("Should never be called");
2567 public virtual bool CheckAccessLevel (DeclSpace ds)
2569 return ds.CheckAccessLevel (Type);
2572 public virtual bool AsAccessible (DeclSpace ds)
2574 return ds.IsAccessibleAs (Type);
2577 public virtual bool IsClass {
2578 get { return Type.IsClass; }
2581 public virtual bool IsValueType {
2582 get { return Type.IsValueType; }
2585 public virtual bool IsInterface {
2586 get { return Type.IsInterface; }
2589 public virtual bool IsSealed {
2590 get { return Type.IsSealed; }
2593 public virtual bool CanInheritFrom ()
2595 if (Type == TypeManager.enum_type ||
2596 (Type == TypeManager.value_type && RootContext.StdLib) ||
2597 Type == TypeManager.multicast_delegate_type ||
2598 Type == TypeManager.delegate_type ||
2599 Type == TypeManager.array_type)
2605 protected abstract TypeExpr DoResolveAsTypeStep (IResolveContext ec);
2607 public abstract string Name {
2611 public override bool Equals (object obj)
2613 TypeExpr tobj = obj as TypeExpr;
2617 return Type == tobj.Type;
2620 public override int GetHashCode ()
2622 return Type.GetHashCode ();
2625 public override string ToString ()
2632 /// Fully resolved Expression that already evaluated to a type
2634 public class TypeExpression : TypeExpr {
2635 public TypeExpression (Type t, Location l)
2638 eclass = ExprClass.Type;
2642 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2647 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2652 public override string Name {
2653 get { return Type.ToString (); }
2656 public override string FullName {
2657 get { return Type.FullName; }
2662 /// Used to create types from a fully qualified name. These are just used
2663 /// by the parser to setup the core types. A TypeLookupExpression is always
2664 /// classified as a type.
2666 public sealed class TypeLookupExpression : TypeExpr {
2667 readonly string name;
2669 public TypeLookupExpression (string name)
2672 eclass = ExprClass.Type;
2675 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2677 // It's null for corlib compilation only
2679 return DoResolveAsTypeStep (ec);
2684 private class UnexpectedType
2688 // This performes recursive type lookup, providing support for generic types.
2689 // For example, given the type:
2691 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]]
2693 // The types will be checked in the following order:
2696 // System.Collections |
2697 // System.Collections.Generic |
2699 // System | recursive call 1 |
2700 // System.Int32 _| | main method call
2702 // System | recursive call 2 |
2703 // System.String _| |
2705 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]] _|
2707 private Type TypeLookup (IResolveContext ec, string name)
2712 FullNamedExpression resolved = null;
2714 Type recursive_type = null;
2715 while (index < name.Length) {
2716 if (name[index] == '[') {
2721 if (name[index] == '[')
2723 else if (name[index] == ']')
2725 } while (braces > 0);
2726 recursive_type = TypeLookup (ec, name.Substring (open + 1, index - open - 1));
2727 if (recursive_type == null || (recursive_type == typeof(UnexpectedType)))
2728 return recursive_type;
2731 if (name[index] == ',')
2733 else if ((name[index] == '.' && !done) || (index == name.Length && name[0] != '[')) {
2734 string substring = name.Substring(dot, index - dot);
2736 if (resolved == null)
2737 resolved = RootNamespace.Global.Lookup (ec.DeclContainer, substring, Location.Null);
2738 else if (resolved is Namespace)
2739 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
2740 else if (type != null)
2741 type = TypeManager.GetNestedType (type, substring);
2745 if (resolved == null)
2747 else if (type == null && resolved is TypeExpr)
2748 type = resolved.Type;
2755 if (name[0] != '[') {
2756 string substring = name.Substring(dot, index - dot);
2759 return TypeManager.GetNestedType (type, substring);
2761 if (resolved != null) {
2762 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
2763 if (resolved is TypeExpr)
2764 return resolved.Type;
2766 if (resolved == null)
2769 resolved.Error_UnexpectedKind (ec.DeclContainer, "type", loc);
2770 return typeof (UnexpectedType);
2776 return recursive_type;
2779 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2781 Type t = TypeLookup (ec, name);
2783 NamespaceEntry.Error_NamespaceNotFound (loc, name);
2786 if (t == typeof(UnexpectedType))
2792 public override string Name {
2793 get { return name; }
2796 public override string FullName {
2797 get { return name; }
2800 protected override void CloneTo (CloneContext clonectx, Expression target)
2802 // CloneTo: Nothing, we do not keep any state on this expression
2805 public override string GetSignatureForError ()
2808 return TypeManager.CSharpName (name);
2810 return base.GetSignatureForError ();
2815 /// Represents an "unbound generic type", ie. typeof (Foo<>).
2818 public class UnboundTypeExpression : TypeExpr
2822 public UnboundTypeExpression (MemberName name, Location l)
2828 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2831 if (name.Left != null) {
2832 Expression lexpr = name.Left.GetTypeExpression ();
2833 expr = new MemberAccess (lexpr, name.Basename);
2835 expr = new SimpleName (name.Basename, loc);
2838 FullNamedExpression fne = expr.ResolveAsTypeStep (ec, false);
2843 return new TypeExpression (type, loc);
2846 public override string Name {
2847 get { return name.FullName; }
2850 public override string FullName {
2851 get { return name.FullName; }
2855 public class TypeAliasExpression : TypeExpr {
2856 FullNamedExpression alias;
2861 public TypeAliasExpression (FullNamedExpression alias, TypeArguments args, Location l)
2867 eclass = ExprClass.Type;
2869 name = alias.FullName + "<" + args.ToString () + ">";
2871 name = alias.FullName;
2874 public override string Name {
2875 get { return alias.FullName; }
2878 public override string FullName {
2879 get { return name; }
2882 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2884 texpr = alias.ResolveAsTypeTerminal (ec, false);
2888 Type type = texpr.Type;
2889 int num_args = TypeManager.GetNumberOfTypeArguments (type);
2892 if (num_args == 0) {
2893 Report.Error (308, loc,
2894 "The non-generic type `{0}' cannot " +
2895 "be used with type arguments.",
2896 TypeManager.CSharpName (type));
2900 ConstructedType ctype = new ConstructedType (type, args, loc);
2901 return ctype.ResolveAsTypeTerminal (ec, false);
2902 } else if (num_args > 0) {
2903 Report.Error (305, loc,
2904 "Using the generic type `{0}' " +
2905 "requires {1} type arguments",
2906 TypeManager.CSharpName (type), num_args.ToString ());
2913 public override bool CheckAccessLevel (DeclSpace ds)
2915 return texpr.CheckAccessLevel (ds);
2918 public override bool AsAccessible (DeclSpace ds)
2920 return texpr.AsAccessible (ds);
2923 public override bool IsClass {
2924 get { return texpr.IsClass; }
2927 public override bool IsValueType {
2928 get { return texpr.IsValueType; }
2931 public override bool IsInterface {
2932 get { return texpr.IsInterface; }
2935 public override bool IsSealed {
2936 get { return texpr.IsSealed; }
2941 /// This class denotes an expression which evaluates to a member
2942 /// of a struct or a class.
2944 public abstract class MemberExpr : Expression
2946 protected bool is_base;
2949 /// The name of this member.
2951 public abstract string Name {
2956 // When base.member is used
2958 public bool IsBase {
2959 get { return is_base; }
2960 set { is_base = value; }
2964 /// Whether this is an instance member.
2966 public abstract bool IsInstance {
2971 /// Whether this is a static member.
2973 public abstract bool IsStatic {
2978 /// The type which declares this member.
2980 public abstract Type DeclaringType {
2985 /// The instance expression associated with this member, if it's a
2986 /// non-static member.
2988 public Expression InstanceExpression;
2990 public static void error176 (Location loc, string name)
2992 Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
2993 "with an instance reference, qualify it with a type name instead", name);
2996 // TODO: possible optimalization
2997 // Cache resolved constant result in FieldBuilder <-> expression map
2998 public virtual MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
2999 SimpleName original)
3003 // original == null || original.Resolve (...) ==> left
3006 if (left is TypeExpr) {
3007 left = left.ResolveAsTypeTerminal (ec, true);
3012 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3020 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3023 return ResolveExtensionMemberAccess (left);
3026 InstanceExpression = left;
3030 protected virtual MemberExpr ResolveExtensionMemberAccess (Expression left)
3032 error176 (loc, GetSignatureForError ());
3036 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3041 if (InstanceExpression == EmptyExpression.Null) {
3042 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3046 if (InstanceExpression.Type.IsValueType) {
3047 if (InstanceExpression is IMemoryLocation) {
3048 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
3050 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
3051 InstanceExpression.Emit (ec);
3053 t.AddressOf (ec, AddressOp.Store);
3056 InstanceExpression.Emit (ec);
3058 if (prepare_for_load)
3059 ec.ig.Emit (OpCodes.Dup);
3062 public virtual void SetTypeArguments (TypeArguments ta)
3064 // TODO: need to get correct member type
3065 Report.Error (307, loc, "The property `{0}' cannot be used with type arguments",
3066 GetSignatureForError ());
3071 /// Represents group of extension methods
3073 public class ExtensionMethodGroupExpr : MethodGroupExpr
3075 readonly NamespaceEntry namespace_entry;
3076 public Expression ExtensionExpression;
3077 Argument extension_argument;
3079 public ExtensionMethodGroupExpr (ArrayList list, NamespaceEntry n, Type extensionType, Location l)
3080 : base (list, extensionType, l)
3082 this.namespace_entry = n;
3085 public override bool IsStatic {
3086 get { return true; }
3089 public bool IsTopLevel {
3090 get { return namespace_entry == null; }
3093 public override void EmitArguments (EmitContext ec, ArrayList arguments)
3095 if (arguments == null)
3096 arguments = new ArrayList (1);
3097 arguments.Insert (0, extension_argument);
3098 base.EmitArguments (ec, arguments);
3101 public override void EmitCall (EmitContext ec, ArrayList arguments)
3103 if (arguments == null)
3104 arguments = new ArrayList (1);
3105 arguments.Insert (0, extension_argument);
3106 base.EmitCall (ec, arguments);
3109 public override MethodGroupExpr OverloadResolve (EmitContext ec, ref ArrayList arguments, bool may_fail, Location loc)
3111 if (arguments == null)
3112 arguments = new ArrayList (1);
3114 arguments.Insert (0, new Argument (ExtensionExpression));
3115 MethodGroupExpr mg = ResolveOverloadExtensions (ec, arguments, namespace_entry, loc);
3117 // Store resolved argument and restore original arguments
3119 ((ExtensionMethodGroupExpr)mg).extension_argument = (Argument)arguments [0];
3120 arguments.RemoveAt (0);
3125 MethodGroupExpr ResolveOverloadExtensions (EmitContext ec, ArrayList arguments, NamespaceEntry ns, Location loc)
3127 // Use normal resolve rules
3128 MethodGroupExpr mg = base.OverloadResolve (ec, ref arguments, ns != null, loc);
3136 ExtensionMethodGroupExpr e = ns.LookupExtensionMethod (type, null, Name);
3138 return base.OverloadResolve (ec, ref arguments, false, loc);
3140 e.ExtensionExpression = ExtensionExpression;
3141 return e.ResolveOverloadExtensions (ec, arguments, e.namespace_entry, loc);
3146 /// MethodGroupExpr represents a group of method candidates which
3147 /// can be resolved to the best method overload
3149 public class MethodGroupExpr : MemberExpr
3151 public interface IErrorHandler
3153 bool NoExactMatch (EmitContext ec, MethodBase method);
3156 public IErrorHandler CustomErrorHandler;
3157 public MethodBase [] Methods;
3158 MethodBase best_candidate;
3159 // TODO: make private
3160 public TypeArguments type_arguments;
3161 bool identical_type_name;
3164 public MethodGroupExpr (MemberInfo [] mi, Type type, Location l)
3167 Methods = new MethodBase [mi.Length];
3168 mi.CopyTo (Methods, 0);
3171 public MethodGroupExpr (ArrayList list, Type type, Location l)
3175 Methods = (MethodBase[])list.ToArray (typeof (MethodBase));
3177 foreach (MemberInfo m in list){
3178 if (!(m is MethodBase)){
3179 Console.WriteLine ("Name " + m.Name);
3180 Console.WriteLine ("Found a: " + m.GetType ().FullName);
3189 protected MethodGroupExpr (Type type, Location loc)
3192 eclass = ExprClass.MethodGroup;
3196 public override Type DeclaringType {
3199 // We assume that the top-level type is in the end
3201 return Methods [Methods.Length - 1].DeclaringType;
3202 //return Methods [0].DeclaringType;
3206 public Type DelegateType {
3208 delegate_type = value;
3212 public bool IdenticalTypeName {
3214 return identical_type_name;
3218 identical_type_name = value;
3222 public override string GetSignatureForError ()
3224 if (best_candidate != null)
3225 return TypeManager.CSharpSignature (best_candidate);
3227 return TypeManager.CSharpSignature (Methods [0]);
3230 public override string Name {
3232 return Methods [0].Name;
3236 public override bool IsInstance {
3238 if (best_candidate != null)
3239 return !best_candidate.IsStatic;
3241 foreach (MethodBase mb in Methods)
3249 public override bool IsStatic {
3251 if (best_candidate != null)
3252 return best_candidate.IsStatic;
3254 foreach (MethodBase mb in Methods)
3262 public static explicit operator ConstructorInfo (MethodGroupExpr mg)
3264 return (ConstructorInfo)mg.best_candidate;
3267 public static explicit operator MethodInfo (MethodGroupExpr mg)
3269 return (MethodInfo)mg.best_candidate;
3273 // 7.4.3.3 Better conversion from expression
3274 // Returns : 1 if a->p is better,
3275 // 2 if a->q is better,
3276 // 0 if neither is better
3278 static int BetterExpressionConversion (EmitContext ec, Argument a, Type p, Type q)
3280 Type argument_type = TypeManager.TypeToCoreType (a.Type);
3281 if (argument_type == TypeManager.anonymous_method_type && RootContext.Version > LanguageVersion.ISO_2) {
3283 // Uwrap delegate from Expression<T>
3285 if (TypeManager.DropGenericTypeArguments (p) == TypeManager.expression_type) {
3286 p = TypeManager.GetTypeArguments (p) [0];
3287 q = TypeManager.GetTypeArguments (q) [0];
3289 p = Delegate.GetInvokeMethod (null, p).ReturnType;
3290 q = Delegate.GetInvokeMethod (null, q).ReturnType;
3292 if (argument_type == p)
3295 if (argument_type == q)
3299 return BetterTypeConversion (ec, p, q);
3303 // 7.4.3.4 Better conversion from type
3305 public static int BetterTypeConversion (EmitContext ec, Type p, Type q)
3307 if (p == null || q == null)
3308 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3310 if (p == TypeManager.int32_type) {
3311 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3313 } else if (p == TypeManager.int64_type) {
3314 if (q == TypeManager.uint64_type)
3316 } else if (p == TypeManager.sbyte_type) {
3317 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3318 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3320 } else if (p == TypeManager.short_type) {
3321 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3322 q == TypeManager.uint64_type)
3326 if (q == TypeManager.int32_type) {
3327 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3329 } if (q == TypeManager.int64_type) {
3330 if (p == TypeManager.uint64_type)
3332 } else if (q == TypeManager.sbyte_type) {
3333 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3334 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3336 } if (q == TypeManager.short_type) {
3337 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3338 p == TypeManager.uint64_type)
3342 // TODO: this is expensive
3343 Expression p_tmp = new EmptyExpression (p);
3344 Expression q_tmp = new EmptyExpression (q);
3346 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3347 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3349 if (p_to_q && !q_to_p)
3352 if (q_to_p && !p_to_q)
3359 /// Determines "Better function" between candidate
3360 /// and the current best match
3363 /// Returns a boolean indicating :
3364 /// false if candidate ain't better
3365 /// true if candidate is better than the current best match
3367 static bool BetterFunction (EmitContext ec, ArrayList args, int argument_count,
3368 MethodBase candidate, bool candidate_params,
3369 MethodBase best, bool best_params)
3371 ParameterData candidate_pd = TypeManager.GetParameterData (candidate);
3372 ParameterData best_pd = TypeManager.GetParameterData (best);
3374 bool better_at_least_one = false;
3376 for (int j = 0, c_idx = 0, b_idx = 0; j < argument_count; ++j, ++c_idx, ++b_idx)
3378 Argument a = (Argument) args [j];
3380 Type ct = TypeManager.TypeToCoreType (candidate_pd.ParameterType (c_idx));
3381 Type bt = TypeManager.TypeToCoreType (best_pd.ParameterType (b_idx));
3383 if (candidate_params && candidate_pd.ParameterModifier (c_idx) == Parameter.Modifier.PARAMS)
3385 ct = TypeManager.GetElementType (ct);
3389 if (best_params && best_pd.ParameterModifier (b_idx) == Parameter.Modifier.PARAMS)
3391 bt = TypeManager.GetElementType (bt);
3399 int result = BetterExpressionConversion (ec, a, ct, bt);
3401 // for each argument, the conversion to 'ct' should be no worse than
3402 // the conversion to 'bt'.
3406 // for at least one argument, the conversion to 'ct' should be better than
3407 // the conversion to 'bt'.
3409 better_at_least_one = true;
3412 if (better_at_least_one)
3416 // This handles the case
3418 // Add (float f1, float f2, float f3);
3419 // Add (params decimal [] foo);
3421 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3422 // first candidate would've chosen as better.
3428 // The two methods have equal parameter types. Now apply tie-breaking rules
3430 if (TypeManager.IsGenericMethod (best) && !TypeManager.IsGenericMethod (candidate))
3432 if (!TypeManager.IsGenericMethod (best) && TypeManager.IsGenericMethod (candidate))
3436 // This handles the following cases:
3438 // Trim () is better than Trim (params char[] chars)
3439 // Concat (string s1, string s2, string s3) is better than
3440 // Concat (string s1, params string [] srest)
3441 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3443 if (!candidate_params && best_params)
3445 if (candidate_params && !best_params)
3448 int candidate_param_count = candidate_pd.Count;
3449 int best_param_count = best_pd.Count;
3451 if (candidate_param_count != best_param_count)
3452 // can only happen if (candidate_params && best_params)
3453 return candidate_param_count > best_param_count;
3456 // now, both methods have the same number of parameters, and the parameters have the same types
3457 // Pick the "more specific" signature
3460 MethodBase orig_candidate = TypeManager.DropGenericMethodArguments (candidate);
3461 MethodBase orig_best = TypeManager.DropGenericMethodArguments (best);
3463 ParameterData orig_candidate_pd = TypeManager.GetParameterData (orig_candidate);
3464 ParameterData orig_best_pd = TypeManager.GetParameterData (orig_best);
3466 bool specific_at_least_once = false;
3467 for (int j = 0; j < candidate_param_count; ++j)
3469 Type ct = TypeManager.TypeToCoreType (orig_candidate_pd.ParameterType (j));
3470 Type bt = TypeManager.TypeToCoreType (orig_best_pd.ParameterType (j));
3473 Type specific = MoreSpecific (ct, bt);
3477 specific_at_least_once = true;
3480 if (specific_at_least_once)
3483 // FIXME: handle lifted operators
3489 protected override MemberExpr ResolveExtensionMemberAccess (Expression left)
3492 return base.ResolveExtensionMemberAccess (left);
3495 // When left side is an expression and at least one candidate method is
3496 // static, it can be extension method
3498 InstanceExpression = left;
3502 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3503 SimpleName original)
3505 if (!(left is TypeExpr) &&
3506 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3507 IdenticalTypeName = true;
3509 return base.ResolveMemberAccess (ec, left, loc, original);
3512 public override Expression CreateExpressionTree (EmitContext ec)
3514 return new Cast (new TypeExpression (typeof (MethodInfo), loc),
3515 new TypeOfMethod ((MethodInfo)best_candidate, loc));
3518 override public Expression DoResolve (EmitContext ec)
3520 if (InstanceExpression != null) {
3521 InstanceExpression = InstanceExpression.DoResolve (ec);
3522 if (InstanceExpression == null)
3529 public void ReportUsageError ()
3531 Report.Error (654, loc, "Method `" + DeclaringType + "." +
3532 Name + "()' is referenced without parentheses");
3535 override public void Emit (EmitContext ec)
3537 ReportUsageError ();
3540 public virtual void EmitArguments (EmitContext ec, ArrayList arguments)
3542 Invocation.EmitArguments (ec, arguments, false, null);
3545 public virtual void EmitCall (EmitContext ec, ArrayList arguments)
3547 Invocation.EmitCall (ec, IsBase, InstanceExpression, best_candidate, arguments, loc);
3550 protected virtual void Error_InvalidArguments (EmitContext ec, Location loc, int idx, MethodBase method,
3551 Argument a, ParameterData expected_par, Type paramType)
3553 if (a is CollectionElementInitializer.ElementInitializerArgument) {
3554 Report.SymbolRelatedToPreviousError (method);
3555 if ((expected_par.ParameterModifier (idx) & Parameter.Modifier.ISBYREF) != 0) {
3556 Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
3557 TypeManager.CSharpSignature (method));
3560 Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
3561 TypeManager.CSharpSignature (method));
3562 } else if (delegate_type == null) {
3563 Report.SymbolRelatedToPreviousError (method);
3564 Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
3565 TypeManager.CSharpSignature (method));
3567 Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
3568 TypeManager.CSharpName (delegate_type));
3570 Parameter.Modifier mod = expected_par.ParameterModifier (idx);
3572 string index = (idx + 1).ToString ();
3573 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
3574 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
3575 if ((mod & Parameter.Modifier.ISBYREF) == 0)
3576 Report.Error (1615, loc, "Argument `{0}' should not be passed with the `{1}' keyword",
3577 index, Parameter.GetModifierSignature (a.Modifier));
3579 Report.Error (1620, loc, "Argument `{0}' must be passed with the `{1}' keyword",
3580 index, Parameter.GetModifierSignature (mod));
3582 string p1 = a.GetSignatureForError ();
3583 string p2 = TypeManager.CSharpName (paramType);
3586 Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
3587 Report.SymbolRelatedToPreviousError (a.Expr.Type);
3588 Report.SymbolRelatedToPreviousError (paramType);
3590 Report.Error (1503, loc, "Argument {0}: Cannot convert type `{1}' to `{2}'", index, p1, p2);
3594 protected virtual int GetApplicableParametersCount (MethodBase method, ParameterData parameters)
3596 return parameters.Count;
3599 public static bool IsAncestralType (Type first_type, Type second_type)
3601 return first_type != second_type &&
3602 (TypeManager.IsSubclassOf (second_type, first_type) ||
3603 TypeManager.ImplementsInterface (second_type, first_type));
3607 /// Determines if the candidate method is applicable (section 14.4.2.1)
3608 /// to the given set of arguments
3609 /// A return value rates candidate method compatibility,
3610 /// 0 = the best, int.MaxValue = the worst
3612 public int IsApplicable (EmitContext ec,
3613 ArrayList arguments, int arg_count, ref MethodBase method, ref bool params_expanded_form)
3615 MethodBase candidate = method;
3617 ParameterData pd = TypeManager.GetParameterData (candidate);
3618 int param_count = GetApplicableParametersCount (candidate, pd);
3620 if (arg_count != param_count) {
3622 return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
3623 if (arg_count < param_count - 1)
3624 return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
3629 // 1. Handle generic method using type arguments when specified or type inference
3631 if (TypeManager.IsGenericMethod (candidate)) {
3632 if (type_arguments != null) {
3633 Type [] g_args = candidate.GetGenericArguments ();
3634 if (g_args.Length != type_arguments.Count)
3635 return int.MaxValue - 20000 + Math.Abs (type_arguments.Count - g_args.Length);
3637 // TODO: Don't create new method, create Parameters only
3638 method = ((MethodInfo) candidate).MakeGenericMethod (type_arguments.Arguments);
3640 pd = TypeManager.GetParameterData (candidate);
3642 int score = TypeManager.InferTypeArguments (ec, arguments, ref candidate);
3644 return score - 20000;
3646 if (TypeManager.IsGenericMethodDefinition (candidate))
3647 throw new InternalErrorException ("A generic method `{0}' definition took part in overload resolution",
3648 TypeManager.CSharpSignature (candidate));
3650 pd = TypeManager.GetParameterData (candidate);
3653 if (type_arguments != null)
3654 return int.MaxValue - 15000;
3659 // 2. Each argument has to be implicitly convertible to method parameter
3662 Parameter.Modifier p_mod = 0;
3664 for (int i = 0; i < arg_count; i++) {
3665 Argument a = (Argument) arguments [i];
3666 Parameter.Modifier a_mod = a.Modifier &
3667 ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3669 if (p_mod != Parameter.Modifier.PARAMS) {
3670 p_mod = pd.ParameterModifier (i) & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3672 if (p_mod == Parameter.Modifier.ARGLIST) {
3673 if (a.Type == TypeManager.runtime_argument_handle_type)
3679 pt = pd.ParameterType (i);
3681 params_expanded_form = true;
3685 if (!params_expanded_form)
3686 score = IsArgumentCompatible (ec, a_mod, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
3688 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0) {
3689 // It can be applicable in expanded form
3690 score = IsArgumentCompatible (ec, a_mod, a, 0, pt.GetElementType ());
3692 params_expanded_form = true;
3696 if (params_expanded_form)
3698 return (arg_count - i) * 2 + score;
3702 if (arg_count != param_count)
3703 params_expanded_form = true;
3708 int IsArgumentCompatible (EmitContext ec, Parameter.Modifier arg_mod, Argument argument, Parameter.Modifier param_mod, Type parameter)
3711 // Types have to be identical when ref or out modifer is used
3713 if (arg_mod != 0 || param_mod != 0) {
3714 if (TypeManager.HasElementType (parameter))
3715 parameter = parameter.GetElementType ();
3717 Type a_type = argument.Type;
3718 if (TypeManager.HasElementType (a_type))
3719 a_type = a_type.GetElementType ();
3721 if (a_type != parameter)
3727 // FIXME: Kill this abomination (EmitContext.TempEc)
3728 EmitContext prevec = EmitContext.TempEc;
3729 EmitContext.TempEc = ec;
3731 if (delegate_type != null ?
3732 !Delegate.IsTypeCovariant (argument.Expr, parameter) :
3733 !Convert.ImplicitConversionExists (ec, argument.Expr, parameter))
3736 if (arg_mod != param_mod)
3740 EmitContext.TempEc = prevec;
3746 public static bool IsOverride (MethodBase cand_method, MethodBase base_method)
3748 if (!IsAncestralType (base_method.DeclaringType, cand_method.DeclaringType))
3751 ParameterData cand_pd = TypeManager.GetParameterData (cand_method);
3752 ParameterData base_pd = TypeManager.GetParameterData (base_method);
3754 if (cand_pd.Count != base_pd.Count)
3757 for (int j = 0; j < cand_pd.Count; ++j)
3759 Parameter.Modifier cm = cand_pd.ParameterModifier (j);
3760 Parameter.Modifier bm = base_pd.ParameterModifier (j);
3761 Type ct = TypeManager.TypeToCoreType (cand_pd.ParameterType (j));
3762 Type bt = TypeManager.TypeToCoreType (base_pd.ParameterType (j));
3764 if (cm != bm || ct != bt)
3771 public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2, Location loc)
3773 MemberInfo [] miset;
3774 MethodGroupExpr union;
3779 return (MethodGroupExpr) mg2;
3782 return (MethodGroupExpr) mg1;
3785 MethodGroupExpr left_set = null, right_set = null;
3786 int length1 = 0, length2 = 0;
3788 left_set = (MethodGroupExpr) mg1;
3789 length1 = left_set.Methods.Length;
3791 right_set = (MethodGroupExpr) mg2;
3792 length2 = right_set.Methods.Length;
3794 ArrayList common = new ArrayList ();
3796 foreach (MethodBase r in right_set.Methods){
3797 if (TypeManager.ArrayContainsMethod (left_set.Methods, r))
3801 miset = new MemberInfo [length1 + length2 - common.Count];
3802 left_set.Methods.CopyTo (miset, 0);
3806 foreach (MethodBase r in right_set.Methods) {
3807 if (!common.Contains (r))
3811 union = new MethodGroupExpr (miset, mg1.Type, loc);
3816 static Type MoreSpecific (Type p, Type q)
3818 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
3820 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
3823 if (TypeManager.HasElementType (p))
3825 Type pe = TypeManager.GetElementType (p);
3826 Type qe = TypeManager.GetElementType (q);
3827 Type specific = MoreSpecific (pe, qe);
3833 else if (TypeManager.IsGenericType (p))
3835 Type[] pargs = TypeManager.GetTypeArguments (p);
3836 Type[] qargs = TypeManager.GetTypeArguments (q);
3838 bool p_specific_at_least_once = false;
3839 bool q_specific_at_least_once = false;
3841 for (int i = 0; i < pargs.Length; i++)
3843 Type specific = MoreSpecific (pargs [i], qargs [i]);
3844 if (specific == pargs [i])
3845 p_specific_at_least_once = true;
3846 if (specific == qargs [i])
3847 q_specific_at_least_once = true;
3850 if (p_specific_at_least_once && !q_specific_at_least_once)
3852 if (!p_specific_at_least_once && q_specific_at_least_once)
3860 /// Find the Applicable Function Members (7.4.2.1)
3862 /// me: Method Group expression with the members to select.
3863 /// it might contain constructors or methods (or anything
3864 /// that maps to a method).
3866 /// Arguments: ArrayList containing resolved Argument objects.
3868 /// loc: The location if we want an error to be reported, or a Null
3869 /// location for "probing" purposes.
3871 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3872 /// that is the best match of me on Arguments.
3875 public virtual MethodGroupExpr OverloadResolve (EmitContext ec, ref ArrayList Arguments,
3876 bool may_fail, Location loc)
3878 bool method_params = false;
3879 Type applicable_type = null;
3881 ArrayList candidates = new ArrayList (2);
3882 ArrayList candidate_overrides = null;
3885 // Used to keep a map between the candidate
3886 // and whether it is being considered in its
3887 // normal or expanded form
3889 // false is normal form, true is expanded form
3891 Hashtable candidate_to_form = null;
3893 if (Arguments != null)
3894 arg_count = Arguments.Count;
3896 if (RootContext.Version == LanguageVersion.ISO_1 && Name == "Invoke" && TypeManager.IsDelegateType (DeclaringType)) {
3898 Report.Error (1533, loc, "Invoke cannot be called directly on a delegate");
3902 int nmethods = Methods.Length;
3906 // Methods marked 'override' don't take part in 'applicable_type'
3907 // computation, nor in the actual overload resolution.
3908 // However, they still need to be emitted instead of a base virtual method.
3909 // So, we salt them away into the 'candidate_overrides' array.
3911 // In case of reflected methods, we replace each overriding method with
3912 // its corresponding base virtual method. This is to improve compatibility
3913 // with non-C# libraries which change the visibility of overrides (#75636)
3916 for (int i = 0; i < Methods.Length; ++i) {
3917 MethodBase m = Methods [i];
3918 if (TypeManager.IsOverride (m)) {
3919 if (candidate_overrides == null)
3920 candidate_overrides = new ArrayList ();
3921 candidate_overrides.Add (m);
3922 m = TypeManager.TryGetBaseDefinition (m);
3931 // Enable message recording, it's used mainly by lambda expressions
3933 Report.IMessageRecorder msg_recorder = new Report.MessageRecorder ();
3934 Report.IMessageRecorder prev_recorder = Report.SetMessageRecorder (msg_recorder);
3937 // First we construct the set of applicable methods
3939 bool is_sorted = true;
3940 int best_candidate_rate = int.MaxValue;
3941 for (int i = 0; i < nmethods; i++) {
3942 Type decl_type = Methods [i].DeclaringType;
3945 // If we have already found an applicable method
3946 // we eliminate all base types (Section 14.5.5.1)
3948 if (applicable_type != null && IsAncestralType (decl_type, applicable_type))
3952 // Check if candidate is applicable (section 14.4.2.1)
3954 bool params_expanded_form = false;
3955 int candidate_rate = IsApplicable (ec, Arguments, arg_count, ref Methods [i], ref params_expanded_form);
3957 if (candidate_rate < best_candidate_rate) {
3958 best_candidate_rate = candidate_rate;
3959 best_candidate = Methods [i];
3962 if (params_expanded_form) {
3963 if (candidate_to_form == null)
3964 candidate_to_form = new PtrHashtable ();
3965 MethodBase candidate = Methods [i];
3966 candidate_to_form [candidate] = candidate;
3969 if (candidate_rate != 0) {
3970 if (msg_recorder != null)
3971 msg_recorder.EndSession ();
3975 msg_recorder = null;
3976 candidates.Add (Methods [i]);
3978 if (applicable_type == null)
3979 applicable_type = decl_type;
3980 else if (applicable_type != decl_type) {
3982 if (IsAncestralType (applicable_type, decl_type))
3983 applicable_type = decl_type;
3987 Report.SetMessageRecorder (prev_recorder);
3988 if (msg_recorder != null && msg_recorder.PrintMessages ())
3991 int candidate_top = candidates.Count;
3993 if (applicable_type == null) {
3995 // When we found a top level method which does not match and it's
3996 // not an extension method. We start extension methods lookup from here
3998 if (InstanceExpression != null) {
3999 ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (type, Name);
4000 if (ex_method_lookup != null) {
4001 ex_method_lookup.ExtensionExpression = InstanceExpression;
4002 ex_method_lookup.SetTypeArguments (type_arguments);
4003 return ex_method_lookup.OverloadResolve (ec, ref Arguments, may_fail, loc);
4011 // Okay so we have failed to find exact match so we
4012 // return error info about the closest match
4014 if (best_candidate != null) {
4015 if (CustomErrorHandler != null) {
4016 if (CustomErrorHandler.NoExactMatch (ec, best_candidate))
4020 ParameterData pd = TypeManager.GetParameterData (best_candidate);
4021 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4022 if (arg_count == pd.Count || pd.HasParams) {
4023 if (TypeManager.IsGenericMethodDefinition (best_candidate)) {
4024 if (type_arguments == null) {
4025 Report.Error (411, loc,
4026 "The type arguments for method `{0}' cannot be inferred from " +
4027 "the usage. Try specifying the type arguments explicitly",
4028 TypeManager.CSharpSignature (best_candidate));
4032 Type [] g_args = TypeManager.GetGenericArguments (best_candidate);
4033 if (type_arguments.Count != g_args.Length) {
4034 Report.SymbolRelatedToPreviousError (best_candidate);
4035 Report.Error (305, loc, "Using the generic method `{0}' requires `{1}' type argument(s)",
4036 TypeManager.CSharpSignature (best_candidate),
4037 g_args.Length.ToString ());
4041 if (type_arguments != null && !TypeManager.IsGenericMethod (best_candidate)) {
4042 Namespace.Error_TypeArgumentsCannotBeUsed (best_candidate, loc);
4047 if (VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate, cand_params, may_fail, loc))
4048 throw new InternalErrorException ("Overload verification expected failure");
4053 if (almost_matched_members.Count != 0) {
4054 Error_MemberLookupFailed (ec.ContainerType, type, type, ".ctor",
4055 null, MemberTypes.Constructor, AllBindingFlags);
4060 // We failed to find any method with correct argument count
4062 if (Name == ConstructorInfo.ConstructorName) {
4063 Report.SymbolRelatedToPreviousError (type);
4064 Report.Error (1729, loc,
4065 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4066 TypeManager.CSharpName (type), arg_count);
4068 Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4069 Name, arg_count.ToString ());
4077 // At this point, applicable_type is _one_ of the most derived types
4078 // in the set of types containing the methods in this MethodGroup.
4079 // Filter the candidates so that they only contain methods from the
4080 // most derived types.
4083 int finalized = 0; // Number of finalized candidates
4086 // Invariant: applicable_type is a most derived type
4088 // We'll try to complete Section 14.5.5.1 for 'applicable_type' by
4089 // eliminating all it's base types. At the same time, we'll also move
4090 // every unrelated type to the end of the array, and pick the next
4091 // 'applicable_type'.
4093 Type next_applicable_type = null;
4094 int j = finalized; // where to put the next finalized candidate
4095 int k = finalized; // where to put the next undiscarded candidate
4096 for (int i = finalized; i < candidate_top; ++i) {
4097 MethodBase candidate = (MethodBase) candidates [i];
4098 Type decl_type = candidate.DeclaringType;
4100 if (decl_type == applicable_type) {
4101 candidates [k++] = candidates [j];
4102 candidates [j++] = candidates [i];
4106 if (IsAncestralType (decl_type, applicable_type))
4109 if (next_applicable_type != null &&
4110 IsAncestralType (decl_type, next_applicable_type))
4113 candidates [k++] = candidates [i];
4115 if (next_applicable_type == null ||
4116 IsAncestralType (next_applicable_type, decl_type))
4117 next_applicable_type = decl_type;
4120 applicable_type = next_applicable_type;
4123 } while (applicable_type != null);
4127 // Now we actually find the best method
4130 best_candidate = (MethodBase) candidates [0];
4131 if (delegate_type == null)
4132 method_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4134 for (int ix = 1; ix < candidate_top; ix++) {
4135 MethodBase candidate = (MethodBase) candidates [ix];
4137 if (candidate == best_candidate)
4140 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4142 if (BetterFunction (ec, Arguments, arg_count,
4143 candidate, cand_params,
4144 best_candidate, method_params)) {
4145 best_candidate = candidate;
4146 method_params = cand_params;
4150 // Now check that there are no ambiguities i.e the selected method
4151 // should be better than all the others
4153 MethodBase ambiguous = null;
4154 for (int ix = 0; ix < candidate_top; ix++) {
4155 MethodBase candidate = (MethodBase) candidates [ix];
4157 if (candidate == best_candidate)
4160 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4161 if (!BetterFunction (ec, Arguments, arg_count,
4162 best_candidate, method_params,
4163 candidate, cand_params))
4166 Report.SymbolRelatedToPreviousError (candidate);
4167 ambiguous = candidate;
4171 if (ambiguous != null) {
4172 Report.SymbolRelatedToPreviousError (best_candidate);
4173 Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4174 TypeManager.CSharpSignature (ambiguous), TypeManager.CSharpSignature (best_candidate));
4179 // If the method is a virtual function, pick an override closer to the LHS type.
4181 if (!IsBase && best_candidate.IsVirtual) {
4182 if (TypeManager.IsOverride (best_candidate))
4183 throw new InternalErrorException (
4184 "Should not happen. An 'override' method took part in overload resolution: " + best_candidate);
4186 if (candidate_overrides != null) {
4187 Type[] gen_args = null;
4188 bool gen_override = false;
4189 if (TypeManager.IsGenericMethod (best_candidate))
4190 gen_args = TypeManager.GetGenericArguments (best_candidate);
4192 foreach (MethodBase candidate in candidate_overrides) {
4193 if (TypeManager.IsGenericMethod (candidate)) {
4194 if (gen_args == null)
4197 if (gen_args.Length != TypeManager.GetGenericArguments (candidate).Length)
4200 if (gen_args != null)
4204 if (IsOverride (candidate, best_candidate)) {
4205 gen_override = true;
4206 best_candidate = candidate;
4210 if (gen_override && gen_args != null) {
4212 best_candidate = ((MethodInfo) best_candidate).MakeGenericMethod (gen_args);
4219 // And now check if the arguments are all
4220 // compatible, perform conversions if
4221 // necessary etc. and return if everything is
4224 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate,
4225 method_params, may_fail, loc))
4228 if (best_candidate == null)
4231 MethodBase the_method = TypeManager.DropGenericMethodArguments (best_candidate);
4233 if (the_method.IsGenericMethodDefinition &&
4234 !ConstraintChecker.CheckConstraints (ec, the_method, best_candidate, loc))
4238 IMethodData data = TypeManager.GetMethod (the_method);
4240 data.SetMemberIsUsed ();
4245 public override void SetTypeArguments (TypeArguments ta)
4247 type_arguments = ta;
4250 public bool VerifyArgumentsCompat (EmitContext ec, ref ArrayList arguments,
4251 int arg_count, MethodBase method,
4252 bool chose_params_expanded,
4253 bool may_fail, Location loc)
4255 ParameterData pd = TypeManager.GetParameterData (method);
4257 int errors = Report.Errors;
4258 Parameter.Modifier p_mod = 0;
4260 int a_idx = 0, a_pos = 0;
4262 ArrayList params_initializers = null;
4264 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4265 a = (Argument) arguments [a_idx];
4266 if (p_mod != Parameter.Modifier.PARAMS) {
4267 p_mod = pd.ParameterModifier (a_idx);
4268 pt = pd.ParameterType (a_idx);
4270 if (p_mod == Parameter.Modifier.ARGLIST) {
4271 if (a.Type != TypeManager.runtime_argument_handle_type)
4276 if (pt.IsPointer && !ec.InUnsafe) {
4283 if (p_mod == Parameter.Modifier.PARAMS) {
4284 if (chose_params_expanded) {
4285 params_initializers = new ArrayList (arg_count - a_idx);
4286 pt = TypeManager.GetElementType (pt);
4288 } else if (p_mod != 0) {
4289 pt = TypeManager.GetElementType (pt);
4294 // Types have to be identical when ref or out modifer is used
4296 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4297 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4300 if (!TypeManager.IsEqual (a.Expr.Type, pt))
4307 if (TypeManager.IsEqual (a.Type, pt)) {
4310 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4316 // Convert params arguments to an array initializer
4318 if (params_initializers != null) {
4319 params_initializers.Add (conv);
4320 arguments.RemoveAt (a_idx--);
4325 // Update the argument with the implicit conversion
4330 // Fill not provided arguments required by params modifier
4332 if (params_initializers == null && pd.HasParams && arg_count < pd.Count) {
4333 if (arguments == null)
4334 arguments = new ArrayList (1);
4336 pt = pd.Types [GetApplicableParametersCount (method, pd) - 1];
4337 pt = TypeManager.GetElementType (pt);
4338 params_initializers = new ArrayList (0);
4341 if (a_idx == arg_count) {
4343 // Append an array argument with all params arguments
4345 if (params_initializers != null) {
4346 arguments.Add (new Argument (
4347 new ArrayCreation (new TypeExpression (pt, loc), "[]",
4348 params_initializers, loc).Resolve (ec)));
4353 if (!may_fail && Report.Errors == errors) {
4354 if (CustomErrorHandler != null)
4355 CustomErrorHandler.NoExactMatch (ec, best_candidate);
4357 Error_InvalidArguments (ec, loc, a_pos, method, a, pd, pt);
4363 public class ConstantExpr : MemberExpr
4367 public ConstantExpr (FieldInfo constant, Location loc)
4369 this.constant = constant;
4373 public override string Name {
4374 get { throw new NotImplementedException (); }
4377 public override bool IsInstance {
4378 get { return !IsStatic; }
4381 public override bool IsStatic {
4382 get { return constant.IsStatic; }
4385 public override Type DeclaringType {
4386 get { return constant.DeclaringType; }
4389 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc, SimpleName original)
4391 constant = TypeManager.GetGenericFieldDefinition (constant);
4393 IConstant ic = TypeManager.GetConstant (constant);
4395 if (constant.IsLiteral) {
4396 ic = new ExternalConstant (constant);
4398 ic = ExternalConstant.CreateDecimal (constant);
4399 // HACK: decimal field was not resolved as constant
4401 return new FieldExpr (constant, loc).ResolveMemberAccess (ec, left, loc, original);
4403 TypeManager.RegisterConstant (constant, ic);
4406 return base.ResolveMemberAccess (ec, left, loc, original);
4409 public override Expression DoResolve (EmitContext ec)
4411 IConstant ic = TypeManager.GetConstant (constant);
4412 if (ic.ResolveValue ()) {
4413 if (!ec.IsInObsoleteScope)
4414 ic.CheckObsoleteness (loc);
4417 return ic.CreateConstantReference (loc);
4420 public override void Emit (EmitContext ec)
4422 throw new NotSupportedException ();
4425 public override string GetSignatureForError ()
4427 return TypeManager.GetFullNameSignature (constant);
4432 /// Fully resolved expression that evaluates to a Field
4434 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariable {
4435 public readonly FieldInfo FieldInfo;
4436 VariableInfo variable_info;
4438 LocalTemporary temp;
4440 bool in_initializer;
4442 public FieldExpr (FieldInfo fi, Location l, bool in_initializer):
4445 this.in_initializer = in_initializer;
4448 public FieldExpr (FieldInfo fi, Location l)
4451 eclass = ExprClass.Variable;
4452 type = TypeManager.TypeToCoreType (fi.FieldType);
4456 public override string Name {
4458 return FieldInfo.Name;
4462 public override bool IsInstance {
4464 return !FieldInfo.IsStatic;
4468 public override bool IsStatic {
4470 return FieldInfo.IsStatic;
4474 public override Type DeclaringType {
4476 return FieldInfo.DeclaringType;
4480 public override string GetSignatureForError ()
4482 return TypeManager.GetFullNameSignature (FieldInfo);
4485 public VariableInfo VariableInfo {
4487 return variable_info;
4491 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
4492 SimpleName original)
4494 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
4495 Type t = fi.FieldType;
4497 if (t.IsPointer && !ec.InUnsafe) {
4501 return base.ResolveMemberAccess (ec, left, loc, original);
4504 override public Expression DoResolve (EmitContext ec)
4506 return DoResolve (ec, false, false);
4509 Expression DoResolve (EmitContext ec, bool lvalue_instance, bool out_access)
4511 if (!FieldInfo.IsStatic){
4512 if (InstanceExpression == null){
4514 // This can happen when referencing an instance field using
4515 // a fully qualified type expression: TypeName.InstanceField = xxx
4517 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4521 // Resolve the field's instance expression while flow analysis is turned
4522 // off: when accessing a field "a.b", we must check whether the field
4523 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4525 if (lvalue_instance) {
4526 using (ec.With (EmitContext.Flags.DoFlowAnalysis, false)) {
4527 Expression right_side =
4528 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4529 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side, loc);
4532 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
4533 InstanceExpression = InstanceExpression.Resolve (ec, rf);
4536 if (InstanceExpression == null)
4539 using (ec.Set (EmitContext.Flags.OmitStructFlowAnalysis)) {
4540 InstanceExpression.CheckMarshalByRefAccess (ec);
4544 if (!in_initializer && !ec.IsInFieldInitializer) {
4545 ObsoleteAttribute oa;
4546 FieldBase f = TypeManager.GetField (FieldInfo);
4548 if (!ec.IsInObsoleteScope)
4549 f.CheckObsoleteness (loc);
4551 // To be sure that type is external because we do not register generated fields
4552 } else if (!(FieldInfo.DeclaringType is TypeBuilder)) {
4553 oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
4555 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
4559 AnonymousContainer am = ec.CurrentAnonymousMethod;
4561 if (!FieldInfo.IsStatic){
4562 if (!am.IsIterator && (ec.TypeContainer is Struct)){
4563 Report.Error (1673, loc,
4564 "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",
4571 IFixedBuffer fb = AttributeTester.GetFixedBuffer (FieldInfo);
4573 if (!ec.InFixedInitializer && ec.ContainerType.IsValueType) {
4574 Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4577 if (InstanceExpression.eclass != ExprClass.Variable) {
4578 Report.SymbolRelatedToPreviousError (FieldInfo);
4579 Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4580 TypeManager.GetFullNameSignature (FieldInfo));
4583 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4586 // If the instance expression is a local variable or parameter.
4587 IVariable var = InstanceExpression as IVariable;
4588 if ((var == null) || (var.VariableInfo == null))
4591 VariableInfo vi = var.VariableInfo;
4592 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
4595 variable_info = vi.GetSubStruct (FieldInfo.Name);
4599 static readonly int [] codes = {
4600 191, // instance, write access
4601 192, // instance, out access
4602 198, // static, write access
4603 199, // static, out access
4604 1648, // member of value instance, write access
4605 1649, // member of value instance, out access
4606 1650, // member of value static, write access
4607 1651 // member of value static, out access
4610 static readonly string [] msgs = {
4611 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4612 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4613 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4614 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4615 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4616 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4617 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4618 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4621 // The return value is always null. Returning a value simplifies calling code.
4622 Expression Report_AssignToReadonly (Expression right_side)
4625 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4629 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4631 Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4636 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4638 IVariable var = InstanceExpression as IVariable;
4639 if ((var != null) && (var.VariableInfo != null))
4640 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
4642 bool lvalue_instance = !FieldInfo.IsStatic && FieldInfo.DeclaringType.IsValueType;
4643 bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
4645 Expression e = DoResolve (ec, lvalue_instance, out_access);
4650 FieldBase fb = TypeManager.GetField (FieldInfo);
4654 if (FieldInfo.IsInitOnly) {
4655 // InitOnly fields can only be assigned in constructors or initializers
4656 if (!ec.IsInFieldInitializer && !ec.IsConstructor)
4657 return Report_AssignToReadonly (right_side);
4659 if (ec.IsConstructor) {
4660 Type ctype = ec.TypeContainer.CurrentType;
4662 ctype = ec.ContainerType;
4664 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4665 if (!TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
4666 return Report_AssignToReadonly (right_side);
4667 // static InitOnly fields cannot be assigned-to in an instance constructor
4668 if (IsStatic && !ec.IsStatic)
4669 return Report_AssignToReadonly (right_side);
4670 // instance constructors can't modify InitOnly fields of other instances of the same type
4671 if (!IsStatic && !(InstanceExpression is This))
4672 return Report_AssignToReadonly (right_side);
4676 if (right_side == EmptyExpression.OutAccess &&
4677 !IsStatic && !(InstanceExpression is This) && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type)) {
4678 Report.SymbolRelatedToPreviousError (DeclaringType);
4679 Report.Warning (197, 1, loc,
4680 "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",
4681 GetSignatureForError ());
4687 public override void CheckMarshalByRefAccess (EmitContext ec)
4689 if (!IsStatic && Type.IsValueType && !(InstanceExpression is This) && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type)) {
4690 Report.SymbolRelatedToPreviousError (DeclaringType);
4691 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",
4692 GetSignatureForError ());
4696 public bool VerifyFixed ()
4698 IVariable variable = InstanceExpression as IVariable;
4699 // A variable of the form V.I is fixed when V is a fixed variable of a struct type.
4700 // We defer the InstanceExpression check after the variable check to avoid a
4701 // separate null check on InstanceExpression.
4702 return variable != null && InstanceExpression.Type.IsValueType && variable.VerifyFixed ();
4705 public override int GetHashCode ()
4707 return FieldInfo.GetHashCode ();
4710 public override bool Equals (object obj)
4712 FieldExpr fe = obj as FieldExpr;
4716 if (FieldInfo != fe.FieldInfo)
4719 if (InstanceExpression == null || fe.InstanceExpression == null)
4722 return InstanceExpression.Equals (fe.InstanceExpression);
4725 public void Emit (EmitContext ec, bool leave_copy)
4727 ILGenerator ig = ec.ig;
4728 bool is_volatile = false;
4730 FieldBase f = TypeManager.GetField (FieldInfo);
4732 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4735 f.SetMemberIsUsed ();
4738 if (FieldInfo.IsStatic){
4740 ig.Emit (OpCodes.Volatile);
4742 ig.Emit (OpCodes.Ldsfld, FieldInfo);
4745 EmitInstance (ec, false);
4747 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
4749 ig.Emit (OpCodes.Ldflda, FieldInfo);
4750 ig.Emit (OpCodes.Ldflda, ff.Element);
4753 ig.Emit (OpCodes.Volatile);
4755 ig.Emit (OpCodes.Ldfld, FieldInfo);
4760 ec.ig.Emit (OpCodes.Dup);
4761 if (!FieldInfo.IsStatic) {
4762 temp = new LocalTemporary (this.Type);
4768 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4770 FieldAttributes fa = FieldInfo.Attributes;
4771 bool is_static = (fa & FieldAttributes.Static) != 0;
4772 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
4773 ILGenerator ig = ec.ig;
4775 if (is_readonly && !ec.IsConstructor){
4776 Report_AssignToReadonly (source);
4781 // String concatenation creates a new string instance
4783 prepared = prepare_for_load && !(source is StringConcat);
4784 EmitInstance (ec, prepared);
4788 ec.ig.Emit (OpCodes.Dup);
4789 if (!FieldInfo.IsStatic) {
4790 temp = new LocalTemporary (this.Type);
4795 FieldBase f = TypeManager.GetField (FieldInfo);
4797 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4798 ig.Emit (OpCodes.Volatile);
4804 ig.Emit (OpCodes.Stsfld, FieldInfo);
4806 ig.Emit (OpCodes.Stfld, FieldInfo);
4814 public override void Emit (EmitContext ec)
4819 public void AddressOf (EmitContext ec, AddressOp mode)
4821 ILGenerator ig = ec.ig;
4823 FieldBase f = TypeManager.GetField (FieldInfo);
4825 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
4826 Report.Warning (420, 1, loc, "`{0}': A volatile field references will not be treated as volatile",
4827 f.GetSignatureForError ());
4830 if ((mode & AddressOp.Store) != 0)
4832 if ((mode & AddressOp.Load) != 0)
4833 f.SetMemberIsUsed ();
4837 // Handle initonly fields specially: make a copy and then
4838 // get the address of the copy.
4841 if (FieldInfo.IsInitOnly){
4843 if (ec.IsConstructor){
4844 if (FieldInfo.IsStatic){
4856 local = ig.DeclareLocal (type);
4857 ig.Emit (OpCodes.Stloc, local);
4858 ig.Emit (OpCodes.Ldloca, local);
4863 if (FieldInfo.IsStatic){
4864 ig.Emit (OpCodes.Ldsflda, FieldInfo);
4867 EmitInstance (ec, false);
4868 ig.Emit (OpCodes.Ldflda, FieldInfo);
4875 /// Expression that evaluates to a Property. The Assign class
4876 /// might set the `Value' expression if we are in an assignment.
4878 /// This is not an LValue because we need to re-write the expression, we
4879 /// can not take data from the stack and store it.
4881 public class PropertyExpr : MemberExpr, IAssignMethod {
4882 public readonly PropertyInfo PropertyInfo;
4883 MethodInfo getter, setter;
4888 LocalTemporary temp;
4891 public PropertyExpr (Type container_type, PropertyInfo pi, Location l)
4894 eclass = ExprClass.PropertyAccess;
4898 type = TypeManager.TypeToCoreType (pi.PropertyType);
4900 ResolveAccessors (container_type);
4903 public override string Name {
4905 return PropertyInfo.Name;
4909 public override bool IsInstance {
4915 public override bool IsStatic {
4921 public override Expression CreateExpressionTree (EmitContext ec)
4923 if (IsSingleDimensionalArrayLength ()) {
4924 ArrayList args = new ArrayList (1);
4925 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
4926 return CreateExpressionFactoryCall ("ArrayLength", args);
4929 // TODO: it's waiting for PropertyExpr refactoring
4930 //ArrayList args = new ArrayList (2);
4931 //args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
4932 //args.Add (getter expression);
4933 //return CreateExpressionFactoryCall ("Property", args);
4934 return base.CreateExpressionTree (ec);
4937 public override Type DeclaringType {
4939 return PropertyInfo.DeclaringType;
4943 public override string GetSignatureForError ()
4945 return TypeManager.GetFullNameSignature (PropertyInfo);
4948 void FindAccessors (Type invocation_type)
4950 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
4951 BindingFlags.Static | BindingFlags.Instance |
4952 BindingFlags.DeclaredOnly;
4954 Type current = PropertyInfo.DeclaringType;
4955 for (; current != null; current = current.BaseType) {
4956 MemberInfo[] group = TypeManager.MemberLookup (
4957 invocation_type, invocation_type, current,
4958 MemberTypes.Property, flags, PropertyInfo.Name, null);
4963 if (group.Length != 1)
4964 // Oooops, can this ever happen ?
4967 PropertyInfo pi = (PropertyInfo) group [0];
4970 getter = pi.GetGetMethod (true);
4973 setter = pi.GetSetMethod (true);
4975 MethodInfo accessor = getter != null ? getter : setter;
4977 if (!accessor.IsVirtual)
4983 // We also perform the permission checking here, as the PropertyInfo does not
4984 // hold the information for the accessibility of its setter/getter
4986 // TODO: Refactor to use some kind of cache together with GetPropertyFromAccessor
4987 void ResolveAccessors (Type container_type)
4989 FindAccessors (container_type);
4991 if (getter != null) {
4992 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
4993 IMethodData md = TypeManager.GetMethod (the_getter);
4995 md.SetMemberIsUsed ();
4997 is_static = getter.IsStatic;
5000 if (setter != null) {
5001 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
5002 IMethodData md = TypeManager.GetMethod (the_setter);
5004 md.SetMemberIsUsed ();
5006 is_static = setter.IsStatic;
5010 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
5013 InstanceExpression = null;
5017 if (InstanceExpression == null) {
5018 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5022 InstanceExpression = InstanceExpression.DoResolve (ec);
5023 if (lvalue_instance && InstanceExpression != null)
5024 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
5026 if (InstanceExpression == null)
5029 InstanceExpression.CheckMarshalByRefAccess (ec);
5031 if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) &&
5032 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
5033 !TypeManager.IsNestedChildOf (ec.ContainerType, InstanceExpression.Type) &&
5034 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.ContainerType)) {
5035 Report.SymbolRelatedToPreviousError (PropertyInfo);
5036 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
5043 void Error_PropertyNotFound (MethodInfo mi, bool getter)
5045 // TODO: correctly we should compare arguments but it will lead to bigger changes
5046 if (mi is MethodBuilder) {
5047 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
5051 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
5053 ParameterData iparams = TypeManager.GetParameterData (mi);
5054 sig.Append (getter ? "get_" : "set_");
5056 sig.Append (iparams.GetSignatureForError ());
5058 Report.SymbolRelatedToPreviousError (mi);
5059 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
5060 Name, sig.ToString ());
5063 public bool IsAccessibleFrom (Type invocation_type, bool lvalue)
5066 MethodInfo accessor = lvalue ? setter : getter;
5067 if (accessor == null && lvalue)
5069 return accessor != null && IsAccessorAccessible (invocation_type, accessor, out dummy);
5072 bool IsSingleDimensionalArrayLength ()
5074 if (getter == TypeManager.system_int_array_get_length ||
5075 getter == TypeManager.int_array_get_length) {
5076 Type iet = InstanceExpression.Type;
5079 // System.Array.Length can be called, but the Type does not
5080 // support invoking GetArrayRank, so test for that case first
5082 return iet != TypeManager.array_type && (iet.GetArrayRank () == 1);
5088 override public Expression DoResolve (EmitContext ec)
5093 if (getter != null){
5094 if (TypeManager.GetParameterData (getter).Count != 0){
5095 Error_PropertyNotFound (getter, true);
5100 if (getter == null){
5102 // The following condition happens if the PropertyExpr was
5103 // created, but is invalid (ie, the property is inaccessible),
5104 // and we did not want to embed the knowledge about this in
5105 // the caller routine. This only avoids double error reporting.
5110 if (InstanceExpression != EmptyExpression.Null) {
5111 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5112 TypeManager.GetFullNameSignature (PropertyInfo));
5117 bool must_do_cs1540_check = false;
5118 if (getter != null &&
5119 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
5120 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
5121 if (pm != null && pm.HasCustomAccessModifier) {
5122 Report.SymbolRelatedToPreviousError (pm);
5123 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5124 TypeManager.CSharpSignature (getter));
5127 Report.SymbolRelatedToPreviousError (getter);
5128 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
5133 if (!InstanceResolve (ec, false, must_do_cs1540_check))
5137 // Only base will allow this invocation to happen.
5139 if (IsBase && getter.IsAbstract) {
5140 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5144 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
5154 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
5156 if (right_side == EmptyExpression.OutAccess) {
5157 if (ec.CurrentBlock.Toplevel.GetTransparentIdentifier (PropertyInfo.Name) != null) {
5158 Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5161 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as `ref' or `out' parameter",
5162 GetSignatureForError ());
5167 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5168 Error_CannotModifyIntermediateExpressionValue (ec);
5171 if (setter == null){
5173 // The following condition happens if the PropertyExpr was
5174 // created, but is invalid (ie, the property is inaccessible),
5175 // and we did not want to embed the knowledge about this in
5176 // the caller routine. This only avoids double error reporting.
5180 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
5181 GetSignatureForError ());
5185 if (TypeManager.GetParameterData (setter).Count != 1){
5186 Error_PropertyNotFound (setter, false);
5190 bool must_do_cs1540_check;
5191 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
5192 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
5193 if (pm != null && pm.HasCustomAccessModifier) {
5194 Report.SymbolRelatedToPreviousError (pm);
5195 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5196 TypeManager.CSharpSignature (setter));
5199 Report.SymbolRelatedToPreviousError (setter);
5200 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
5205 if (!InstanceResolve (ec, PropertyInfo.DeclaringType.IsValueType, must_do_cs1540_check))
5209 // Only base will allow this invocation to happen.
5211 if (IsBase && setter.IsAbstract){
5212 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5219 public override void Emit (EmitContext ec)
5224 public void Emit (EmitContext ec, bool leave_copy)
5227 // Special case: length of single dimension array property is turned into ldlen
5229 if (IsSingleDimensionalArrayLength ()) {
5231 EmitInstance (ec, false);
5232 ec.ig.Emit (OpCodes.Ldlen);
5233 ec.ig.Emit (OpCodes.Conv_I4);
5237 Invocation.EmitCall (ec, IsBase, InstanceExpression, getter, null, loc, prepared, false);
5240 ec.ig.Emit (OpCodes.Dup);
5242 temp = new LocalTemporary (this.Type);
5249 // Implements the IAssignMethod interface for assignments
5251 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5253 Expression my_source = source;
5255 if (prepare_for_load) {
5256 if (source is StringConcat)
5257 EmitInstance (ec, false);
5265 ec.ig.Emit (OpCodes.Dup);
5267 temp = new LocalTemporary (this.Type);
5271 } else if (leave_copy) {
5273 temp = new LocalTemporary (this.Type);
5278 ArrayList args = new ArrayList (1);
5279 args.Add (new Argument (my_source, Argument.AType.Expression));
5281 Invocation.EmitCall (ec, IsBase, InstanceExpression, setter, args, loc, false, prepared);
5291 /// Fully resolved expression that evaluates to an Event
5293 public class EventExpr : MemberExpr {
5294 public readonly EventInfo EventInfo;
5297 MethodInfo add_accessor, remove_accessor;
5299 public EventExpr (EventInfo ei, Location loc)
5303 eclass = ExprClass.EventAccess;
5305 add_accessor = TypeManager.GetAddMethod (ei);
5306 remove_accessor = TypeManager.GetRemoveMethod (ei);
5307 if (add_accessor.IsStatic || remove_accessor.IsStatic)
5310 if (EventInfo is MyEventBuilder){
5311 MyEventBuilder eb = (MyEventBuilder) EventInfo;
5312 type = eb.EventType;
5315 type = EventInfo.EventHandlerType;
5318 public override string Name {
5320 return EventInfo.Name;
5324 public override bool IsInstance {
5330 public override bool IsStatic {
5336 public override Type DeclaringType {
5338 return EventInfo.DeclaringType;
5342 void Error_AssignmentEventOnly ()
5344 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5345 GetSignatureForError ());
5348 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
5349 SimpleName original)
5352 // If the event is local to this class, we transform ourselves into a FieldExpr
5355 if (EventInfo.DeclaringType == ec.ContainerType ||
5356 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
5357 EventField mi = TypeManager.GetEventField (EventInfo);
5360 if (!ec.IsInObsoleteScope)
5361 mi.CheckObsoleteness (loc);
5363 if ((mi.ModFlags & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0 && !ec.IsInCompoundAssignment)
5364 Error_AssignmentEventOnly ();
5366 FieldExpr ml = new FieldExpr (mi.FieldBuilder, loc);
5368 InstanceExpression = null;
5370 return ml.ResolveMemberAccess (ec, left, loc, original);
5374 if (left is This && !ec.IsInCompoundAssignment)
5375 Error_AssignmentEventOnly ();
5377 return base.ResolveMemberAccess (ec, left, loc, original);
5381 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
5384 InstanceExpression = null;
5388 if (InstanceExpression == null) {
5389 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5393 InstanceExpression = InstanceExpression.DoResolve (ec);
5394 if (InstanceExpression == null)
5397 if (IsBase && add_accessor.IsAbstract) {
5398 Error_CannotCallAbstractBase(TypeManager.CSharpSignature(add_accessor));
5403 // This is using the same mechanism as the CS1540 check in PropertyExpr.
5404 // However, in the Event case, we reported a CS0122 instead.
5406 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
5407 InstanceExpression.Type != ec.ContainerType &&
5408 TypeManager.IsSubclassOf (ec.ContainerType, InstanceExpression.Type)) {
5409 Report.SymbolRelatedToPreviousError (EventInfo);
5410 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5417 public bool IsAccessibleFrom (Type invocation_type)
5420 return IsAccessorAccessible (invocation_type, add_accessor, out dummy) &&
5421 IsAccessorAccessible (invocation_type, remove_accessor, out dummy);
5424 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5426 return DoResolve (ec);
5429 public override Expression DoResolve (EmitContext ec)
5431 bool must_do_cs1540_check;
5432 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
5433 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
5434 Report.SymbolRelatedToPreviousError (EventInfo);
5435 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5439 if (!InstanceResolve (ec, must_do_cs1540_check))
5445 public override void Emit (EmitContext ec)
5447 Report.Error (70, loc, "The event `{0}' can only appear on the left hand side of += or -= "+
5448 "(except on the defining type)", GetSignatureForError ());
5451 public override string GetSignatureForError ()
5453 return TypeManager.CSharpSignature (EventInfo);
5456 public void EmitAddOrRemove (EmitContext ec, Expression source)
5458 BinaryDelegate source_del = source as BinaryDelegate;
5459 if (source_del == null) {
5463 Expression handler = source_del.Right;
5465 Argument arg = new Argument (handler, Argument.AType.Expression);
5466 ArrayList args = new ArrayList ();
5470 if (source_del.IsAddition)
5471 Invocation.EmitCall (
5472 ec, IsBase, InstanceExpression, add_accessor, args, loc);
5474 Invocation.EmitCall (
5475 ec, IsBase, InstanceExpression, remove_accessor, args, loc);
5479 public class TemporaryVariable : Expression, IMemoryLocation
5484 public TemporaryVariable (Type type, Location loc)
5488 eclass = ExprClass.Value;
5491 public override Expression DoResolve (EmitContext ec)
5496 TypeExpr te = new TypeExpression (type, loc);
5497 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
5498 if (!li.Resolve (ec))
5501 if (ec.MustCaptureVariable (li)) {
5502 ScopeInfo scope = li.Block.CreateScopeInfo ();
5503 var = scope.AddLocal (li);
5510 public Variable Variable {
5511 get { return var != null ? var : li.Variable; }
5514 public override void Emit (EmitContext ec)
5516 Variable.EmitInstance (ec);
5520 public void EmitLoadAddress (EmitContext ec)
5522 Variable.EmitInstance (ec);
5523 Variable.EmitAddressOf (ec);
5526 public void Store (EmitContext ec, Expression right_side)
5528 Variable.EmitInstance (ec);
5529 right_side.Emit (ec);
5530 Variable.EmitAssign (ec);
5533 public void EmitThis (EmitContext ec)
5535 Variable.EmitInstance (ec);
5538 public void EmitStore (EmitContext ec)
5540 Variable.EmitAssign (ec);
5543 public void AddressOf (EmitContext ec, AddressOp mode)
5545 EmitLoadAddress (ec);
5550 /// Handles `var' contextual keyword; var becomes a keyword only
5551 /// if no type called var exists in a variable scope
5553 public class VarExpr : SimpleName
5555 // Used for error reporting only
5556 ArrayList initializer;
5558 public VarExpr (Location loc)
5563 public ArrayList VariableInitializer {
5565 this.initializer = value;
5569 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5572 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
5574 type = right_side.Type;
5575 if (type == TypeManager.null_type || type == TypeManager.void_type || type == TypeManager.anonymous_method_type) {
5576 Report.Error (815, loc, "An implicitly typed local variable declaration cannot be initialized with `{0}'",
5577 right_side.GetSignatureForError ());
5581 eclass = ExprClass.Variable;
5585 protected override void Error_TypeOrNamespaceNotFound (IResolveContext ec)
5587 Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");
5590 public override TypeExpr ResolveAsContextualType (IResolveContext rc, bool silent)
5592 TypeExpr te = base.ResolveAsContextualType (rc, true);
5596 if (initializer == null)
5599 if (initializer.Count > 1) {
5600 Location loc = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [1]).Location;
5601 Report.Error (819, loc, "An implicitly typed local variable declaration cannot include multiple declarators");
5606 Expression variable_initializer = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [0]).expression_or_array_initializer;
5607 if (variable_initializer == null) {
5608 Report.Error (818, loc, "An implicitly typed local variable declarator must include an initializer");