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 ()
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;
189 /// Performs semantic analysis on the Expression
193 /// The Resolve method is invoked to perform the semantic analysis
196 /// The return value is an expression (it can be the
197 /// same expression in some cases) or a new
198 /// expression that better represents this node.
200 /// For example, optimizations of Unary (LiteralInt)
201 /// would return a new LiteralInt with a negated
204 /// If there is an error during semantic analysis,
205 /// then an error should be reported (using Report)
206 /// and a null value should be returned.
208 /// There are two side effects expected from calling
209 /// Resolve(): the the field variable "eclass" should
210 /// be set to any value of the enumeration
211 /// `ExprClass' and the type variable should be set
212 /// to a valid type (this is the type of the
215 public abstract Expression DoResolve (EmitContext ec);
217 public virtual Expression DoResolveLValue (EmitContext ec, Expression right_side)
223 // This is used if the expression should be resolved as a type or namespace name.
224 // the default implementation fails.
226 public virtual FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
232 // C# 3.0 introduced contextual keywords (var) which behaves like a type if type with
233 // same name exists or as a keyword when no type was found
235 public virtual TypeExpr ResolveAsContextualType (IResolveContext rc, bool silent)
237 return ResolveAsTypeTerminal (rc, silent);
241 // This is used to resolve the expression as a type, a null
242 // value will be returned if the expression is not a type
245 public virtual TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
247 TypeExpr te = ResolveAsBaseTerminal (ec, silent);
251 if (!silent) { // && !(te is TypeParameterExpr)) {
252 ObsoleteAttribute obsolete_attr = AttributeTester.GetObsoleteAttribute (te.Type);
253 if (obsolete_attr != null && !ec.IsInObsoleteScope) {
254 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location);
258 // Constrains don't need to be checked for overrides
259 GenericMethod gm = ec.GenericDeclContainer as GenericMethod;
260 if (gm != null && (gm.ModFlags & Modifiers.OVERRIDE) != 0) {
265 ConstructedType ct = te as ConstructedType;
266 if ((ct != null) && !ct.CheckConstraints (ec))
272 public TypeExpr ResolveAsBaseTerminal (IResolveContext ec, bool silent)
274 int errors = Report.Errors;
276 FullNamedExpression fne = ResolveAsTypeStep (ec, silent);
281 if (fne.eclass != ExprClass.Type) {
282 if (!silent && errors == Report.Errors)
283 fne.Error_UnexpectedKind (null, "type", loc);
287 TypeExpr te = fne as TypeExpr;
289 if (!te.CheckAccessLevel (ec.DeclContainer)) {
290 Report.SymbolRelatedToPreviousError (te.Type);
291 ErrorIsInaccesible (loc, TypeManager.CSharpName (te.Type));
299 public static void ErrorIsInaccesible (Location loc, string name)
301 Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", name);
304 protected static void Error_CannotAccessProtected (Location loc, MemberInfo m, Type qualifier, Type container)
306 Report.Error (1540, loc, "Cannot access protected member `{0}' via a qualifier of type `{1}'."
307 + " The qualifier must be of type `{2}' or derived from it",
308 TypeManager.GetFullNameSignature (m),
309 TypeManager.CSharpName (qualifier),
310 TypeManager.CSharpName (container));
314 public static void Error_InvalidExpressionStatement (Location loc)
316 Report.Error (201, loc, "Only assignment, call, increment, decrement, and new object " +
317 "expressions can be used as a statement");
320 public void Error_InvalidExpressionStatement ()
322 Error_InvalidExpressionStatement (loc);
325 protected void Error_CannotAssign (string to, string roContext)
327 Report.Error (1656, loc, "Cannot assign to `{0}' because it is a `{1}'",
331 public static void Error_VoidInvalidInTheContext (Location loc)
333 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
336 public virtual void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl)
338 // The error was already reported as CS1660
339 if (type == TypeManager.anonymous_method_type)
342 if (TypeManager.IsGenericParameter (Type) && TypeManager.IsGenericParameter (target) && type.Name == target.Name) {
344 string sig1 = Type.DeclaringMethod == null ?
345 TypeManager.CSharpName (Type.DeclaringType) :
346 TypeManager.CSharpSignature (Type.DeclaringMethod);
347 string sig2 = target.DeclaringMethod == null ?
348 TypeManager.CSharpName (target.DeclaringType) :
349 TypeManager.CSharpSignature (target.DeclaringMethod);
350 Report.ExtraInformation (loc,
352 "The generic parameter `{0}' of `{1}' cannot be converted to the generic parameter `{0}' of `{2}' (in the previous ",
353 Type.Name, sig1, sig2));
355 } else if (Type.FullName == target.FullName){
356 Report.ExtraInformation (loc,
358 "The type `{0}' has two conflicting definitions, one comes from `{1}' and the other from `{2}' (in the previous ",
359 Type.FullName, Type.Assembly.FullName, target.Assembly.FullName));
363 Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
364 TypeManager.CSharpName (type), TypeManager.CSharpName (target));
368 Expression e = (this is EnumConstant) ? ((EnumConstant)this).Child : this;
369 bool b = Convert.ExplicitNumericConversion (e, target) != null;
372 Convert.ExplicitReferenceConversionExists (Type, target) ||
373 Convert.ExplicitUnsafe (e, target) != null ||
374 (ec != null && Convert.UserDefinedConversion (ec, this, target, Location.Null, true) != null))
376 Report.Error (266, loc, "Cannot implicitly convert type `{0}' to `{1}'. " +
377 "An explicit conversion exists (are you missing a cast?)",
378 TypeManager.CSharpName (Type), TypeManager.CSharpName (target));
382 if (Type != TypeManager.string_type && this is Constant && !(this is EmptyConstantCast)) {
383 Report.Error (31, loc, "Constant value `{0}' cannot be converted to a `{1}'",
384 ((Constant)(this)).GetValue ().ToString (), TypeManager.CSharpName (target));
388 Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
389 TypeManager.CSharpName (type),
390 TypeManager.CSharpName (target));
393 protected void Error_VariableIsUsedBeforeItIsDeclared (string name)
395 Report.Error (841, loc, "The variable `{0}' cannot be used before it is declared",
399 protected virtual void Error_TypeDoesNotContainDefinition (Type type, string name)
401 Error_TypeDoesNotContainDefinition (loc, type, name);
404 public static void Error_TypeDoesNotContainDefinition (Location loc, Type type, string name)
406 Report.SymbolRelatedToPreviousError (type);
407 Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
408 TypeManager.CSharpName (type), name);
411 protected static void Error_ValueAssignment (Location loc)
413 Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
416 ResolveFlags ExprClassToResolveFlags
421 case ExprClass.Namespace:
422 return ResolveFlags.Type;
424 case ExprClass.MethodGroup:
425 return ResolveFlags.MethodGroup;
427 case ExprClass.Value:
428 case ExprClass.Variable:
429 case ExprClass.PropertyAccess:
430 case ExprClass.EventAccess:
431 case ExprClass.IndexerAccess:
432 return ResolveFlags.VariableOrValue;
435 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
441 /// Resolves an expression and performs semantic analysis on it.
445 /// Currently Resolve wraps DoResolve to perform sanity
446 /// checking and assertion checking on what we expect from Resolve.
448 public Expression Resolve (EmitContext ec, ResolveFlags flags)
450 if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type)
451 return ResolveAsTypeStep (ec, false);
453 bool do_flow_analysis = ec.DoFlowAnalysis;
454 bool omit_struct_analysis = ec.OmitStructFlowAnalysis;
455 if ((flags & ResolveFlags.DisableFlowAnalysis) != 0)
456 do_flow_analysis = false;
457 if ((flags & ResolveFlags.DisableStructFlowAnalysis) != 0)
458 omit_struct_analysis = true;
461 using (ec.WithFlowAnalysis (do_flow_analysis, omit_struct_analysis)) {
462 if (this is SimpleName) {
463 bool intermediate = (flags & ResolveFlags.Intermediate) == ResolveFlags.Intermediate;
464 e = ((SimpleName) this).DoResolve (ec, intermediate);
473 if ((flags & e.ExprClassToResolveFlags) == 0) {
474 e.Error_UnexpectedKind (flags, loc);
478 if (e.type == null && !(e is Namespace)) {
479 throw new Exception (
480 "Expression " + e.GetType () +
481 " did not set its type after Resolve\n" +
482 "called from: " + this.GetType ());
489 /// Resolves an expression and performs semantic analysis on it.
491 public Expression Resolve (EmitContext ec)
493 Expression e = Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
495 if (e != null && e.eclass == ExprClass.MethodGroup && RootContext.Version == LanguageVersion.ISO_1) {
496 ((MethodGroupExpr) e).ReportUsageError ();
502 public Constant ResolveAsConstant (EmitContext ec, MemberCore mc)
504 Expression e = Resolve (ec);
508 Constant c = e as Constant;
512 Const.Error_ExpressionMustBeConstant (loc, mc.GetSignatureForError ());
517 /// Resolves an expression for LValue assignment
521 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
522 /// checking and assertion checking on what we expect from Resolve
524 public Expression ResolveLValue (EmitContext ec, Expression right_side, Location loc)
526 int errors = Report.Errors;
527 bool out_access = right_side == EmptyExpression.OutAccess;
529 Expression e = DoResolveLValue (ec, right_side);
531 if (e != null && out_access && !(e is IMemoryLocation)) {
532 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
533 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
535 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
536 // e.GetType () + " " + e.GetSignatureForError ());
541 if (errors == Report.Errors) {
543 Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
545 Error_ValueAssignment (loc);
550 if (e.eclass == ExprClass.Invalid)
551 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
553 if (e.eclass == ExprClass.MethodGroup) {
554 ((MethodGroupExpr) e).ReportUsageError ();
558 if ((e.type == null) && !(e is ConstructedType))
559 throw new Exception ("Expression " + e + " did not set its type after Resolve");
565 /// Emits the code for the expression
569 /// The Emit method is invoked to generate the code
570 /// for the expression.
572 public abstract void Emit (EmitContext ec);
574 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
577 ec.ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
581 /// Protected constructor. Only derivate types should
582 /// be able to be created
585 protected Expression ()
587 eclass = ExprClass.Invalid;
592 /// Returns a fully formed expression after a MemberLookup
595 public static Expression ExprClassFromMemberInfo (Type container_type, MemberInfo mi, Location loc)
598 return new EventExpr ((EventInfo) mi, loc);
599 else if (mi is FieldInfo)
600 return new FieldExpr ((FieldInfo) mi, loc);
601 else if (mi is PropertyInfo)
602 return new PropertyExpr (container_type, (PropertyInfo) mi, loc);
603 else if (mi is Type){
604 return new TypeExpression ((System.Type) mi, loc);
610 protected static ArrayList almost_matched_members = new ArrayList (4);
613 // FIXME: Probably implement a cache for (t,name,current_access_set)?
615 // This code could use some optimizations, but we need to do some
616 // measurements. For example, we could use a delegate to `flag' when
617 // something can not any longer be a method-group (because it is something
621 // If the return value is an Array, then it is an array of
624 // If the return value is an MemberInfo, it is anything, but a Method
628 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
629 // the arguments here and have MemberLookup return only the methods that
630 // match the argument count/type, unlike we are doing now (we delay this
633 // This is so we can catch correctly attempts to invoke instance methods
634 // from a static body (scan for error 120 in ResolveSimpleName).
637 // FIXME: Potential optimization, have a static ArrayList
640 public static Expression MemberLookup (Type container_type, Type queried_type, string name,
641 MemberTypes mt, BindingFlags bf, Location loc)
643 return MemberLookup (container_type, null, queried_type, name, mt, bf, loc);
647 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
648 // `qualifier_type' or null to lookup members in the current class.
651 public static Expression MemberLookup (Type container_type,
652 Type qualifier_type, Type queried_type,
653 string name, MemberTypes mt,
654 BindingFlags bf, Location loc)
656 almost_matched_members.Clear ();
658 MemberInfo [] mi = TypeManager.MemberLookup (container_type, qualifier_type,
659 queried_type, mt, bf, name, almost_matched_members);
665 bool is_interface = qualifier_type != null && qualifier_type.IsInterface;
666 ArrayList methods = new ArrayList (2);
667 ArrayList non_methods = null;
669 foreach (MemberInfo m in mi) {
670 if (m is MethodBase) {
675 if (non_methods == null) {
676 non_methods = new ArrayList (2);
681 foreach (MemberInfo n_m in non_methods) {
682 if (m.DeclaringType.IsInterface && TypeManager.ImplementsInterface (m.DeclaringType, n_m.DeclaringType))
685 Report.SymbolRelatedToPreviousError (m);
686 Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
687 TypeManager.GetFullNameSignature (m), TypeManager.GetFullNameSignature (n_m));
692 if (methods.Count == 0)
693 return ExprClassFromMemberInfo (container_type, (MemberInfo)non_methods [0], loc);
695 if (non_methods != null) {
696 MethodBase method = (MethodBase) methods [0];
697 MemberInfo non_method = (MemberInfo) non_methods [0];
698 if (method.DeclaringType == non_method.DeclaringType) {
699 // Cannot happen with C# code, but is valid in IL
700 Report.SymbolRelatedToPreviousError (method);
701 Report.SymbolRelatedToPreviousError (non_method);
702 Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
703 TypeManager.GetFullNameSignature (non_method),
704 TypeManager.CSharpSignature (method));
709 Report.SymbolRelatedToPreviousError (method);
710 Report.SymbolRelatedToPreviousError (non_method);
711 Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and non-method `{1}'. Using method `{0}'",
712 TypeManager.CSharpSignature (method), TypeManager.GetFullNameSignature (non_method));
716 return new MethodGroupExpr (methods, queried_type, loc);
719 if (mi [0] is MethodBase)
720 return new MethodGroupExpr (mi, queried_type, loc);
722 return ExprClassFromMemberInfo (container_type, mi [0], loc);
725 public const MemberTypes AllMemberTypes =
726 MemberTypes.Constructor |
730 MemberTypes.NestedType |
731 MemberTypes.Property;
733 public const BindingFlags AllBindingFlags =
734 BindingFlags.Public |
735 BindingFlags.Static |
736 BindingFlags.Instance;
738 public static Expression MemberLookup (Type container_type, Type queried_type,
739 string name, Location loc)
741 return MemberLookup (container_type, null, queried_type, name,
742 AllMemberTypes, AllBindingFlags, loc);
745 public static Expression MemberLookup (Type container_type, Type qualifier_type,
746 Type queried_type, string name, Location loc)
748 return MemberLookup (container_type, qualifier_type, queried_type,
749 name, AllMemberTypes, AllBindingFlags, loc);
752 public static MethodGroupExpr MethodLookup (Type container_type, Type queried_type,
753 string name, Location loc)
755 return (MethodGroupExpr)MemberLookup (container_type, null, queried_type, name,
756 MemberTypes.Method, AllBindingFlags, loc);
760 /// This is a wrapper for MemberLookup that is not used to "probe", but
761 /// to find a final definition. If the final definition is not found, we
762 /// look for private members and display a useful debugging message if we
765 protected Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
766 Type queried_type, string name,
767 MemberTypes mt, BindingFlags bf,
772 int errors = Report.Errors;
774 e = MemberLookup (ec.ContainerType, qualifier_type, queried_type, name, mt, bf, loc);
776 if (e != null || errors != Report.Errors)
779 // No errors were reported by MemberLookup, but there was an error.
780 return Error_MemberLookupFailed (ec.ContainerType, qualifier_type, queried_type,
784 protected virtual Expression Error_MemberLookupFailed (Type container_type, Type qualifier_type,
785 Type queried_type, string name, string class_name,
786 MemberTypes mt, BindingFlags bf)
788 if (almost_matched_members.Count != 0) {
789 for (int i = 0; i < almost_matched_members.Count; ++i) {
790 MemberInfo m = (MemberInfo) almost_matched_members [i];
791 for (int j = 0; j < i; ++j) {
792 if (m == almost_matched_members [j]) {
800 Type declaring_type = m.DeclaringType;
802 Report.SymbolRelatedToPreviousError (m);
803 if (qualifier_type == null) {
804 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
805 TypeManager.CSharpName (m.DeclaringType),
806 TypeManager.CSharpName (container_type));
808 } else if (qualifier_type != container_type &&
809 TypeManager.IsNestedFamilyAccessible (container_type, declaring_type)) {
810 // Although a derived class can access protected members of
811 // its base class it cannot do so through an instance of the
812 // base class (CS1540). If the qualifier_type is a base of the
813 // ec.ContainerType and the lookup succeeds with the latter one,
814 // then we are in this situation.
815 Error_CannotAccessProtected (loc, m, qualifier_type, container_type);
817 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (m));
820 almost_matched_members.Clear ();
824 MemberInfo[] lookup = null;
825 if (queried_type == null) {
826 class_name = "global::";
828 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
829 mt, (bf & ~BindingFlags.Public) | BindingFlags.NonPublic,
832 if (lookup != null) {
833 Report.SymbolRelatedToPreviousError (lookup [0]);
834 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (lookup [0]));
835 return Error_MemberLookupFailed (lookup);
838 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
839 AllMemberTypes, AllBindingFlags | BindingFlags.NonPublic,
843 if (lookup == null) {
844 if (class_name != null) {
845 Report.Error (103, loc, "The name `{0}' does not exist in the current context",
848 Error_TypeDoesNotContainDefinition (queried_type, name);
853 if (TypeManager.MemberLookup (queried_type, null, queried_type,
854 AllMemberTypes, AllBindingFlags |
855 BindingFlags.NonPublic, name, null) == null) {
856 if ((lookup.Length == 1) && (lookup [0] is Type)) {
857 Type t = (Type) lookup [0];
859 Report.Error (305, loc,
860 "Using the generic type `{0}' " +
861 "requires {1} type arguments",
862 TypeManager.CSharpName (t),
863 TypeManager.GetNumberOfTypeArguments (t).ToString ());
868 return Error_MemberLookupFailed (lookup);
871 protected virtual Expression Error_MemberLookupFailed (MemberInfo[] members)
873 for (int i = 0; i < members.Length; ++i) {
874 if (!(members [i] is MethodBase))
878 // By default propagate the closest candidates upwards
879 return new MethodGroupExpr (members, type, loc);
883 /// Returns an expression that can be used to invoke operator true
884 /// on the expression if it exists.
886 static public Expression GetOperatorTrue (EmitContext ec, Expression e, Location loc)
888 return GetOperatorTrueOrFalse (ec, e, true, loc);
892 /// Returns an expression that can be used to invoke operator false
893 /// on the expression if it exists.
895 static public Expression GetOperatorFalse (EmitContext ec, Expression e, Location loc)
897 return GetOperatorTrueOrFalse (ec, e, false, loc);
900 static Expression GetOperatorTrueOrFalse (EmitContext ec, Expression e, bool is_true, Location loc)
902 MethodGroupExpr operator_group;
905 if (TypeManager.IsNullableType (e.Type))
906 return new Nullable.OperatorTrueOrFalse (e, is_true, loc).Resolve (ec);
909 operator_group = MethodLookup (ec.ContainerType, e.Type, is_true ? "op_True" : "op_False", loc) as MethodGroupExpr;
910 if (operator_group == null)
913 ArrayList arguments = new ArrayList (1);
914 arguments.Add (new Argument (e, Argument.AType.Expression));
915 operator_group = operator_group.OverloadResolve (
916 ec, arguments, false, loc);
918 if (operator_group == null)
921 return new StaticCallExpr ((MethodInfo) operator_group, arguments, loc);
925 /// Resolves the expression `e' into a boolean expression: either through
926 /// an implicit conversion, or through an `operator true' invocation
928 public static Expression ResolveBoolean (EmitContext ec, Expression e, Location loc)
934 if (e.Type == TypeManager.bool_type)
937 Expression converted = Convert.ImplicitConversion (ec, e, TypeManager.bool_type, Location.Null);
939 if (converted != null)
943 // If no implicit conversion to bool exists, try using `operator true'
945 converted = Expression.GetOperatorTrue (ec, e, loc);
946 if (converted == null){
947 e.Error_ValueCannotBeConverted (ec, loc, TypeManager.bool_type, false);
953 public virtual string ExprClassName
957 case ExprClass.Invalid:
959 case ExprClass.Value:
961 case ExprClass.Variable:
963 case ExprClass.Namespace:
967 case ExprClass.MethodGroup:
968 return "method group";
969 case ExprClass.PropertyAccess:
970 return "property access";
971 case ExprClass.EventAccess:
972 return "event access";
973 case ExprClass.IndexerAccess:
974 return "indexer access";
975 case ExprClass.Nothing:
978 throw new Exception ("Should not happen");
983 /// Reports that we were expecting `expr' to be of class `expected'
985 public void Error_UnexpectedKind (DeclSpace ds, string expected, Location loc)
987 Error_UnexpectedKind (ds, expected, ExprClassName, loc);
990 public void Error_UnexpectedKind (DeclSpace ds, string expected, string was, Location loc)
992 string name = GetSignatureForError ();
994 name = ds.GetSignatureForError () + '.' + name;
996 Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
997 name, was, expected);
1000 public void Error_UnexpectedKind (ResolveFlags flags, Location loc)
1002 string [] valid = new string [4];
1005 if ((flags & ResolveFlags.VariableOrValue) != 0) {
1006 valid [count++] = "variable";
1007 valid [count++] = "value";
1010 if ((flags & ResolveFlags.Type) != 0)
1011 valid [count++] = "type";
1013 if ((flags & ResolveFlags.MethodGroup) != 0)
1014 valid [count++] = "method group";
1017 valid [count++] = "unknown";
1019 StringBuilder sb = new StringBuilder (valid [0]);
1020 for (int i = 1; i < count - 1; i++) {
1022 sb.Append (valid [i]);
1025 sb.Append ("' or `");
1026 sb.Append (valid [count - 1]);
1029 Report.Error (119, loc,
1030 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1033 public static void UnsafeError (Location loc)
1035 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1039 // Load the object from the pointer.
1041 public static void LoadFromPtr (ILGenerator ig, Type t)
1043 if (t == TypeManager.int32_type)
1044 ig.Emit (OpCodes.Ldind_I4);
1045 else if (t == TypeManager.uint32_type)
1046 ig.Emit (OpCodes.Ldind_U4);
1047 else if (t == TypeManager.short_type)
1048 ig.Emit (OpCodes.Ldind_I2);
1049 else if (t == TypeManager.ushort_type)
1050 ig.Emit (OpCodes.Ldind_U2);
1051 else if (t == TypeManager.char_type)
1052 ig.Emit (OpCodes.Ldind_U2);
1053 else if (t == TypeManager.byte_type)
1054 ig.Emit (OpCodes.Ldind_U1);
1055 else if (t == TypeManager.sbyte_type)
1056 ig.Emit (OpCodes.Ldind_I1);
1057 else if (t == TypeManager.uint64_type)
1058 ig.Emit (OpCodes.Ldind_I8);
1059 else if (t == TypeManager.int64_type)
1060 ig.Emit (OpCodes.Ldind_I8);
1061 else if (t == TypeManager.float_type)
1062 ig.Emit (OpCodes.Ldind_R4);
1063 else if (t == TypeManager.double_type)
1064 ig.Emit (OpCodes.Ldind_R8);
1065 else if (t == TypeManager.bool_type)
1066 ig.Emit (OpCodes.Ldind_I1);
1067 else if (t == TypeManager.intptr_type)
1068 ig.Emit (OpCodes.Ldind_I);
1069 else if (TypeManager.IsEnumType (t)) {
1070 if (t == TypeManager.enum_type)
1071 ig.Emit (OpCodes.Ldind_Ref);
1073 LoadFromPtr (ig, TypeManager.EnumToUnderlying (t));
1074 } else if (t.IsValueType || TypeManager.IsGenericParameter (t))
1075 ig.Emit (OpCodes.Ldobj, t);
1076 else if (t.IsPointer)
1077 ig.Emit (OpCodes.Ldind_I);
1079 ig.Emit (OpCodes.Ldind_Ref);
1083 // The stack contains the pointer and the value of type `type'
1085 public static void StoreFromPtr (ILGenerator ig, Type type)
1087 if (TypeManager.IsEnumType (type))
1088 type = TypeManager.EnumToUnderlying (type);
1089 if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
1090 ig.Emit (OpCodes.Stind_I4);
1091 else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
1092 ig.Emit (OpCodes.Stind_I8);
1093 else if (type == TypeManager.char_type || type == TypeManager.short_type ||
1094 type == TypeManager.ushort_type)
1095 ig.Emit (OpCodes.Stind_I2);
1096 else if (type == TypeManager.float_type)
1097 ig.Emit (OpCodes.Stind_R4);
1098 else if (type == TypeManager.double_type)
1099 ig.Emit (OpCodes.Stind_R8);
1100 else if (type == TypeManager.byte_type || type == TypeManager.sbyte_type ||
1101 type == TypeManager.bool_type)
1102 ig.Emit (OpCodes.Stind_I1);
1103 else if (type == TypeManager.intptr_type)
1104 ig.Emit (OpCodes.Stind_I);
1105 else if (type.IsValueType || TypeManager.IsGenericParameter (type))
1106 ig.Emit (OpCodes.Stobj, type);
1108 ig.Emit (OpCodes.Stind_Ref);
1112 // Returns the size of type `t' if known, otherwise, 0
1114 public static int GetTypeSize (Type t)
1116 t = TypeManager.TypeToCoreType (t);
1117 if (t == TypeManager.int32_type ||
1118 t == TypeManager.uint32_type ||
1119 t == TypeManager.float_type)
1121 else if (t == TypeManager.int64_type ||
1122 t == TypeManager.uint64_type ||
1123 t == TypeManager.double_type)
1125 else if (t == TypeManager.byte_type ||
1126 t == TypeManager.sbyte_type ||
1127 t == TypeManager.bool_type)
1129 else if (t == TypeManager.short_type ||
1130 t == TypeManager.char_type ||
1131 t == TypeManager.ushort_type)
1133 else if (t == TypeManager.decimal_type)
1139 public static void Error_NegativeArrayIndex (Location loc)
1141 Report.Error (248, loc, "Cannot create an array with a negative size");
1144 protected void Error_CannotCallAbstractBase (string name)
1146 Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
1150 // Converts `source' to an int, uint, long or ulong.
1152 public Expression ExpressionToArrayArgument (EmitContext ec, Expression source, Location loc)
1156 using (ec.With (EmitContext.Flags.CheckState, true)) {
1157 target = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, loc);
1159 target = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, loc);
1161 target = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, loc);
1163 target = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, loc);
1165 if (target == null) {
1166 source.Error_ValueCannotBeConverted (ec, loc, TypeManager.int32_type, false);
1172 // Only positive constants are allowed at compile time
1174 if (target is Constant){
1175 if (target is IntConstant){
1176 if (((IntConstant) target).Value < 0){
1177 Error_NegativeArrayIndex (loc);
1182 if (target is LongConstant){
1183 if (((LongConstant) target).Value < 0){
1184 Error_NegativeArrayIndex (loc);
1195 // Derived classes implement this method by cloning the fields that
1196 // could become altered during the Resolve stage
1198 // Only expressions that are created for the parser need to implement
1201 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1203 throw new NotImplementedException (
1205 "CloneTo not implemented for expression {0}", this.GetType ()));
1209 // Clones an expression created by the parser.
1211 // We only support expressions created by the parser so far, not
1212 // expressions that have been resolved (many more classes would need
1213 // to implement CloneTo).
1215 // This infrastructure is here merely for Lambda expressions which
1216 // compile the same code using different type values for the same
1217 // arguments to find the correct overload
1219 public Expression Clone (CloneContext clonectx)
1221 Expression cloned = (Expression) MemberwiseClone ();
1222 CloneTo (clonectx, cloned);
1229 /// This is just a base class for expressions that can
1230 /// appear on statements (invocations, object creation,
1231 /// assignments, post/pre increment and decrement). The idea
1232 /// being that they would support an extra Emition interface that
1233 /// does not leave a result on the stack.
1235 public abstract class ExpressionStatement : Expression {
1237 public virtual ExpressionStatement ResolveStatement (EmitContext ec)
1239 Expression e = Resolve (ec);
1243 ExpressionStatement es = e as ExpressionStatement;
1245 Error_InvalidExpressionStatement ();
1251 /// Requests the expression to be emitted in a `statement'
1252 /// context. This means that no new value is left on the
1253 /// stack after invoking this method (constrasted with
1254 /// Emit that will always leave a value on the stack).
1256 public abstract void EmitStatement (EmitContext ec);
1260 /// This kind of cast is used to encapsulate the child
1261 /// whose type is child.Type into an expression that is
1262 /// reported to return "return_type". This is used to encapsulate
1263 /// expressions which have compatible types, but need to be dealt
1264 /// at higher levels with.
1266 /// For example, a "byte" expression could be encapsulated in one
1267 /// of these as an "unsigned int". The type for the expression
1268 /// would be "unsigned int".
1271 public class EmptyCast : Expression
1273 protected Expression child;
1275 protected EmptyCast (Expression child, Type return_type)
1277 eclass = child.eclass;
1278 loc = child.Location;
1283 public static Expression Create (Expression child, Type type)
1285 Constant c = child as Constant;
1287 return new EmptyConstantCast (c, type);
1289 return new EmptyCast (child, type);
1292 public override Expression DoResolve (EmitContext ec)
1294 // This should never be invoked, we are born in fully
1295 // initialized state.
1300 public override void Emit (EmitContext ec)
1305 public override bool GetAttributableValue (Type value_type, out object value)
1307 return child.GetAttributableValue (value_type, out value);
1310 protected override void CloneTo (CloneContext clonectx, Expression t)
1312 EmptyCast target = (EmptyCast) t;
1314 target.child = child.Clone (clonectx);
1319 /// Performs a cast using an operator (op_Explicit or op_Implicit)
1321 public class OperatorCast : EmptyCast {
1322 MethodInfo conversion_operator;
1325 public OperatorCast (Expression child, Type target_type) : this (child, target_type, false) {}
1327 public OperatorCast (Expression child, Type target_type, bool find_explicit)
1328 : base (child, target_type)
1330 this.find_explicit = find_explicit;
1333 // Returns the implicit operator that converts from
1334 // 'child.Type' to our target type (type)
1335 MethodInfo GetConversionOperator (bool find_explicit)
1337 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1341 mi = TypeManager.MemberLookup (child.Type, child.Type, child.Type, MemberTypes.Method,
1342 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1345 mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1346 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1349 foreach (MethodInfo oper in mi) {
1350 ParameterData pd = TypeManager.GetParameterData (oper);
1352 if (pd.ParameterType (0) == child.Type && oper.ReturnType == type)
1360 public override void Emit (EmitContext ec)
1362 ILGenerator ig = ec.ig;
1365 conversion_operator = GetConversionOperator (find_explicit);
1367 if (conversion_operator == null)
1368 throw new InternalErrorException ("Outer conversion routine is out of sync");
1370 ig.Emit (OpCodes.Call, conversion_operator);
1376 /// This is a numeric cast to a Decimal
1378 public class CastToDecimal : EmptyCast {
1379 MethodInfo conversion_operator;
1381 public CastToDecimal (Expression child)
1382 : this (child, false)
1386 public CastToDecimal (Expression child, bool find_explicit)
1387 : base (child, TypeManager.decimal_type)
1389 conversion_operator = GetConversionOperator (find_explicit);
1391 if (conversion_operator == null)
1392 throw new InternalErrorException ("Outer conversion routine is out of sync");
1395 // Returns the implicit operator that converts from
1396 // 'child.Type' to System.Decimal.
1397 MethodInfo GetConversionOperator (bool find_explicit)
1399 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1401 MemberInfo [] mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1402 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1404 foreach (MethodInfo oper in mi) {
1405 ParameterData pd = TypeManager.GetParameterData (oper);
1407 if (pd.ParameterType (0) == child.Type && oper.ReturnType == type)
1413 public override void Emit (EmitContext ec)
1415 ILGenerator ig = ec.ig;
1418 ig.Emit (OpCodes.Call, conversion_operator);
1423 /// This is an explicit numeric cast from a Decimal
1425 public class CastFromDecimal : EmptyCast
1427 static IDictionary operators;
1429 public CastFromDecimal (Expression child, Type return_type)
1430 : base (child, return_type)
1432 if (child.Type != TypeManager.decimal_type)
1433 throw new InternalErrorException (
1434 "The expected type is Decimal, instead it is " + child.Type.FullName);
1437 // Returns the explicit operator that converts from an
1438 // express of type System.Decimal to 'type'.
1439 public Expression Resolve ()
1441 if (operators == null) {
1442 MemberInfo[] all_oper = TypeManager.MemberLookup (TypeManager.decimal_type,
1443 TypeManager.decimal_type, TypeManager.decimal_type, MemberTypes.Method,
1444 BindingFlags.Static | BindingFlags.Public, "op_Explicit", null);
1446 operators = new System.Collections.Specialized.HybridDictionary ();
1447 foreach (MethodInfo oper in all_oper) {
1448 ParameterData pd = TypeManager.GetParameterData (oper);
1449 if (pd.ParameterType (0) == TypeManager.decimal_type)
1450 operators.Add (oper.ReturnType, oper);
1454 return operators.Contains (type) ? this : null;
1457 public override void Emit (EmitContext ec)
1459 ILGenerator ig = ec.ig;
1462 ig.Emit (OpCodes.Call, (MethodInfo)operators [type]);
1468 // Constant specialization of EmptyCast.
1469 // We need to special case this since an empty cast of
1470 // a constant is still a constant.
1472 public class EmptyConstantCast : Constant
1474 public readonly Constant child;
1476 public EmptyConstantCast(Constant child, Type type)
1477 : base (child.Location)
1479 eclass = child.eclass;
1484 public override string AsString ()
1486 return child.AsString ();
1489 public override object GetValue ()
1491 return child.GetValue ();
1494 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
1496 // FIXME: check that 'type' can be converted to 'target_type' first
1497 return child.ConvertExplicitly (in_checked_context, target_type);
1500 public override Constant Increment ()
1502 return child.Increment ();
1505 public override bool IsDefaultValue {
1506 get { return child.IsDefaultValue; }
1509 public override bool IsNegative {
1510 get { return child.IsNegative; }
1513 public override bool IsZeroInteger {
1514 get { return child.IsZeroInteger; }
1517 public override void Emit (EmitContext ec)
1522 public override Constant ConvertImplicitly (Type target_type)
1524 // FIXME: Do we need to check user conversions?
1525 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1527 return child.ConvertImplicitly (target_type);
1533 /// This class is used to wrap literals which belong inside Enums
1535 public class EnumConstant : Constant {
1536 public Constant Child;
1538 public EnumConstant (Constant child, Type enum_type):
1539 base (child.Location)
1541 eclass = child.eclass;
1546 public override Expression DoResolve (EmitContext ec)
1548 // This should never be invoked, we are born in fully
1549 // initialized state.
1554 public override void Emit (EmitContext ec)
1559 public override bool GetAttributableValue (Type value_type, out object value)
1561 value = GetTypedValue ();
1565 public override string GetSignatureForError()
1567 return TypeManager.CSharpName (Type);
1570 public override object GetValue ()
1572 return Child.GetValue ();
1575 public override object GetTypedValue ()
1577 // FIXME: runtime is not ready to work with just emited enums
1578 if (!RootContext.StdLib) {
1579 return Child.GetValue ();
1582 return System.Enum.ToObject (type, Child.GetValue ());
1585 public override string AsString ()
1587 return TypeManager.CSharpEnumValue (type, Child.GetValue ());
1590 public override Constant Increment()
1592 return new EnumConstant (Child.Increment (), type);
1595 public override bool IsDefaultValue {
1597 return Child.IsDefaultValue;
1601 public override bool IsZeroInteger {
1602 get { return Child.IsZeroInteger; }
1605 public override bool IsNegative {
1607 return Child.IsNegative;
1611 public override Constant ConvertExplicitly(bool in_checked_context, Type target_type)
1613 if (Child.Type == target_type)
1616 return Child.ConvertExplicitly (in_checked_context, target_type);
1619 public override Constant ConvertImplicitly (Type type)
1621 Type this_type = TypeManager.DropGenericTypeArguments (Type);
1622 type = TypeManager.DropGenericTypeArguments (type);
1624 if (this_type == type) {
1625 // This is workaround of mono bug. It can be removed when the latest corlib spreads enough
1626 if (TypeManager.IsEnumType (type.UnderlyingSystemType))
1629 Type child_type = TypeManager.DropGenericTypeArguments (Child.Type);
1630 if (type.UnderlyingSystemType != child_type)
1631 Child = Child.ConvertImplicitly (type.UnderlyingSystemType);
1635 if (!Convert.ImplicitStandardConversionExists (this, type)){
1639 return Child.ConvertImplicitly(type);
1645 /// This kind of cast is used to encapsulate Value Types in objects.
1647 /// The effect of it is to box the value type emitted by the previous
1650 public class BoxedCast : EmptyCast {
1652 public BoxedCast (Expression expr, Type target_type)
1653 : base (expr, target_type)
1655 eclass = ExprClass.Value;
1658 public override Expression DoResolve (EmitContext ec)
1660 // This should never be invoked, we are born in fully
1661 // initialized state.
1666 public override void Emit (EmitContext ec)
1670 ec.ig.Emit (OpCodes.Box, child.Type);
1674 public class UnboxCast : EmptyCast {
1675 public UnboxCast (Expression expr, Type return_type)
1676 : base (expr, return_type)
1680 public override Expression DoResolve (EmitContext ec)
1682 // This should never be invoked, we are born in fully
1683 // initialized state.
1688 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1690 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
1691 Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
1692 return base.DoResolveLValue (ec, right_side);
1695 public override void Emit (EmitContext ec)
1698 ILGenerator ig = ec.ig;
1702 if (t.IsGenericParameter || t.IsGenericType && t.IsValueType)
1703 ig.Emit (OpCodes.Unbox_Any, t);
1707 ig.Emit (OpCodes.Unbox, t);
1709 LoadFromPtr (ig, t);
1715 /// This is used to perform explicit numeric conversions.
1717 /// Explicit numeric conversions might trigger exceptions in a checked
1718 /// context, so they should generate the conv.ovf opcodes instead of
1721 public class ConvCast : EmptyCast {
1722 public enum Mode : byte {
1723 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1725 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1726 U2_I1, U2_U1, U2_I2, U2_CH,
1727 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1728 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1729 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH,
1730 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH,
1731 CH_I1, CH_U1, CH_I2,
1732 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1733 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4
1738 public ConvCast (Expression child, Type return_type, Mode m)
1739 : base (child, return_type)
1744 public override Expression DoResolve (EmitContext ec)
1746 // This should never be invoked, we are born in fully
1747 // initialized state.
1752 public override string ToString ()
1754 return String.Format ("ConvCast ({0}, {1})", mode, child);
1757 public override void Emit (EmitContext ec)
1759 ILGenerator ig = ec.ig;
1765 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1766 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1767 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1768 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1769 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1771 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1772 case Mode.U1_CH: /* nothing */ break;
1774 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1775 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1776 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1777 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1778 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1779 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1781 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1782 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1783 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1784 case Mode.U2_CH: /* nothing */ break;
1786 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1787 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1788 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1789 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1790 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1791 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1792 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1794 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1795 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1796 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1797 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1798 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1799 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1801 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1802 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1803 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1804 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1805 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1806 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1807 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1808 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1810 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1811 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1812 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1813 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1814 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1815 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1816 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1817 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1819 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1820 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1821 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1823 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1824 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1825 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1826 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1827 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1828 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1829 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1830 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1831 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1833 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1834 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1835 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1836 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1837 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1838 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1839 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1840 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1841 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1842 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1846 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
1847 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
1848 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
1849 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
1850 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
1852 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
1853 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
1855 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
1856 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
1857 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
1858 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
1859 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
1860 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
1862 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
1863 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
1864 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
1865 case Mode.U2_CH: /* nothing */ break;
1867 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
1868 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
1869 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
1870 case Mode.I4_U4: /* nothing */ break;
1871 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
1872 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
1873 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
1875 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
1876 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
1877 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
1878 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
1879 case Mode.U4_I4: /* nothing */ break;
1880 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
1882 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
1883 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
1884 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
1885 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
1886 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
1887 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
1888 case Mode.I8_U8: /* nothing */ break;
1889 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
1891 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
1892 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
1893 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
1894 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
1895 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
1896 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
1897 case Mode.U8_I8: /* nothing */ break;
1898 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
1900 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
1901 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
1902 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
1904 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
1905 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
1906 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
1907 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
1908 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
1909 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
1910 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
1911 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
1912 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
1914 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
1915 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
1916 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
1917 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
1918 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
1919 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
1920 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
1921 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
1922 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
1923 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1929 public class OpcodeCast : EmptyCast {
1933 public OpcodeCast (Expression child, Type return_type, OpCode op)
1934 : base (child, return_type)
1938 second_valid = false;
1941 public OpcodeCast (Expression child, Type return_type, OpCode op, OpCode op2)
1942 : base (child, return_type)
1947 second_valid = true;
1950 public override Expression DoResolve (EmitContext ec)
1952 // This should never be invoked, we are born in fully
1953 // initialized state.
1958 public override void Emit (EmitContext ec)
1969 /// This kind of cast is used to encapsulate a child and cast it
1970 /// to the class requested
1972 public class ClassCast : EmptyCast {
1973 public ClassCast (Expression child, Type return_type)
1974 : base (child, return_type)
1979 public override Expression DoResolve (EmitContext ec)
1981 // This should never be invoked, we are born in fully
1982 // initialized state.
1987 public override void Emit (EmitContext ec)
1991 if (TypeManager.IsGenericParameter (child.Type))
1992 ec.ig.Emit (OpCodes.Box, child.Type);
1995 if (type.IsGenericParameter)
1996 ec.ig.Emit (OpCodes.Unbox_Any, type);
1999 ec.ig.Emit (OpCodes.Castclass, type);
2004 /// SimpleName expressions are formed of a single word and only happen at the beginning
2005 /// of a dotted-name.
2007 public class SimpleName : Expression {
2008 public readonly string Name;
2009 public readonly TypeArguments Arguments;
2012 public SimpleName (string name, Location l)
2018 public SimpleName (string name, TypeArguments args, Location l)
2025 public SimpleName (string name, TypeParameter[] type_params, Location l)
2030 Arguments = new TypeArguments (l);
2031 foreach (TypeParameter type_param in type_params)
2032 Arguments.Add (new TypeParameterExpr (type_param, l));
2035 public static string RemoveGenericArity (string name)
2038 StringBuilder sb = null;
2040 int pos = name.IndexOf ('`', start);
2045 sb.Append (name.Substring (start));
2050 sb = new StringBuilder ();
2051 sb.Append (name.Substring (start, pos-start));
2054 while ((pos < name.Length) && Char.IsNumber (name [pos]))
2058 } while (start < name.Length);
2060 return sb.ToString ();
2063 public SimpleName GetMethodGroup ()
2065 return new SimpleName (RemoveGenericArity (Name), Arguments, loc);
2068 public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
2070 if (ec.IsInFieldInitializer)
2071 Report.Error (236, l,
2072 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2076 120, l, "`{0}': An object reference is required for the nonstatic field, method or property",
2080 public bool IdenticalNameAndTypeName (EmitContext ec, Expression resolved_to, Location loc)
2082 return resolved_to != null && resolved_to.Type != null &&
2083 resolved_to.Type.Name == Name &&
2084 (ec.DeclContainer.LookupNamespaceOrType (Name, loc, /* ignore_cs0104 = */ true) != null);
2087 public override Expression DoResolve (EmitContext ec)
2089 return SimpleNameResolve (ec, null, false);
2092 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
2094 return SimpleNameResolve (ec, right_side, false);
2098 public Expression DoResolve (EmitContext ec, bool intermediate)
2100 return SimpleNameResolve (ec, null, intermediate);
2103 private bool IsNestedChild (Type t, Type parent)
2108 while (parent != null) {
2109 parent = TypeManager.DropGenericTypeArguments (parent);
2110 if (TypeManager.IsNestedChildOf (t, parent))
2113 parent = parent.BaseType;
2119 FullNamedExpression ResolveNested (IResolveContext ec, Type t)
2121 if (!TypeManager.IsGenericTypeDefinition (t) && !TypeManager.IsGenericType (t))
2124 DeclSpace ds = ec.DeclContainer;
2125 while (ds != null) {
2126 if (IsNestedChild (t, ds.TypeBuilder))
2135 Type[] gen_params = TypeManager.GetTypeArguments (t);
2137 int arg_count = Arguments != null ? Arguments.Count : 0;
2139 for (; (ds != null) && ds.IsGeneric; ds = ds.Parent) {
2140 if (arg_count + ds.CountTypeParameters == gen_params.Length) {
2141 TypeArguments new_args = new TypeArguments (loc);
2142 foreach (TypeParameter param in ds.TypeParameters)
2143 new_args.Add (new TypeParameterExpr (param, loc));
2145 if (Arguments != null)
2146 new_args.Add (Arguments);
2148 return new ConstructedType (t, new_args, loc);
2155 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2157 FullNamedExpression fne = ec.GenericDeclContainer.LookupGeneric (Name, loc);
2159 return fne.ResolveAsTypeStep (ec, silent);
2161 int errors = Report.Errors;
2162 fne = ec.DeclContainer.LookupNamespaceOrType (Name, loc, /*ignore_cs0104=*/ false);
2165 if (fne.Type == null)
2168 FullNamedExpression nested = ResolveNested (ec, fne.Type);
2170 return nested.ResolveAsTypeStep (ec, false);
2172 if (Arguments != null) {
2173 ConstructedType ct = new ConstructedType (fne, Arguments, loc);
2174 return ct.ResolveAsTypeStep (ec, false);
2180 if (silent || errors != Report.Errors)
2183 Error_TypeOrNamespaceNotFound (ec);
2187 protected virtual void Error_TypeOrNamespaceNotFound (IResolveContext ec)
2189 MemberCore mc = ec.DeclContainer.GetDefinition (Name);
2191 Error_UnexpectedKind (ec.DeclContainer, "type", GetMemberType (mc), loc);
2195 string ns = ec.DeclContainer.NamespaceEntry.NS.Name;
2196 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2197 foreach (Assembly a in RootNamespace.Global.Assemblies) {
2198 Type type = a.GetType (fullname);
2200 Report.SymbolRelatedToPreviousError (type);
2201 Expression.ErrorIsInaccesible (loc, TypeManager.CSharpName (type));
2206 Type t = ec.DeclContainer.LookupAnyGeneric (Name);
2208 Namespace.Error_InvalidNumberOfTypeArguments (t, loc);
2212 if (Arguments != null) {
2213 FullNamedExpression retval = ec.DeclContainer.LookupNamespaceOrType (SimpleName.RemoveGenericArity (Name), loc, true);
2214 if (retval != null) {
2215 Namespace.Error_TypeArgumentsCannotBeUsed (retval.Type, loc, "type");
2220 NamespaceEntry.Error_NamespaceNotFound (loc, Name);
2223 // TODO: I am still not convinced about this. If someone else will need it
2224 // implement this as virtual property in MemberCore hierarchy
2225 public static string GetMemberType (MemberCore mc)
2231 if (mc is FieldBase)
2233 if (mc is MethodCore)
2235 if (mc is EnumMember)
2243 Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2249 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2255 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2262 /// 7.5.2: Simple Names.
2264 /// Local Variables and Parameters are handled at
2265 /// parse time, so they never occur as SimpleNames.
2267 /// The `intermediate' flag is used by MemberAccess only
2268 /// and it is used to inform us that it is ok for us to
2269 /// avoid the static check, because MemberAccess might end
2270 /// up resolving the Name as a Type name and the access as
2271 /// a static type access.
2273 /// ie: Type Type; .... { Type.GetType (""); }
2275 /// Type is both an instance variable and a Type; Type.GetType
2276 /// is the static method not an instance method of type.
2278 Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2280 Expression e = null;
2283 // Stage 1: Performed by the parser (binding to locals or parameters).
2285 Block current_block = ec.CurrentBlock;
2286 if (current_block != null){
2287 LocalInfo vi = current_block.GetLocalInfo (Name);
2289 if (Arguments != null) {
2290 Report.Error (307, loc,
2291 "The variable `{0}' cannot be used with type arguments",
2296 LocalVariableReference var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2297 if (right_side != null) {
2298 return var.ResolveLValue (ec, right_side, loc);
2300 ResolveFlags rf = ResolveFlags.VariableOrValue;
2302 rf |= ResolveFlags.DisableFlowAnalysis;
2303 return var.Resolve (ec, rf);
2307 ParameterReference pref = current_block.Toplevel.GetParameterReference (Name, loc);
2309 if (Arguments != null) {
2310 Report.Error (307, loc,
2311 "The variable `{0}' cannot be used with type arguments",
2316 if (right_side != null)
2317 return pref.ResolveLValue (ec, right_side, loc);
2319 return pref.Resolve (ec);
2322 Expression expr = current_block.Toplevel.GetTransparentIdentifier (Name);
2324 if (right_side != null)
2325 return expr.ResolveLValue (ec, right_side, loc);
2326 return expr.Resolve (ec);
2331 // Stage 2: Lookup members
2334 Type almost_matched_type = null;
2335 ArrayList almost_matched = null;
2336 for (DeclSpace lookup_ds = ec.DeclContainer; lookup_ds != null; lookup_ds = lookup_ds.Parent) {
2337 // either RootDeclSpace or GenericMethod
2338 if (lookup_ds.TypeBuilder == null)
2341 e = MemberLookup (ec.ContainerType, lookup_ds.TypeBuilder, Name, loc);
2343 if (e is PropertyExpr) {
2344 // since TypeManager.MemberLookup doesn't know if we're doing a lvalue access or not,
2345 // it doesn't know which accessor to check permissions against
2346 if (((PropertyExpr) e).IsAccessibleFrom (ec.ContainerType, right_side != null))
2348 } else if (e is EventExpr) {
2349 if (((EventExpr) e).IsAccessibleFrom (ec.ContainerType))
2357 if (almost_matched == null && almost_matched_members.Count > 0) {
2358 almost_matched_type = lookup_ds.TypeBuilder;
2359 almost_matched = (ArrayList) almost_matched_members.Clone ();
2364 if (almost_matched == null && almost_matched_members.Count > 0) {
2365 almost_matched_type = ec.ContainerType;
2366 almost_matched = (ArrayList) almost_matched_members.Clone ();
2368 e = ResolveAsTypeStep (ec, true);
2372 if (current_block != null) {
2373 IKnownVariable ikv = current_block.Explicit.GetKnownVariable (Name);
2375 LocalInfo li = ikv as LocalInfo;
2376 // Supress CS0219 warning
2380 Error_VariableIsUsedBeforeItIsDeclared (Name);
2385 if (almost_matched != null)
2386 almost_matched_members = almost_matched;
2387 if (almost_matched_type == null)
2388 almost_matched_type = ec.ContainerType;
2389 Error_MemberLookupFailed (ec.ContainerType, null, almost_matched_type, Name,
2390 ec.DeclContainer.Name, AllMemberTypes, AllBindingFlags);
2394 if (e is TypeExpr) {
2395 if (Arguments == null)
2398 ConstructedType ct = new ConstructedType (
2399 (FullNamedExpression) e, Arguments, loc);
2400 return ct.ResolveAsTypeStep (ec, false);
2403 if (e is MemberExpr) {
2404 MemberExpr me = (MemberExpr) e;
2407 if (me.IsInstance) {
2408 if (ec.IsStatic || ec.IsInFieldInitializer) {
2410 // Note that an MemberExpr can be both IsInstance and IsStatic.
2411 // An unresolved MethodGroupExpr can contain both kinds of methods
2412 // and each predicate is true if the MethodGroupExpr contains
2413 // at least one of that kind of method.
2417 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2418 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2419 return EmptyExpression.Null;
2423 // Pass the buck to MemberAccess and Invocation.
2425 left = EmptyExpression.Null;
2427 left = ec.GetThis (loc);
2430 left = new TypeExpression (ec.ContainerType, loc);
2433 e = me.ResolveMemberAccess (ec, left, loc, null);
2437 me = e as MemberExpr;
2441 if (Arguments != null) {
2442 MethodGroupExpr mg = me as MethodGroupExpr;
2446 return mg.ResolveGeneric (ec, Arguments);
2449 if (!me.IsStatic && (me.InstanceExpression != null) &&
2450 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2451 me.InstanceExpression.Type != me.DeclaringType &&
2452 !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2453 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2454 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2455 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2459 return (right_side != null)
2460 ? me.DoResolveLValue (ec, right_side)
2461 : me.DoResolve (ec);
2467 public override void Emit (EmitContext ec)
2469 throw new InternalErrorException ("The resolve phase was not executed");
2472 public override string ToString ()
2477 public override string GetSignatureForError ()
2479 if (Arguments != null) {
2480 return TypeManager.RemoveGenericArity (Name) + "<" +
2481 Arguments.GetSignatureForError () + ">";
2487 protected override void CloneTo (CloneContext clonectx, Expression target)
2489 // CloneTo: Nothing, we do not keep any state on this expression
2494 /// Represents a namespace or a type. The name of the class was inspired by
2495 /// section 10.8.1 (Fully Qualified Names).
2497 public abstract class FullNamedExpression : Expression {
2498 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2503 public abstract string FullName {
2509 /// Expression that evaluates to a type
2511 public abstract class TypeExpr : FullNamedExpression {
2512 override public FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2514 TypeExpr t = DoResolveAsTypeStep (ec);
2518 eclass = ExprClass.Type;
2522 override public Expression DoResolve (EmitContext ec)
2524 return ResolveAsTypeTerminal (ec, false);
2527 override public void Emit (EmitContext ec)
2529 throw new Exception ("Should never be called");
2532 public virtual bool CheckAccessLevel (DeclSpace ds)
2534 return ds.CheckAccessLevel (Type);
2537 public virtual bool AsAccessible (DeclSpace ds, int flags)
2539 return ds.AsAccessible (Type, flags);
2542 public virtual bool IsClass {
2543 get { return Type.IsClass; }
2546 public virtual bool IsValueType {
2547 get { return Type.IsValueType; }
2550 public virtual bool IsInterface {
2551 get { return Type.IsInterface; }
2554 public virtual bool IsSealed {
2555 get { return Type.IsSealed; }
2558 public virtual bool CanInheritFrom ()
2560 if (Type == TypeManager.enum_type ||
2561 (Type == TypeManager.value_type && RootContext.StdLib) ||
2562 Type == TypeManager.multicast_delegate_type ||
2563 Type == TypeManager.delegate_type ||
2564 Type == TypeManager.array_type)
2570 protected abstract TypeExpr DoResolveAsTypeStep (IResolveContext ec);
2572 public abstract string Name {
2576 public override bool Equals (object obj)
2578 TypeExpr tobj = obj as TypeExpr;
2582 return Type == tobj.Type;
2585 public override int GetHashCode ()
2587 return Type.GetHashCode ();
2590 public override string ToString ()
2597 /// Fully resolved Expression that already evaluated to a type
2599 public class TypeExpression : TypeExpr {
2600 public TypeExpression (Type t, Location l)
2603 eclass = ExprClass.Type;
2607 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2612 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2617 public override string Name {
2618 get { return Type.ToString (); }
2621 public override string FullName {
2622 get { return Type.FullName; }
2627 /// Used to create types from a fully qualified name. These are just used
2628 /// by the parser to setup the core types. A TypeLookupExpression is always
2629 /// classified as a type.
2631 public sealed class TypeLookupExpression : TypeExpr {
2632 readonly string name;
2634 public TypeLookupExpression (string name)
2637 eclass = ExprClass.Type;
2640 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2642 // It's null for corlib compilation only
2644 return DoResolveAsTypeStep (ec);
2649 private class UnexpectedType
2653 // This performes recursive type lookup, providing support for generic types.
2654 // For example, given the type:
2656 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]]
2658 // The types will be checked in the following order:
2661 // System.Collections |
2662 // System.Collections.Generic |
2664 // System | recursive call 1 |
2665 // System.Int32 _| | main method call
2667 // System | recursive call 2 |
2668 // System.String _| |
2670 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]] _|
2672 private Type TypeLookup (IResolveContext ec, string name)
2677 FullNamedExpression resolved = null;
2679 Type recursive_type = null;
2680 while (index < name.Length) {
2681 if (name[index] == '[') {
2686 if (name[index] == '[')
2688 else if (name[index] == ']')
2690 } while (braces > 0);
2691 recursive_type = TypeLookup (ec, name.Substring (open + 1, index - open - 1));
2692 if (recursive_type == null || (recursive_type == typeof(UnexpectedType)))
2693 return recursive_type;
2696 if (name[index] == ',')
2698 else if ((name[index] == '.' && !done) || (index == name.Length && name[0] != '[')) {
2699 string substring = name.Substring(dot, index - dot);
2701 if (resolved == null)
2702 resolved = RootNamespace.Global.Lookup (ec.DeclContainer, substring, Location.Null);
2703 else if (resolved is Namespace)
2704 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
2705 else if (type != null)
2706 type = TypeManager.GetNestedType (type, substring);
2710 if (resolved == null)
2712 else if (type == null && resolved is TypeExpr)
2713 type = resolved.Type;
2720 if (name[0] != '[') {
2721 string substring = name.Substring(dot, index - dot);
2724 return TypeManager.GetNestedType (type, substring);
2726 if (resolved != null) {
2727 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
2728 if (resolved is TypeExpr)
2729 return resolved.Type;
2731 if (resolved == null)
2734 resolved.Error_UnexpectedKind (ec.DeclContainer, "type", loc);
2735 return typeof (UnexpectedType);
2741 return recursive_type;
2744 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2746 Type t = TypeLookup (ec, name);
2748 NamespaceEntry.Error_NamespaceNotFound (loc, name);
2751 if (t == typeof(UnexpectedType))
2757 public override string Name {
2758 get { return name; }
2761 public override string FullName {
2762 get { return name; }
2765 protected override void CloneTo (CloneContext clonectx, Expression target)
2767 // CloneTo: Nothing, we do not keep any state on this expression
2770 public override string GetSignatureForError ()
2773 return TypeManager.CSharpName (name);
2775 return base.GetSignatureForError ();
2780 /// Represents an "unbound generic type", ie. typeof (Foo<>).
2783 public class UnboundTypeExpression : TypeExpr
2787 public UnboundTypeExpression (MemberName name, Location l)
2793 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2796 if (name.Left != null) {
2797 Expression lexpr = name.Left.GetTypeExpression ();
2798 expr = new MemberAccess (lexpr, name.Basename);
2800 expr = new SimpleName (name.Basename, loc);
2803 FullNamedExpression fne = expr.ResolveAsTypeStep (ec, false);
2808 return new TypeExpression (type, loc);
2811 public override string Name {
2812 get { return name.FullName; }
2815 public override string FullName {
2816 get { return name.FullName; }
2820 public class TypeAliasExpression : TypeExpr {
2821 FullNamedExpression alias;
2826 public TypeAliasExpression (FullNamedExpression alias, TypeArguments args, Location l)
2832 eclass = ExprClass.Type;
2834 name = alias.FullName + "<" + args.ToString () + ">";
2836 name = alias.FullName;
2839 public override string Name {
2840 get { return alias.FullName; }
2843 public override string FullName {
2844 get { return name; }
2847 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2849 texpr = alias.ResolveAsTypeTerminal (ec, false);
2853 Type type = texpr.Type;
2854 int num_args = TypeManager.GetNumberOfTypeArguments (type);
2857 if (num_args == 0) {
2858 Report.Error (308, loc,
2859 "The non-generic type `{0}' cannot " +
2860 "be used with type arguments.",
2861 TypeManager.CSharpName (type));
2865 ConstructedType ctype = new ConstructedType (type, args, loc);
2866 return ctype.ResolveAsTypeTerminal (ec, false);
2867 } else if (num_args > 0) {
2868 Report.Error (305, loc,
2869 "Using the generic type `{0}' " +
2870 "requires {1} type arguments",
2871 TypeManager.CSharpName (type), num_args.ToString ());
2878 public override bool CheckAccessLevel (DeclSpace ds)
2880 return texpr.CheckAccessLevel (ds);
2883 public override bool AsAccessible (DeclSpace ds, int flags)
2885 return texpr.AsAccessible (ds, flags);
2888 public override bool IsClass {
2889 get { return texpr.IsClass; }
2892 public override bool IsValueType {
2893 get { return texpr.IsValueType; }
2896 public override bool IsInterface {
2897 get { return texpr.IsInterface; }
2900 public override bool IsSealed {
2901 get { return texpr.IsSealed; }
2906 /// This class denotes an expression which evaluates to a member
2907 /// of a struct or a class.
2909 public abstract class MemberExpr : Expression
2912 /// The name of this member.
2914 public abstract string Name {
2919 /// Whether this is an instance member.
2921 public abstract bool IsInstance {
2926 /// Whether this is a static member.
2928 public abstract bool IsStatic {
2933 /// The type which declares this member.
2935 public abstract Type DeclaringType {
2940 /// The instance expression associated with this member, if it's a
2941 /// non-static member.
2943 public Expression InstanceExpression;
2945 public static void error176 (Location loc, string name)
2947 Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
2948 "with an instance reference, qualify it with a type name instead", name);
2951 // TODO: possible optimalization
2952 // Cache resolved constant result in FieldBuilder <-> expression map
2953 public virtual Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
2954 SimpleName original)
2958 // original == null || original.Resolve (...) ==> left
2961 if (left is TypeExpr) {
2962 left = left.ResolveAsTypeTerminal (ec, true);
2967 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
2975 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
2978 error176 (loc, GetSignatureForError ());
2982 InstanceExpression = left;
2987 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
2992 if (InstanceExpression == EmptyExpression.Null) {
2993 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
2997 if (InstanceExpression.Type.IsValueType) {
2998 if (InstanceExpression is IMemoryLocation) {
2999 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
3001 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
3002 InstanceExpression.Emit (ec);
3004 t.AddressOf (ec, AddressOp.Store);
3007 InstanceExpression.Emit (ec);
3009 if (prepare_for_load)
3010 ec.ig.Emit (OpCodes.Dup);
3015 /// Represents group of extension methods
3017 public class ExtensionMethodGroupExpr : MethodGroupExpr
3019 readonly NamespaceEntry namespace_entry;
3020 public Expression ExtensionExpression;
3021 Argument extension_argument;
3023 public ExtensionMethodGroupExpr (ArrayList list, NamespaceEntry n, Type extensionType, Location l)
3024 : base (list, extensionType, l)
3026 this.namespace_entry = n;
3029 public override bool IsBase {
3030 get { return true; }
3033 public override bool IsStatic {
3034 get { return true; }
3037 public bool IsTopLevel {
3038 get { return namespace_entry == null; }
3041 public override void EmitArguments (EmitContext ec, ArrayList arguments)
3043 if (arguments == null)
3044 arguments = new ArrayList (1);
3045 arguments.Insert (0, extension_argument);
3046 base.EmitArguments (ec, arguments);
3049 public override void EmitCall (EmitContext ec, ArrayList arguments)
3051 if (arguments == null)
3052 arguments = new ArrayList (1);
3053 arguments.Insert (0, extension_argument);
3054 base.EmitCall (ec, arguments);
3057 public override MethodGroupExpr OverloadResolve (EmitContext ec, ArrayList arguments, bool may_fail, Location loc)
3059 if ((ExtensionExpression.eclass & (ExprClass.Value | ExprClass.Variable)) == 0)
3060 return base.OverloadResolve (ec, arguments, may_fail, loc);
3062 if (arguments == null)
3063 arguments = new ArrayList (1);
3065 arguments.Insert (0, new Argument (ExtensionExpression));
3066 MethodGroupExpr mg = ResolveOverloadExtensions (ec, arguments, namespace_entry, loc);
3068 // Store resolved argument and restore original arguments
3070 ((ExtensionMethodGroupExpr)mg).extension_argument = (Argument)arguments [0];
3071 arguments.RemoveAt (0);
3076 MethodGroupExpr ResolveOverloadExtensions (EmitContext ec, ArrayList arguments, NamespaceEntry ns, Location loc)
3078 // Use normal resolve rules
3079 MethodGroupExpr mg = base.OverloadResolve (ec, arguments, ns != null, loc);
3087 ExtensionMethodGroupExpr e = ns.LookupExtensionMethod (type, null, Name);
3089 return base.OverloadResolve (ec, arguments, false, loc);
3091 e.ExtensionExpression = ExtensionExpression;
3092 return e.ResolveOverloadExtensions (ec, arguments, e.namespace_entry, loc);
3097 /// MethodGroupExpr represents a group of method candidates which
3098 /// can be resolved to the best method overload
3100 public class MethodGroupExpr : MemberExpr
3102 public interface IErrorHandler
3104 bool NoExactMatch (EmitContext ec, MethodBase method);
3107 public IErrorHandler CustomErrorHandler;
3108 public MethodBase [] Methods;
3109 MethodBase best_candidate;
3110 bool has_type_arguments;
3111 bool identical_type_name;
3115 public MethodGroupExpr (MemberInfo [] mi, Type type, Location l)
3118 Methods = new MethodBase [mi.Length];
3119 mi.CopyTo (Methods, 0);
3122 public MethodGroupExpr (ArrayList list, Type type, Location l)
3126 Methods = (MethodBase[])list.ToArray (typeof (MethodBase));
3128 foreach (MemberInfo m in list){
3129 if (!(m is MethodBase)){
3130 Console.WriteLine ("Name " + m.Name);
3131 Console.WriteLine ("Found a: " + m.GetType ().FullName);
3140 protected MethodGroupExpr (Type type, Location loc)
3143 eclass = ExprClass.MethodGroup;
3147 public override Type DeclaringType {
3150 // We assume that the top-level type is in the end
3152 return Methods [Methods.Length - 1].DeclaringType;
3153 //return Methods [0].DeclaringType;
3157 public Type DelegateType {
3159 delegate_type = value;
3163 public bool HasTypeArguments {
3165 return has_type_arguments;
3169 public bool IdenticalTypeName {
3171 return identical_type_name;
3175 identical_type_name = value;
3179 public virtual bool IsBase {
3188 public override string GetSignatureForError ()
3190 if (best_candidate != null)
3191 return TypeManager.CSharpSignature (best_candidate);
3193 return TypeManager.CSharpSignature (Methods [0]);
3196 public override string Name {
3198 return Methods [0].Name;
3202 public override bool IsInstance {
3204 foreach (MethodBase mb in Methods)
3212 public override bool IsStatic {
3214 foreach (MethodBase mb in Methods)
3222 public static explicit operator ConstructorInfo (MethodGroupExpr mg)
3224 return (ConstructorInfo)mg.best_candidate;
3227 public static explicit operator MethodInfo (MethodGroupExpr mg)
3229 return (MethodInfo)mg.best_candidate;
3233 /// Determines "better conversion" as specified in 14.4.2.3
3235 /// Returns : p if a->p is better,
3236 /// q if a->q is better,
3237 /// null if neither is better
3239 static Type BetterConversion (EmitContext ec, Argument a, Type p, Type q)
3241 Type argument_type = TypeManager.TypeToCoreType (a.Type);
3242 Expression argument_expr = a.Expr;
3244 if (argument_type == null)
3245 throw new Exception ("Expression of type " + a.Expr +
3246 " does not resolve its type");
3248 if (p == null || q == null)
3249 throw new InternalErrorException ("BetterConversion Got a null conversion");
3254 if (argument_expr is NullLiteral)
3257 // If the argument is null and one of the types to compare is 'object' and
3258 // the other is a reference type, we prefer the other.
3260 // This follows from the usual rules:
3261 // * There is an implicit conversion from 'null' to type 'object'
3262 // * There is an implicit conversion from 'null' to any reference type
3263 // * There is an implicit conversion from any reference type to type 'object'
3264 // * There is no implicit conversion from type 'object' to other reference types
3265 // => Conversion of 'null' to a reference type is better than conversion to 'object'
3267 // FIXME: This probably isn't necessary, since the type of a NullLiteral is the
3268 // null type. I think it used to be 'object' and thus needed a special
3269 // case to avoid the immediately following two checks.
3271 if (!p.IsValueType && q == TypeManager.object_type)
3273 if (!q.IsValueType && p == TypeManager.object_type)
3277 if (argument_type == p)
3280 if (argument_type == q)
3283 Expression p_tmp = new EmptyExpression (p);
3284 Expression q_tmp = new EmptyExpression (q);
3286 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3287 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3289 if (p_to_q && !q_to_p)
3292 if (q_to_p && !p_to_q)
3295 if (p == TypeManager.sbyte_type)
3296 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3297 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3299 if (q == TypeManager.sbyte_type)
3300 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3301 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3304 if (p == TypeManager.short_type)
3305 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3306 q == TypeManager.uint64_type)
3308 if (q == TypeManager.short_type)
3309 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3310 p == TypeManager.uint64_type)
3313 if (p == TypeManager.int32_type)
3314 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3316 if (q == TypeManager.int32_type)
3317 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3320 if (p == TypeManager.int64_type)
3321 if (q == TypeManager.uint64_type)
3323 if (q == TypeManager.int64_type)
3324 if (p == TypeManager.uint64_type)
3331 /// Determines "Better function" between candidate
3332 /// and the current best match
3335 /// Returns a boolean indicating :
3336 /// false if candidate ain't better
3337 /// true if candidate is better than the current best match
3339 static bool BetterFunction (EmitContext ec, ArrayList args, int argument_count,
3340 MethodBase candidate, bool candidate_params,
3341 MethodBase best, bool best_params)
3343 ParameterData candidate_pd = TypeManager.GetParameterData (candidate);
3344 ParameterData best_pd = TypeManager.GetParameterData (best);
3346 bool better_at_least_one = false;
3348 for (int j = 0, c_idx = 0, b_idx = 0; j < argument_count; ++j, ++c_idx, ++b_idx)
3350 Argument a = (Argument) args [j];
3352 Type ct = TypeManager.TypeToCoreType (candidate_pd.ParameterType (c_idx));
3353 Type bt = TypeManager.TypeToCoreType (best_pd.ParameterType (b_idx));
3355 if (candidate_params && candidate_pd.ParameterModifier (c_idx) == Parameter.Modifier.PARAMS)
3357 ct = TypeManager.GetElementType (ct);
3361 if (best_params && best_pd.ParameterModifier (b_idx) == Parameter.Modifier.PARAMS)
3363 bt = TypeManager.GetElementType (bt);
3371 Type better = BetterConversion (ec, a, ct, bt);
3373 // for each argument, the conversion to 'ct' should be no worse than
3374 // the conversion to 'bt'.
3378 // for at least one argument, the conversion to 'ct' should be better than
3379 // the conversion to 'bt'.
3381 better_at_least_one = true;
3384 if (better_at_least_one)
3388 // This handles the case
3390 // Add (float f1, float f2, float f3);
3391 // Add (params decimal [] foo);
3393 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3394 // first candidate would've chosen as better.
3400 // The two methods have equal parameter types. Now apply tie-breaking rules
3402 if (TypeManager.IsGenericMethod (best) && !TypeManager.IsGenericMethod (candidate))
3404 if (!TypeManager.IsGenericMethod (best) && TypeManager.IsGenericMethod (candidate))
3408 // This handles the following cases:
3410 // Trim () is better than Trim (params char[] chars)
3411 // Concat (string s1, string s2, string s3) is better than
3412 // Concat (string s1, params string [] srest)
3413 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3415 if (!candidate_params && best_params)
3417 if (candidate_params && !best_params)
3420 int candidate_param_count = candidate_pd.Count;
3421 int best_param_count = best_pd.Count;
3423 if (candidate_param_count != best_param_count)
3424 // can only happen if (candidate_params && best_params)
3425 return candidate_param_count > best_param_count;
3428 // now, both methods have the same number of parameters, and the parameters have the same types
3429 // Pick the "more specific" signature
3432 MethodBase orig_candidate = TypeManager.DropGenericMethodArguments (candidate);
3433 MethodBase orig_best = TypeManager.DropGenericMethodArguments (best);
3435 ParameterData orig_candidate_pd = TypeManager.GetParameterData (orig_candidate);
3436 ParameterData orig_best_pd = TypeManager.GetParameterData (orig_best);
3438 bool specific_at_least_once = false;
3439 for (int j = 0; j < candidate_param_count; ++j)
3441 Type ct = TypeManager.TypeToCoreType (orig_candidate_pd.ParameterType (j));
3442 Type bt = TypeManager.TypeToCoreType (orig_best_pd.ParameterType (j));
3445 Type specific = MoreSpecific (ct, bt);
3449 specific_at_least_once = true;
3452 if (specific_at_least_once)
3455 // FIXME: handle lifted operators
3461 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3462 SimpleName original)
3464 if (!(left is TypeExpr) &&
3465 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3466 IdenticalTypeName = true;
3468 return base.ResolveMemberAccess (ec, left, loc, original);
3471 override public Expression DoResolve (EmitContext ec)
3473 if (InstanceExpression != null) {
3474 InstanceExpression = InstanceExpression.DoResolve (ec);
3475 if (InstanceExpression == null)
3482 public void ReportUsageError ()
3484 Report.Error (654, loc, "Method `" + DeclaringType + "." +
3485 Name + "()' is referenced without parentheses");
3488 override public void Emit (EmitContext ec)
3490 ReportUsageError ();
3493 public virtual void EmitArguments (EmitContext ec, ArrayList arguments)
3495 Invocation.EmitArguments (ec, best_candidate, arguments, false, null);
3498 public virtual void EmitCall (EmitContext ec, ArrayList arguments)
3500 Invocation.EmitCall (ec, IsBase, InstanceExpression, best_candidate, arguments, loc);
3503 protected virtual void Error_InvalidArguments (EmitContext ec, Location loc, int idx, MethodBase method,
3504 Argument a, ParameterData expected_par)
3506 if (a is CollectionElementInitializer.ElementInitializerArgument) {
3507 Report.SymbolRelatedToPreviousError (method);
3508 if ((expected_par.ParameterModifier (idx) & Parameter.Modifier.ISBYREF) != 0) {
3509 Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
3510 TypeManager.CSharpSignature (method));
3513 Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
3514 TypeManager.CSharpSignature (method));
3515 } else if (delegate_type == null) {
3516 Report.SymbolRelatedToPreviousError (method);
3517 Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
3518 TypeManager.CSharpSignature (method));
3520 Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
3521 TypeManager.CSharpName (delegate_type));
3523 Parameter.Modifier mod = expected_par.ParameterModifier (idx);
3525 string index = (idx + 1).ToString ();
3526 if ((mod & Parameter.Modifier.ISBYREF) != (a.Modifier & Parameter.Modifier.ISBYREF) ||
3527 (mod & Parameter.Modifier.ISBYREF) != 0) {
3528 if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) == 0)
3529 Report.Error (1615, loc, "Argument `{0}' should not be passed with the `{1}' keyword",
3530 index, Parameter.GetModifierSignature (a.Modifier));
3532 Report.Error (1620, loc, "Argument `{0}' must be passed with the `{1}' keyword",
3533 index, Parameter.GetModifierSignature (mod));
3535 string p1 = Argument.FullDesc (a);
3536 string p2 = TypeManager.CSharpName (expected_par.ParameterType (idx));
3539 Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
3540 Report.SymbolRelatedToPreviousError (a.Expr.Type);
3541 Report.SymbolRelatedToPreviousError (expected_par.ParameterType (idx));
3543 Report.Error (1503, loc, "Argument {0}: Cannot convert type `{1}' to `{2}'", index, p1, p2);
3547 protected virtual int GetApplicableParametersCount (MethodBase method, ParameterData parameters)
3549 return parameters.Count;
3552 public static bool IsAncestralType (Type first_type, Type second_type)
3554 return first_type != second_type &&
3555 (TypeManager.IsSubclassOf (second_type, first_type) ||
3556 TypeManager.ImplementsInterface (second_type, first_type));
3560 /// Determines if the candidate method is applicable (section 14.4.2.1)
3561 /// to the given set of arguments
3562 /// A return value rates candidate method compatibility,
3563 /// 0 = the best, int.MaxValue = the worst
3565 public int IsApplicable (EmitContext ec,
3566 ArrayList arguments, int arg_count, ref MethodBase method)
3568 MethodBase candidate = method;
3570 ParameterData pd = TypeManager.GetParameterData (candidate);
3571 int param_count = GetApplicableParametersCount (candidate, pd);
3573 if (arg_count != param_count)
3574 return int.MaxValue - arg_count - param_count;
3577 // 1. Infer type arguments for generic method
3580 if (!HasTypeArguments && TypeManager.IsGenericMethod (method)) {
3581 int score = TypeManager.InferTypeArguments (ec, arguments, ref candidate);
3583 return score - 1024;
3585 if (TypeManager.IsGenericMethodDefinition (candidate))
3586 throw new InternalErrorException ("a generic method definition took part in overload resolution");
3588 pd = TypeManager.GetParameterData (candidate);
3593 // 2. Each argument has to be implicitly convertible to method parameter
3595 for (int i = arg_count; i > 0; ) {
3598 Argument a = (Argument) arguments [i];
3600 Parameter.Modifier a_mod = a.Modifier &
3601 ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3603 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
3604 ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK | Parameter.Modifier.PARAMS);
3606 Type pt = pd.ParameterType (i);
3608 // FIXME: Kill this abomination (EmitContext.TempEc)
3609 EmitContext prevec = EmitContext.TempEc;
3610 EmitContext.TempEc = ec;
3613 pt = pt.GetElementType ();
3615 if (delegate_type != null ?
3616 !Delegate.IsTypeCovariant (a.Expr, pt) :
3617 !Convert.ImplicitConversionExists (ec, a.Expr, pt))
3624 EmitContext.TempEc = prevec;
3632 public static bool IsOverride (MethodBase cand_method, MethodBase base_method)
3634 if (!IsAncestralType (base_method.DeclaringType, cand_method.DeclaringType))
3637 ParameterData cand_pd = TypeManager.GetParameterData (cand_method);
3638 ParameterData base_pd = TypeManager.GetParameterData (base_method);
3640 if (cand_pd.Count != base_pd.Count)
3643 for (int j = 0; j < cand_pd.Count; ++j)
3645 Parameter.Modifier cm = cand_pd.ParameterModifier (j);
3646 Parameter.Modifier bm = base_pd.ParameterModifier (j);
3647 Type ct = TypeManager.TypeToCoreType (cand_pd.ParameterType (j));
3648 Type bt = TypeManager.TypeToCoreType (base_pd.ParameterType (j));
3650 if (cm != bm || ct != bt)
3657 public bool IsParamsMethodApplicable (EmitContext ec,
3658 ArrayList arguments, int arg_count,
3659 ref MethodBase candidate)
3661 return IsParamsMethodApplicable (
3662 ec, arguments, arg_count, false, ref candidate) ||
3663 IsParamsMethodApplicable (
3664 ec, arguments, arg_count, true, ref candidate);
3669 bool IsParamsMethodApplicable (EmitContext ec,
3670 ArrayList arguments, int arg_count,
3671 bool do_varargs, ref MethodBase candidate)
3674 if (!HasTypeArguments &&
3675 !TypeManager.InferParamsTypeArguments (ec, arguments, ref candidate))
3678 if (TypeManager.IsGenericMethodDefinition (candidate))
3679 throw new InternalErrorException ("a generic method definition took part in overload resolution");
3682 return IsParamsMethodApplicable (
3683 ec, arguments, arg_count, candidate, do_varargs);
3687 /// Determines if the candidate method, if a params method, is applicable
3688 /// in its expanded form to the given set of arguments
3690 bool IsParamsMethodApplicable (EmitContext ec, ArrayList arguments,
3691 int arg_count, MethodBase candidate,
3694 ParameterData pd = TypeManager.GetParameterData (candidate);
3695 int pd_count = GetApplicableParametersCount (candidate, pd);
3699 int count = pd_count - 1;
3701 if (pd.ParameterModifier (count) != Parameter.Modifier.ARGLIST)
3703 if (pd_count != arg_count)
3706 if (!(((Argument) arguments [count]).Expr is Arglist))
3714 if (count > arg_count)
3717 if (pd_count == 1 && arg_count == 0)
3721 // If we have come this far, the case which
3722 // remains is when the number of parameters is
3723 // less than or equal to the argument count.
3725 int argument_index = 0;
3727 for (int i = 0; i < pd_count; ++i) {
3729 if ((pd.ParameterModifier (i) & Parameter.Modifier.PARAMS) != 0) {
3730 Type element_type = TypeManager.GetElementType (pd.ParameterType (i));
3731 int params_args_count = arg_count - pd_count;
3732 if (params_args_count < 0)
3736 a = (Argument) arguments [argument_index++];
3738 if (!Convert.ImplicitConversionExists (ec, a.Expr, element_type))
3740 } while (params_args_count-- > 0);
3744 a = (Argument) arguments [argument_index++];
3746 Parameter.Modifier a_mod = a.Modifier &
3747 (unchecked (~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK)));
3748 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
3749 (unchecked (~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK)));
3751 if (a_mod == p_mod) {
3753 if (a_mod == Parameter.Modifier.NONE)
3754 if (!Convert.ImplicitConversionExists (ec,
3756 pd.ParameterType (i)))
3759 if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {
3760 Type pt = pd.ParameterType (i);
3763 pt = TypeManager.GetReferenceType (pt);
3776 public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2, Location loc)
3778 MemberInfo [] miset;
3779 MethodGroupExpr union;
3784 return (MethodGroupExpr) mg2;
3787 return (MethodGroupExpr) mg1;
3790 MethodGroupExpr left_set = null, right_set = null;
3791 int length1 = 0, length2 = 0;
3793 left_set = (MethodGroupExpr) mg1;
3794 length1 = left_set.Methods.Length;
3796 right_set = (MethodGroupExpr) mg2;
3797 length2 = right_set.Methods.Length;
3799 ArrayList common = new ArrayList ();
3801 foreach (MethodBase r in right_set.Methods){
3802 if (TypeManager.ArrayContainsMethod (left_set.Methods, r))
3806 miset = new MemberInfo [length1 + length2 - common.Count];
3807 left_set.Methods.CopyTo (miset, 0);
3811 foreach (MethodBase r in right_set.Methods) {
3812 if (!common.Contains (r))
3816 union = new MethodGroupExpr (miset, mg1.Type, loc);
3821 static Type MoreSpecific (Type p, Type q)
3823 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
3825 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
3828 if (TypeManager.HasElementType (p))
3830 Type pe = TypeManager.GetElementType (p);
3831 Type qe = TypeManager.GetElementType (q);
3832 Type specific = MoreSpecific (pe, qe);
3838 else if (TypeManager.IsGenericType (p))
3840 Type[] pargs = TypeManager.GetTypeArguments (p);
3841 Type[] qargs = TypeManager.GetTypeArguments (q);
3843 bool p_specific_at_least_once = false;
3844 bool q_specific_at_least_once = false;
3846 for (int i = 0; i < pargs.Length; i++)
3848 Type specific = MoreSpecific (pargs [i], qargs [i]);
3849 if (specific == pargs [i])
3850 p_specific_at_least_once = true;
3851 if (specific == qargs [i])
3852 q_specific_at_least_once = true;
3855 if (p_specific_at_least_once && !q_specific_at_least_once)
3857 if (!p_specific_at_least_once && q_specific_at_least_once)
3865 /// Find the Applicable Function Members (7.4.2.1)
3867 /// me: Method Group expression with the members to select.
3868 /// it might contain constructors or methods (or anything
3869 /// that maps to a method).
3871 /// Arguments: ArrayList containing resolved Argument objects.
3873 /// loc: The location if we want an error to be reported, or a Null
3874 /// location for "probing" purposes.
3876 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3877 /// that is the best match of me on Arguments.
3880 public virtual MethodGroupExpr OverloadResolve (EmitContext ec, ArrayList Arguments,
3881 bool may_fail, Location loc)
3883 bool method_params = false;
3884 Type applicable_type = null;
3886 ArrayList candidates = new ArrayList (2);
3887 ArrayList candidate_overrides = null;
3890 // Used to keep a map between the candidate
3891 // and whether it is being considered in its
3892 // normal or expanded form
3894 // false is normal form, true is expanded form
3896 Hashtable candidate_to_form = null;
3898 if (Arguments != null)
3899 arg_count = Arguments.Count;
3901 if (RootContext.Version == LanguageVersion.ISO_1 && Name == "Invoke" && TypeManager.IsDelegateType (DeclaringType)) {
3903 Report.Error (1533, loc, "Invoke cannot be called directly on a delegate");
3907 int nmethods = Methods.Length;
3911 // Methods marked 'override' don't take part in 'applicable_type'
3912 // computation, nor in the actual overload resolution.
3913 // However, they still need to be emitted instead of a base virtual method.
3914 // So, we salt them away into the 'candidate_overrides' array.
3916 // In case of reflected methods, we replace each overriding method with
3917 // its corresponding base virtual method. This is to improve compatibility
3918 // with non-C# libraries which change the visibility of overrides (#75636)
3921 for (int i = 0; i < Methods.Length; ++i) {
3922 MethodBase m = Methods [i];
3924 Type [] gen_args = null;
3925 if (m.IsGenericMethod && !m.IsGenericMethodDefinition)
3926 gen_args = m.GetGenericArguments ();
3928 if (TypeManager.IsOverride (m)) {
3929 if (candidate_overrides == null)
3930 candidate_overrides = new ArrayList ();
3931 candidate_overrides.Add (m);
3932 m = TypeManager.TryGetBaseDefinition (m);
3934 if (m != null && gen_args != null) {
3935 if (!m.IsGenericMethodDefinition)
3936 throw new InternalErrorException ("GetBaseDefinition didn't return a GenericMethodDefinition");
3937 m = ((MethodInfo) m).MakeGenericMethod (gen_args);
3948 // Enable message recording, it's used mainly by lambda expressions
3950 Report.IMessageRecorder msg_recorder = new Report.MessageRecorder ();
3951 Report.IMessageRecorder prev_recorder = Report.SetMessageRecorder (msg_recorder);
3954 // First we construct the set of applicable methods
3956 bool is_sorted = true;
3957 int best_candidate_rate = int.MaxValue;
3958 for (int i = 0; i < nmethods; i++) {
3959 Type decl_type = Methods [i].DeclaringType;
3962 // If we have already found an applicable method
3963 // we eliminate all base types (Section 14.5.5.1)
3965 if (applicable_type != null && IsAncestralType (decl_type, applicable_type))
3969 // Check if candidate is applicable (section 14.4.2.1)
3970 // Is candidate applicable in normal form?
3972 int candidate_rate = IsApplicable (ec, Arguments, arg_count, ref Methods [i]);
3974 if (candidate_rate != 0 && IsParamsMethodApplicable (ec, Arguments, arg_count, ref Methods [i])) {
3975 MethodBase candidate = Methods [i];
3976 if (candidate_to_form == null)
3977 candidate_to_form = new PtrHashtable ();
3978 candidate_to_form [candidate] = candidate;
3979 // Candidate is applicable in expanded form
3983 if (candidate_rate < best_candidate_rate) {
3984 best_candidate_rate = candidate_rate;
3985 best_candidate = Methods [i];
3988 if (candidate_rate != 0) {
3989 if (msg_recorder != null)
3990 msg_recorder.EndSession ();
3994 msg_recorder = null;
3996 candidates.Add (Methods [i]);
3998 if (applicable_type == null)
3999 applicable_type = decl_type;
4000 else if (applicable_type != decl_type) {
4002 if (IsAncestralType (applicable_type, decl_type))
4003 applicable_type = decl_type;
4007 Report.SetMessageRecorder (prev_recorder);
4008 if (msg_recorder != null && msg_recorder.PrintMessages ())
4011 int candidate_top = candidates.Count;
4013 if (applicable_type == null) {
4015 // When we found a top level method which does not match and it's
4016 // not an extension method. We start extension methods lookup from here
4018 if (InstanceExpression != null) {
4019 ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (type, Name);
4020 if (ex_method_lookup != null) {
4021 ex_method_lookup.ExtensionExpression = InstanceExpression;
4022 return ex_method_lookup.OverloadResolve (ec, Arguments, may_fail, loc);
4026 if (ec.IsInProbingMode || may_fail)
4030 // Okay so we have failed to find exact match so we
4031 // return error info about the closest match
4033 if (best_candidate != null) {
4034 if (CustomErrorHandler != null) {
4035 if (CustomErrorHandler.NoExactMatch (ec, best_candidate))
4039 if (TypeManager.IsGenericMethod (best_candidate)) {
4040 Report.Error (411, loc,
4041 "The type arguments for method `{0}' cannot be inferred from " +
4042 "the usage. Try specifying the type arguments explicitly",
4043 TypeManager.CSharpSignature (best_candidate));
4047 ParameterData pd = TypeManager.GetParameterData (best_candidate);
4048 if (arg_count == pd.Count) {
4049 VerifyArgumentsCompat (ec, Arguments, arg_count, best_candidate, false, may_fail, loc);
4054 if (almost_matched_members.Count != 0) {
4055 Error_MemberLookupFailed (ec.ContainerType, type, type, ".ctor",
4056 null, MemberTypes.Constructor, AllBindingFlags);
4061 // We failed to find any method with correct argument count
4063 if (Name == ConstructorInfo.ConstructorName) {
4064 Report.SymbolRelatedToPreviousError (type);
4065 Report.Error (1729, loc,
4066 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4067 TypeManager.CSharpName (type), arg_count);
4069 Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4070 Name, arg_count.ToString ());
4078 // At this point, applicable_type is _one_ of the most derived types
4079 // in the set of types containing the methods in this MethodGroup.
4080 // Filter the candidates so that they only contain methods from the
4081 // most derived types.
4084 int finalized = 0; // Number of finalized candidates
4087 // Invariant: applicable_type is a most derived type
4089 // We'll try to complete Section 14.5.5.1 for 'applicable_type' by
4090 // eliminating all it's base types. At the same time, we'll also move
4091 // every unrelated type to the end of the array, and pick the next
4092 // 'applicable_type'.
4094 Type next_applicable_type = null;
4095 int j = finalized; // where to put the next finalized candidate
4096 int k = finalized; // where to put the next undiscarded candidate
4097 for (int i = finalized; i < candidate_top; ++i) {
4098 MethodBase candidate = (MethodBase) candidates [i];
4099 Type decl_type = candidate.DeclaringType;
4101 if (decl_type == applicable_type) {
4102 candidates [k++] = candidates [j];
4103 candidates [j++] = candidates [i];
4107 if (IsAncestralType (decl_type, applicable_type))
4110 if (next_applicable_type != null &&
4111 IsAncestralType (decl_type, next_applicable_type))
4114 candidates [k++] = candidates [i];
4116 if (next_applicable_type == null ||
4117 IsAncestralType (next_applicable_type, decl_type))
4118 next_applicable_type = decl_type;
4121 applicable_type = next_applicable_type;
4124 } while (applicable_type != null);
4128 // Now we actually find the best method
4131 best_candidate = (MethodBase) candidates [0];
4132 method_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4133 for (int ix = 1; ix < candidate_top; ix++) {
4134 MethodBase candidate = (MethodBase) candidates [ix];
4136 if (candidate == best_candidate)
4139 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4141 if (BetterFunction (ec, Arguments, arg_count,
4142 candidate, cand_params,
4143 best_candidate, method_params)) {
4144 best_candidate = candidate;
4145 method_params = cand_params;
4149 // Now check that there are no ambiguities i.e the selected method
4150 // should be better than all the others
4152 MethodBase ambiguous = null;
4153 for (int ix = 0; ix < candidate_top; ix++) {
4154 MethodBase candidate = (MethodBase) candidates [ix];
4156 if (candidate == best_candidate)
4159 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4160 if (!BetterFunction (ec, Arguments, arg_count,
4161 best_candidate, method_params,
4162 candidate, cand_params))
4165 Report.SymbolRelatedToPreviousError (candidate);
4166 ambiguous = candidate;
4170 if (ambiguous != null) {
4171 Report.SymbolRelatedToPreviousError (best_candidate);
4172 Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4173 TypeManager.CSharpSignature (ambiguous), TypeManager.CSharpSignature (best_candidate));
4178 // If the method is a virtual function, pick an override closer to the LHS type.
4180 if (!IsBase && best_candidate.IsVirtual) {
4181 if (TypeManager.IsOverride (best_candidate))
4182 throw new InternalErrorException (
4183 "Should not happen. An 'override' method took part in overload resolution: " + best_candidate);
4185 if (candidate_overrides != null)
4186 foreach (MethodBase candidate in candidate_overrides) {
4187 if (IsOverride (candidate, best_candidate))
4188 best_candidate = candidate;
4192 // We can stop here when probing is on
4193 if (ec.IsInProbingMode)
4197 // And now check if the arguments are all
4198 // compatible, perform conversions if
4199 // necessary etc. and return if everything is
4202 if (!VerifyArgumentsCompat (ec, Arguments, arg_count, best_candidate,
4203 method_params, may_fail, loc))
4206 if (best_candidate == null)
4209 MethodBase the_method = TypeManager.DropGenericMethodArguments (best_candidate);
4211 if (the_method.IsGenericMethodDefinition &&
4212 !ConstraintChecker.CheckConstraints (ec, the_method, best_candidate, loc))
4216 IMethodData data = TypeManager.GetMethod (the_method);
4218 data.SetMemberIsUsed ();
4223 public Expression ResolveGeneric (EmitContext ec, TypeArguments args)
4226 if (!args.Resolve (ec))
4229 Type[] atypes = args.Arguments;
4231 int first_count = 0;
4232 MethodInfo first = null;
4234 ArrayList list = new ArrayList ();
4235 foreach (MethodBase mb in Methods) {
4236 MethodInfo mi = mb as MethodInfo;
4237 if ((mi == null) || !mb.IsGenericMethod)
4240 Type[] gen_params = mb.GetGenericArguments ();
4242 if (first == null) {
4244 first_count = gen_params.Length;
4247 if (gen_params.Length != atypes.Length)
4250 mi = mi.MakeGenericMethod (atypes);
4254 // MS implementation throws NotSupportedException for GetParameters
4255 // on unbaked generic method
4256 Parameters p = TypeManager.GetParameterData (mi) as Parameters;
4259 p.InflateTypes (gen_params, atypes);
4260 TypeManager.RegisterMethod (mi, p);
4265 if (list.Count > 0) {
4266 this.Methods = (MethodBase []) list.ToArray (typeof (MethodBase));
4267 has_type_arguments = true;
4271 if (first != null) {
4272 Report.SymbolRelatedToPreviousError (first);
4274 305, loc, "Using the generic method `{0}' requires `{1}' type arguments",
4275 TypeManager.CSharpSignature (first), first_count.ToString ());
4278 308, loc, "The non-generic method `{0}' " +
4279 "cannot be used with type arguments", Name);
4283 throw new NotImplementedException ();
4287 public bool VerifyArgumentsCompat (EmitContext ec, ArrayList Arguments,
4288 int arg_count, MethodBase method,
4289 bool chose_params_expanded,
4290 bool may_fail, Location loc)
4292 ParameterData pd = TypeManager.GetParameterData (method);
4293 int param_count = GetApplicableParametersCount (method, pd);
4298 int errors = Report.Errors;
4299 for (j = 0; j < param_count; j++) {
4300 Type parameter_type = pd.ParameterType (j);
4301 Parameter.Modifier pm = pd.ParameterModifier (j);
4303 if (pm == Parameter.Modifier.ARGLIST) {
4304 a = (Argument) Arguments [a_idx];
4305 if (!(a.Expr is Arglist))
4311 int params_arg_count = 1;
4312 if (pm == Parameter.Modifier.PARAMS) {
4313 pm = Parameter.Modifier.NONE;
4314 params_arg_count = arg_count - param_count + 1;
4315 if (chose_params_expanded)
4316 parameter_type = TypeManager.GetElementType (parameter_type);
4319 while (params_arg_count > 0) {
4320 a = (Argument) Arguments [a_idx];
4321 if (pm != a.Modifier)
4324 if (!TypeManager.IsEqual (a.Type, parameter_type)) {
4325 if (pm == Parameter.Modifier.OUT || pm == Parameter.Modifier.REF)
4328 Expression conv = Convert.ImplicitConversion (ec, a.Expr, parameter_type, loc);
4332 // Update the argument with the implicit conversion
4340 if (params_arg_count > 0)
4343 if (parameter_type.IsPointer && !ec.InUnsafe) {
4350 if (a_idx == arg_count)
4353 if (!may_fail && Report.Errors == errors)
4354 Error_InvalidArguments (ec, loc, a_idx, method, a, pd);
4360 /// Fully resolved expression that evaluates to a Field
4362 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariable {
4363 public readonly FieldInfo FieldInfo;
4364 VariableInfo variable_info;
4366 LocalTemporary temp;
4368 bool in_initializer;
4370 public FieldExpr (FieldInfo fi, Location l, bool in_initializer):
4373 this.in_initializer = in_initializer;
4376 public FieldExpr (FieldInfo fi, Location l)
4379 eclass = ExprClass.Variable;
4380 type = TypeManager.TypeToCoreType (fi.FieldType);
4384 public override string Name {
4386 return FieldInfo.Name;
4390 public override bool IsInstance {
4392 return !FieldInfo.IsStatic;
4396 public override bool IsStatic {
4398 return FieldInfo.IsStatic;
4402 public override Type DeclaringType {
4404 return FieldInfo.DeclaringType;
4408 public override string GetSignatureForError ()
4410 return TypeManager.GetFullNameSignature (FieldInfo);
4413 public VariableInfo VariableInfo {
4415 return variable_info;
4419 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
4420 SimpleName original)
4422 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
4424 Type t = fi.FieldType;
4426 if (fi.IsLiteral || (fi.IsInitOnly && t == TypeManager.decimal_type)) {
4427 IConstant ic = TypeManager.GetConstant (fi);
4430 ic = new ExternalConstant (fi);
4432 ic = ExternalConstant.CreateDecimal (fi);
4434 return base.ResolveMemberAccess (ec, left, loc, original);
4437 TypeManager.RegisterConstant (fi, ic);
4440 bool left_is_type = left is TypeExpr;
4441 if (!left_is_type && (original == null || !original.IdenticalNameAndTypeName (ec, left, loc))) {
4442 Report.SymbolRelatedToPreviousError (FieldInfo);
4443 error176 (loc, TypeManager.GetFullNameSignature (FieldInfo));
4447 if (ic.ResolveValue ()) {
4448 if (!ec.IsInObsoleteScope)
4449 ic.CheckObsoleteness (loc);
4452 return ic.CreateConstantReference (loc);
4455 if (t.IsPointer && !ec.InUnsafe) {
4459 return base.ResolveMemberAccess (ec, left, loc, original);
4462 override public Expression DoResolve (EmitContext ec)
4464 return DoResolve (ec, false, false);
4467 Expression DoResolve (EmitContext ec, bool lvalue_instance, bool out_access)
4469 if (!FieldInfo.IsStatic){
4470 if (InstanceExpression == null){
4472 // This can happen when referencing an instance field using
4473 // a fully qualified type expression: TypeName.InstanceField = xxx
4475 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4479 // Resolve the field's instance expression while flow analysis is turned
4480 // off: when accessing a field "a.b", we must check whether the field
4481 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4483 if (lvalue_instance) {
4484 using (ec.With (EmitContext.Flags.DoFlowAnalysis, false)) {
4485 Expression right_side =
4486 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4487 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side, loc);
4490 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
4491 InstanceExpression = InstanceExpression.Resolve (ec, rf);
4494 if (InstanceExpression == null)
4497 InstanceExpression.CheckMarshalByRefAccess ();
4500 if (!in_initializer && !ec.IsInFieldInitializer) {
4501 ObsoleteAttribute oa;
4502 FieldBase f = TypeManager.GetField (FieldInfo);
4504 if (!ec.IsInObsoleteScope)
4505 f.CheckObsoleteness (loc);
4507 // To be sure that type is external because we do not register generated fields
4508 } else if (!(FieldInfo.DeclaringType is TypeBuilder)) {
4509 oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
4511 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
4515 AnonymousContainer am = ec.CurrentAnonymousMethod;
4517 if (!FieldInfo.IsStatic){
4518 if (!am.IsIterator && (ec.TypeContainer is Struct)){
4519 Report.Error (1673, loc,
4520 "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",
4527 IFixedBuffer fb = AttributeTester.GetFixedBuffer (FieldInfo);
4529 if (!ec.InFixedInitializer && ec.ContainerType.IsValueType) {
4530 Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4533 if (!(InstanceExpression is LocalVariableReference) &&
4534 !(InstanceExpression is This)) {
4535 Report.SymbolRelatedToPreviousError (FieldInfo);
4536 Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4537 TypeManager.GetFullNameSignature (FieldInfo));
4540 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4543 // If the instance expression is a local variable or parameter.
4544 IVariable var = InstanceExpression as IVariable;
4545 if ((var == null) || (var.VariableInfo == null))
4548 VariableInfo vi = var.VariableInfo;
4549 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
4552 variable_info = vi.GetSubStruct (FieldInfo.Name);
4556 static readonly int [] codes = {
4557 191, // instance, write access
4558 192, // instance, out access
4559 198, // static, write access
4560 199, // static, out access
4561 1648, // member of value instance, write access
4562 1649, // member of value instance, out access
4563 1650, // member of value static, write access
4564 1651 // member of value static, out access
4567 static readonly string [] msgs = {
4568 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4569 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4570 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4571 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4572 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4573 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4574 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4575 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4578 // The return value is always null. Returning a value simplifies calling code.
4579 Expression Report_AssignToReadonly (Expression right_side)
4582 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4586 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4588 Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4593 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4595 IVariable var = InstanceExpression as IVariable;
4596 if ((var != null) && (var.VariableInfo != null))
4597 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
4599 bool lvalue_instance = !FieldInfo.IsStatic && FieldInfo.DeclaringType.IsValueType;
4600 bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
4602 Expression e = DoResolve (ec, lvalue_instance, out_access);
4607 FieldBase fb = TypeManager.GetField (FieldInfo);
4611 if (FieldInfo.IsInitOnly) {
4612 // InitOnly fields can only be assigned in constructors or initializers
4613 if (!ec.IsInFieldInitializer && !ec.IsConstructor)
4614 return Report_AssignToReadonly (right_side);
4616 if (ec.IsConstructor) {
4617 Type ctype = ec.TypeContainer.CurrentType;
4619 ctype = ec.ContainerType;
4621 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4622 if (!TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
4623 return Report_AssignToReadonly (right_side);
4624 // static InitOnly fields cannot be assigned-to in an instance constructor
4625 if (IsStatic && !ec.IsStatic)
4626 return Report_AssignToReadonly (right_side);
4627 // instance constructors can't modify InitOnly fields of other instances of the same type
4628 if (!IsStatic && !(InstanceExpression is This))
4629 return Report_AssignToReadonly (right_side);
4633 if (right_side == EmptyExpression.OutAccess &&
4634 !IsStatic && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
4635 Report.SymbolRelatedToPreviousError (DeclaringType);
4636 Report.Warning (197, 1, loc,
4637 "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",
4638 GetSignatureForError ());
4644 public override void CheckMarshalByRefAccess ()
4646 if (!IsStatic && Type.IsValueType && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
4647 Report.SymbolRelatedToPreviousError (DeclaringType);
4648 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",
4649 GetSignatureForError ());
4653 public bool VerifyFixed ()
4655 IVariable variable = InstanceExpression as IVariable;
4656 // A variable of the form V.I is fixed when V is a fixed variable of a struct type.
4657 // We defer the InstanceExpression check after the variable check to avoid a
4658 // separate null check on InstanceExpression.
4659 return variable != null && InstanceExpression.Type.IsValueType && variable.VerifyFixed ();
4662 public override int GetHashCode ()
4664 return FieldInfo.GetHashCode ();
4667 public override bool Equals (object obj)
4669 FieldExpr fe = obj as FieldExpr;
4673 if (FieldInfo != fe.FieldInfo)
4676 if (InstanceExpression == null || fe.InstanceExpression == null)
4679 return InstanceExpression.Equals (fe.InstanceExpression);
4682 public void Emit (EmitContext ec, bool leave_copy)
4684 ILGenerator ig = ec.ig;
4685 bool is_volatile = false;
4687 FieldBase f = TypeManager.GetField (FieldInfo);
4689 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4692 f.SetMemberIsUsed ();
4695 if (FieldInfo.IsStatic){
4697 ig.Emit (OpCodes.Volatile);
4699 ig.Emit (OpCodes.Ldsfld, FieldInfo);
4702 EmitInstance (ec, false);
4704 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
4706 ig.Emit (OpCodes.Ldflda, FieldInfo);
4707 ig.Emit (OpCodes.Ldflda, ff.Element);
4710 ig.Emit (OpCodes.Volatile);
4712 ig.Emit (OpCodes.Ldfld, FieldInfo);
4717 ec.ig.Emit (OpCodes.Dup);
4718 if (!FieldInfo.IsStatic) {
4719 temp = new LocalTemporary (this.Type);
4725 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4727 FieldAttributes fa = FieldInfo.Attributes;
4728 bool is_static = (fa & FieldAttributes.Static) != 0;
4729 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
4730 ILGenerator ig = ec.ig;
4732 if (is_readonly && !ec.IsConstructor){
4733 Report_AssignToReadonly (source);
4738 // String concatenation creates a new string instance
4740 prepared = prepare_for_load && !(source is StringConcat);
4741 EmitInstance (ec, prepared);
4745 ec.ig.Emit (OpCodes.Dup);
4746 if (!FieldInfo.IsStatic) {
4747 temp = new LocalTemporary (this.Type);
4752 FieldBase f = TypeManager.GetField (FieldInfo);
4754 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4755 ig.Emit (OpCodes.Volatile);
4761 ig.Emit (OpCodes.Stsfld, FieldInfo);
4763 ig.Emit (OpCodes.Stfld, FieldInfo);
4771 public override void Emit (EmitContext ec)
4776 public void AddressOf (EmitContext ec, AddressOp mode)
4778 ILGenerator ig = ec.ig;
4780 FieldBase f = TypeManager.GetField (FieldInfo);
4782 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
4783 Report.Warning (420, 1, loc, "`{0}': A volatile field references will not be treated as volatile",
4784 f.GetSignatureForError ());
4787 if ((mode & AddressOp.Store) != 0)
4789 if ((mode & AddressOp.Load) != 0)
4790 f.SetMemberIsUsed ();
4794 // Handle initonly fields specially: make a copy and then
4795 // get the address of the copy.
4798 if (FieldInfo.IsInitOnly){
4800 if (ec.IsConstructor){
4801 if (FieldInfo.IsStatic){
4813 local = ig.DeclareLocal (type);
4814 ig.Emit (OpCodes.Stloc, local);
4815 ig.Emit (OpCodes.Ldloca, local);
4820 if (FieldInfo.IsStatic){
4821 ig.Emit (OpCodes.Ldsflda, FieldInfo);
4824 EmitInstance (ec, false);
4825 ig.Emit (OpCodes.Ldflda, FieldInfo);
4831 // A FieldExpr whose address can not be taken
4833 public class FieldExprNoAddress : FieldExpr, IMemoryLocation {
4834 public FieldExprNoAddress (FieldInfo fi, Location loc) : base (fi, loc)
4838 public new void AddressOf (EmitContext ec, AddressOp mode)
4840 Report.Error (-215, "Report this: Taking the address of a remapped parameter not supported");
4845 /// Expression that evaluates to a Property. The Assign class
4846 /// might set the `Value' expression if we are in an assignment.
4848 /// This is not an LValue because we need to re-write the expression, we
4849 /// can not take data from the stack and store it.
4851 public class PropertyExpr : MemberExpr, IAssignMethod {
4852 public readonly PropertyInfo PropertyInfo;
4855 // This is set externally by the `BaseAccess' class
4858 MethodInfo getter, setter;
4863 LocalTemporary temp;
4866 public PropertyExpr (Type container_type, PropertyInfo pi, Location l)
4869 eclass = ExprClass.PropertyAccess;
4873 type = TypeManager.TypeToCoreType (pi.PropertyType);
4875 ResolveAccessors (container_type);
4878 public override string Name {
4880 return PropertyInfo.Name;
4884 public override bool IsInstance {
4890 public override bool IsStatic {
4896 public override Type DeclaringType {
4898 return PropertyInfo.DeclaringType;
4902 public override string GetSignatureForError ()
4904 return TypeManager.GetFullNameSignature (PropertyInfo);
4907 void FindAccessors (Type invocation_type)
4909 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
4910 BindingFlags.Static | BindingFlags.Instance |
4911 BindingFlags.DeclaredOnly;
4913 Type current = PropertyInfo.DeclaringType;
4914 for (; current != null; current = current.BaseType) {
4915 MemberInfo[] group = TypeManager.MemberLookup (
4916 invocation_type, invocation_type, current,
4917 MemberTypes.Property, flags, PropertyInfo.Name, null);
4922 if (group.Length != 1)
4923 // Oooops, can this ever happen ?
4926 PropertyInfo pi = (PropertyInfo) group [0];
4929 getter = pi.GetGetMethod (true);
4932 setter = pi.GetSetMethod (true);
4934 MethodInfo accessor = getter != null ? getter : setter;
4936 if (!accessor.IsVirtual)
4942 // We also perform the permission checking here, as the PropertyInfo does not
4943 // hold the information for the accessibility of its setter/getter
4945 // TODO: Refactor to use some kind of cache together with GetPropertyFromAccessor
4946 void ResolveAccessors (Type container_type)
4948 FindAccessors (container_type);
4950 if (getter != null) {
4951 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
4952 IMethodData md = TypeManager.GetMethod (the_getter);
4954 md.SetMemberIsUsed ();
4956 is_static = getter.IsStatic;
4959 if (setter != null) {
4960 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
4961 IMethodData md = TypeManager.GetMethod (the_setter);
4963 md.SetMemberIsUsed ();
4965 is_static = setter.IsStatic;
4969 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
4972 InstanceExpression = null;
4976 if (InstanceExpression == null) {
4977 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4981 InstanceExpression = InstanceExpression.DoResolve (ec);
4982 if (lvalue_instance && InstanceExpression != null)
4983 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
4985 if (InstanceExpression == null)
4988 InstanceExpression.CheckMarshalByRefAccess ();
4990 if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) &&
4991 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
4992 !TypeManager.IsNestedChildOf (ec.ContainerType, InstanceExpression.Type) &&
4993 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.ContainerType)) {
4994 Report.SymbolRelatedToPreviousError (PropertyInfo);
4995 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
5002 void Error_PropertyNotFound (MethodInfo mi, bool getter)
5004 // TODO: correctly we should compare arguments but it will lead to bigger changes
5005 if (mi is MethodBuilder) {
5006 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
5010 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
5012 ParameterData iparams = TypeManager.GetParameterData (mi);
5013 sig.Append (getter ? "get_" : "set_");
5015 sig.Append (iparams.GetSignatureForError ());
5017 Report.SymbolRelatedToPreviousError (mi);
5018 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
5019 Name, sig.ToString ());
5022 public bool IsAccessibleFrom (Type invocation_type, bool lvalue)
5025 MethodInfo accessor = lvalue ? setter : getter;
5026 if (accessor == null && lvalue)
5028 return accessor != null && IsAccessorAccessible (invocation_type, accessor, out dummy);
5031 override public Expression DoResolve (EmitContext ec)
5036 if (getter != null){
5037 if (TypeManager.GetParameterData (getter).Count != 0){
5038 Error_PropertyNotFound (getter, true);
5043 if (getter == null){
5045 // The following condition happens if the PropertyExpr was
5046 // created, but is invalid (ie, the property is inaccessible),
5047 // and we did not want to embed the knowledge about this in
5048 // the caller routine. This only avoids double error reporting.
5053 if (InstanceExpression != EmptyExpression.Null) {
5054 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5055 TypeManager.GetFullNameSignature (PropertyInfo));
5060 bool must_do_cs1540_check = false;
5061 if (getter != null &&
5062 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
5063 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
5064 if (pm != null && pm.HasCustomAccessModifier) {
5065 Report.SymbolRelatedToPreviousError (pm);
5066 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5067 TypeManager.CSharpSignature (getter));
5070 Report.SymbolRelatedToPreviousError (getter);
5071 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
5076 if (!InstanceResolve (ec, false, must_do_cs1540_check))
5080 // Only base will allow this invocation to happen.
5082 if (IsBase && getter.IsAbstract) {
5083 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5087 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
5097 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
5099 if (right_side == EmptyExpression.OutAccess) {
5100 if (ec.CurrentBlock.Toplevel.GetTransparentIdentifier (PropertyInfo.Name) != null) {
5101 Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5104 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as `ref' or `out' parameter",
5105 GetSignatureForError ());
5110 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5111 Report.Error (1612, loc, "Cannot modify the return value of `{0}' because it is not a variable",
5112 GetSignatureForError ());
5116 if (setter == null){
5118 // The following condition happens if the PropertyExpr was
5119 // created, but is invalid (ie, the property is inaccessible),
5120 // and we did not want to embed the knowledge about this in
5121 // the caller routine. This only avoids double error reporting.
5125 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
5126 GetSignatureForError ());
5130 if (TypeManager.GetParameterData (setter).Count != 1){
5131 Error_PropertyNotFound (setter, false);
5135 bool must_do_cs1540_check;
5136 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
5137 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
5138 if (pm != null && pm.HasCustomAccessModifier) {
5139 Report.SymbolRelatedToPreviousError (pm);
5140 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5141 TypeManager.CSharpSignature (setter));
5144 Report.SymbolRelatedToPreviousError (setter);
5145 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
5150 if (!InstanceResolve (ec, PropertyInfo.DeclaringType.IsValueType, must_do_cs1540_check))
5154 // Only base will allow this invocation to happen.
5156 if (IsBase && setter.IsAbstract){
5157 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5164 public override void Emit (EmitContext ec)
5169 public void Emit (EmitContext ec, bool leave_copy)
5172 // Special case: length of single dimension array property is turned into ldlen
5174 if ((getter == TypeManager.system_int_array_get_length) ||
5175 (getter == TypeManager.int_array_get_length)){
5176 Type iet = InstanceExpression.Type;
5179 // System.Array.Length can be called, but the Type does not
5180 // support invoking GetArrayRank, so test for that case first
5182 if (iet != TypeManager.array_type && (iet.GetArrayRank () == 1)) {
5184 EmitInstance (ec, false);
5185 ec.ig.Emit (OpCodes.Ldlen);
5186 ec.ig.Emit (OpCodes.Conv_I4);
5191 Invocation.EmitCall (ec, IsBase, InstanceExpression, getter, null, loc, prepared, false);
5194 ec.ig.Emit (OpCodes.Dup);
5196 temp = new LocalTemporary (this.Type);
5203 // Implements the IAssignMethod interface for assignments
5205 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5207 Expression my_source = source;
5209 if (prepare_for_load) {
5210 if (source is StringConcat)
5211 EmitInstance (ec, false);
5219 ec.ig.Emit (OpCodes.Dup);
5221 temp = new LocalTemporary (this.Type);
5225 } else if (leave_copy) {
5227 temp = new LocalTemporary (this.Type);
5232 ArrayList args = new ArrayList (1);
5233 args.Add (new Argument (my_source, Argument.AType.Expression));
5235 Invocation.EmitCall (ec, IsBase, InstanceExpression, setter, args, loc, false, prepared);
5245 /// Fully resolved expression that evaluates to an Event
5247 public class EventExpr : MemberExpr {
5248 public readonly EventInfo EventInfo;
5252 MethodInfo add_accessor, remove_accessor;
5254 public EventExpr (EventInfo ei, Location loc)
5258 eclass = ExprClass.EventAccess;
5260 add_accessor = TypeManager.GetAddMethod (ei);
5261 remove_accessor = TypeManager.GetRemoveMethod (ei);
5262 if (add_accessor.IsStatic || remove_accessor.IsStatic)
5265 if (EventInfo is MyEventBuilder){
5266 MyEventBuilder eb = (MyEventBuilder) EventInfo;
5267 type = eb.EventType;
5270 type = EventInfo.EventHandlerType;
5273 public override string Name {
5275 return EventInfo.Name;
5279 public override bool IsInstance {
5285 public override bool IsStatic {
5291 public override Type DeclaringType {
5293 return EventInfo.DeclaringType;
5297 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
5298 SimpleName original)
5301 // If the event is local to this class, we transform ourselves into a FieldExpr
5304 if (EventInfo.DeclaringType == ec.ContainerType ||
5305 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
5306 EventField mi = TypeManager.GetEventField (EventInfo);
5309 if (!ec.IsInObsoleteScope)
5310 mi.CheckObsoleteness (loc);
5312 FieldExpr ml = new FieldExpr (mi.FieldBuilder, loc);
5314 InstanceExpression = null;
5316 return ml.ResolveMemberAccess (ec, left, loc, original);
5320 return base.ResolveMemberAccess (ec, left, loc, original);
5324 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
5327 InstanceExpression = null;
5331 if (InstanceExpression == null) {
5332 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5336 InstanceExpression = InstanceExpression.DoResolve (ec);
5337 if (InstanceExpression == null)
5340 if (IsBase && add_accessor.IsAbstract) {
5341 Error_CannotCallAbstractBase(TypeManager.CSharpSignature(add_accessor));
5346 // This is using the same mechanism as the CS1540 check in PropertyExpr.
5347 // However, in the Event case, we reported a CS0122 instead.
5349 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
5350 InstanceExpression.Type != ec.ContainerType &&
5351 ec.ContainerType.IsSubclassOf (InstanceExpression.Type)) {
5352 Report.SymbolRelatedToPreviousError (EventInfo);
5353 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5360 public bool IsAccessibleFrom (Type invocation_type)
5363 return IsAccessorAccessible (invocation_type, add_accessor, out dummy) &&
5364 IsAccessorAccessible (invocation_type, remove_accessor, out dummy);
5367 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5369 return DoResolve (ec);
5372 public override Expression DoResolve (EmitContext ec)
5374 bool must_do_cs1540_check;
5375 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
5376 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
5377 Report.SymbolRelatedToPreviousError (EventInfo);
5378 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5382 if (!InstanceResolve (ec, must_do_cs1540_check))
5388 public override void Emit (EmitContext ec)
5390 if (InstanceExpression is This)
5391 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of += or -=", GetSignatureForError ());
5393 Report.Error (70, loc, "The event `{0}' can only appear on the left hand side of += or -= "+
5394 "(except on the defining type)", Name);
5397 public override string GetSignatureForError ()
5399 return TypeManager.CSharpSignature (EventInfo);
5402 public void EmitAddOrRemove (EmitContext ec, Expression source)
5404 BinaryDelegate source_del = source as BinaryDelegate;
5405 if (source_del == null) {
5409 Expression handler = source_del.Right;
5411 Argument arg = new Argument (handler, Argument.AType.Expression);
5412 ArrayList args = new ArrayList ();
5416 if (source_del.IsAddition)
5417 Invocation.EmitCall (
5418 ec, IsBase, InstanceExpression, add_accessor, args, loc);
5420 Invocation.EmitCall (
5421 ec, IsBase, InstanceExpression, remove_accessor, args, loc);
5425 public class TemporaryVariable : Expression, IMemoryLocation
5430 public TemporaryVariable (Type type, Location loc)
5434 eclass = ExprClass.Value;
5437 public override Expression DoResolve (EmitContext ec)
5442 TypeExpr te = new TypeExpression (type, loc);
5443 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
5444 if (!li.Resolve (ec))
5447 if (ec.MustCaptureVariable (li)) {
5448 ScopeInfo scope = li.Block.CreateScopeInfo ();
5449 var = scope.AddLocal (li);
5456 public Variable Variable {
5457 get { return var != null ? var : li.Variable; }
5460 public override void Emit (EmitContext ec)
5462 Variable.EmitInstance (ec);
5466 public void EmitLoadAddress (EmitContext ec)
5468 Variable.EmitInstance (ec);
5469 Variable.EmitAddressOf (ec);
5472 public void Store (EmitContext ec, Expression right_side)
5474 Variable.EmitInstance (ec);
5475 right_side.Emit (ec);
5476 Variable.EmitAssign (ec);
5479 public void EmitThis (EmitContext ec)
5481 Variable.EmitInstance (ec);
5484 public void EmitStore (EmitContext ec)
5486 Variable.EmitAssign (ec);
5489 public void AddressOf (EmitContext ec, AddressOp mode)
5491 EmitLoadAddress (ec);
5496 /// Handles `var' contextual keyword; var becomes a keyword only
5497 /// if no type called var exists in a variable scope
5499 public class VarExpr : SimpleName
5501 // Used for error reporting only
5502 ArrayList initializer;
5504 public VarExpr (string name, Location loc)
5509 public ArrayList VariableInitializer {
5511 this.initializer = value;
5515 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5518 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
5520 type = right_side.Type;
5521 if (type == TypeManager.null_type || type == TypeManager.void_type || type == TypeManager.anonymous_method_type) {
5522 Report.Error (815, loc, "An implicitly typed local variable declaration cannot be initialized with `{0}'",
5523 right_side.GetSignatureForError ());
5527 eclass = ExprClass.Variable;
5531 protected override void Error_TypeOrNamespaceNotFound (IResolveContext ec)
5533 if (ec is FieldBase) {
5534 Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");
5538 base.Error_TypeOrNamespaceNotFound (ec);
5541 public override TypeExpr ResolveAsContextualType (IResolveContext rc, bool silent)
5543 TypeExpr te = base.ResolveAsContextualType (rc, true);
5547 if (initializer == null)
5550 // TODO: refactor, the error is reported too many times
5551 if (initializer.Count > 1) {
5552 Location loc = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [1]).Location;
5553 Report.Error (819, loc, "An implicitly typed local variable declaration cannot include multiple declarators");
5557 Expression variable_initializer = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [0]).expression_or_array_initializer;
5558 if (variable_initializer == null) {
5559 Report.Error (818, loc, "An implicitly typed local variable declarator must include an initializer");