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 valueType, 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 onTrue)
577 ec.ig.Emit (onTrue ? 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 containerType, 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 (containerType, (PropertyInfo) mi, loc);
603 else if (mi is Type){
604 return new TypeExpression ((System.Type) mi, loc);
610 protected static ArrayList almostMatchedMembers = 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 almostMatchedMembers.Clear ();
658 MemberInfo [] mi = TypeManager.MemberLookup (container_type, qualifier_type,
659 queried_type, mt, bf, name, almostMatchedMembers);
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 (almostMatchedMembers.Count != 0) {
789 for (int i = 0; i < almostMatchedMembers.Count; ++i) {
790 MemberInfo m = (MemberInfo) almostMatchedMembers [i];
791 for (int j = 0; j < i; ++j) {
792 if (m == almostMatchedMembers [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 almostMatchedMembers.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 valueType, out object value)
1307 return child.GetAttributableValue (valueType, 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 inCheckedContext, Type target_type)
1496 // FIXME: check that 'type' can be converted to 'target_type' first
1497 return child.ConvertExplicitly (inCheckedContext, 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 valueType, 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 inCheckedContext, Type target_type)
1613 if (Child.Type == target_type)
1616 return Child.ConvertExplicitly (inCheckedContext, 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 && almostMatchedMembers.Count > 0) {
2358 almost_matched_type = lookup_ds.TypeBuilder;
2359 almost_matched = (ArrayList) almostMatchedMembers.Clone ();
2364 if (almost_matched == null && almostMatchedMembers.Count > 0) {
2365 almost_matched_type = ec.ContainerType;
2366 almost_matched = (ArrayList) almostMatchedMembers.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 almostMatchedMembers = 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 namespaceEntry;
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.namespaceEntry = 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 namespaceEntry == 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, namespaceEntry, 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.namespaceEntry, 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 static IErrorHandler CustomErrorHandler;
3108 public MethodBase [] Methods;
3109 MethodBase best_candidate;
3110 bool has_type_arguments;
3111 bool identical_type_name;
3114 public MethodGroupExpr (MemberInfo [] mi, Type type, Location l)
3117 Methods = new MethodBase [mi.Length];
3118 mi.CopyTo (Methods, 0);
3121 public MethodGroupExpr (ArrayList list, Type type, Location l)
3125 Methods = (MethodBase[])list.ToArray (typeof (MethodBase));
3127 foreach (MemberInfo m in list){
3128 if (!(m is MethodBase)){
3129 Console.WriteLine ("Name " + m.Name);
3130 Console.WriteLine ("Found a: " + m.GetType ().FullName);
3139 protected MethodGroupExpr (Type type, Location loc)
3142 eclass = ExprClass.MethodGroup;
3146 public override Type DeclaringType {
3149 // We assume that the top-level type is in the end
3151 return Methods [Methods.Length - 1].DeclaringType;
3152 //return Methods [0].DeclaringType;
3156 public bool HasTypeArguments {
3158 return has_type_arguments;
3162 public bool IdenticalTypeName {
3164 return identical_type_name;
3168 identical_type_name = value;
3172 public virtual bool IsBase {
3181 public override string GetSignatureForError ()
3183 if (best_candidate != null)
3184 return TypeManager.CSharpSignature (best_candidate);
3186 return TypeManager.CSharpSignature (Methods [0]);
3189 public override string Name {
3191 return Methods [0].Name;
3195 public override bool IsInstance {
3197 foreach (MethodBase mb in Methods)
3205 public override bool IsStatic {
3207 foreach (MethodBase mb in Methods)
3215 public static explicit operator ConstructorInfo (MethodGroupExpr mg)
3217 return (ConstructorInfo)mg.best_candidate;
3220 public static explicit operator MethodInfo (MethodGroupExpr mg)
3222 return (MethodInfo)mg.best_candidate;
3226 /// Determines "better conversion" as specified in 14.4.2.3
3228 /// Returns : p if a->p is better,
3229 /// q if a->q is better,
3230 /// null if neither is better
3232 static Type BetterConversion (EmitContext ec, Argument a, Type p, Type q)
3234 Type argument_type = TypeManager.TypeToCoreType (a.Type);
3235 Expression argument_expr = a.Expr;
3237 if (argument_type == null)
3238 throw new Exception ("Expression of type " + a.Expr +
3239 " does not resolve its type");
3241 if (p == null || q == null)
3242 throw new InternalErrorException ("BetterConversion Got a null conversion");
3247 if (argument_expr is NullLiteral)
3250 // If the argument is null and one of the types to compare is 'object' and
3251 // the other is a reference type, we prefer the other.
3253 // This follows from the usual rules:
3254 // * There is an implicit conversion from 'null' to type 'object'
3255 // * There is an implicit conversion from 'null' to any reference type
3256 // * There is an implicit conversion from any reference type to type 'object'
3257 // * There is no implicit conversion from type 'object' to other reference types
3258 // => Conversion of 'null' to a reference type is better than conversion to 'object'
3260 // FIXME: This probably isn't necessary, since the type of a NullLiteral is the
3261 // null type. I think it used to be 'object' and thus needed a special
3262 // case to avoid the immediately following two checks.
3264 if (!p.IsValueType && q == TypeManager.object_type)
3266 if (!q.IsValueType && p == TypeManager.object_type)
3270 if (argument_type == p)
3273 if (argument_type == q)
3276 Expression p_tmp = new EmptyExpression (p);
3277 Expression q_tmp = new EmptyExpression (q);
3279 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3280 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3282 if (p_to_q && !q_to_p)
3285 if (q_to_p && !p_to_q)
3288 if (p == TypeManager.sbyte_type)
3289 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3290 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3292 if (q == TypeManager.sbyte_type)
3293 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3294 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3297 if (p == TypeManager.short_type)
3298 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3299 q == TypeManager.uint64_type)
3301 if (q == TypeManager.short_type)
3302 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3303 p == TypeManager.uint64_type)
3306 if (p == TypeManager.int32_type)
3307 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3309 if (q == TypeManager.int32_type)
3310 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3313 if (p == TypeManager.int64_type)
3314 if (q == TypeManager.uint64_type)
3316 if (q == TypeManager.int64_type)
3317 if (p == TypeManager.uint64_type)
3324 /// Determines "Better function" between candidate
3325 /// and the current best match
3328 /// Returns a boolean indicating :
3329 /// false if candidate ain't better
3330 /// true if candidate is better than the current best match
3332 static bool BetterFunction (EmitContext ec, ArrayList args, int argument_count,
3333 MethodBase candidate, bool candidate_params,
3334 MethodBase best, bool best_params)
3336 ParameterData candidate_pd = TypeManager.GetParameterData (candidate);
3337 ParameterData best_pd = TypeManager.GetParameterData (best);
3339 bool better_at_least_one = false;
3341 for (int j = 0, c_idx = 0, b_idx = 0; j < argument_count; ++j, ++c_idx, ++b_idx)
3343 Argument a = (Argument) args [j];
3345 Type ct = TypeManager.TypeToCoreType (candidate_pd.ParameterType (c_idx));
3346 Type bt = TypeManager.TypeToCoreType (best_pd.ParameterType (b_idx));
3348 if (candidate_params && candidate_pd.ParameterModifier (c_idx) == Parameter.Modifier.PARAMS)
3350 ct = TypeManager.GetElementType (ct);
3354 if (best_params && best_pd.ParameterModifier (b_idx) == Parameter.Modifier.PARAMS)
3356 bt = TypeManager.GetElementType (bt);
3364 Type better = BetterConversion (ec, a, ct, bt);
3366 // for each argument, the conversion to 'ct' should be no worse than
3367 // the conversion to 'bt'.
3371 // for at least one argument, the conversion to 'ct' should be better than
3372 // the conversion to 'bt'.
3374 better_at_least_one = true;
3377 if (better_at_least_one)
3381 // This handles the case
3383 // Add (float f1, float f2, float f3);
3384 // Add (params decimal [] foo);
3386 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3387 // first candidate would've chosen as better.
3393 // The two methods have equal parameter types. Now apply tie-breaking rules
3395 if (TypeManager.IsGenericMethod (best) && !TypeManager.IsGenericMethod (candidate))
3397 if (!TypeManager.IsGenericMethod (best) && TypeManager.IsGenericMethod (candidate))
3401 // This handles the following cases:
3403 // Trim () is better than Trim (params char[] chars)
3404 // Concat (string s1, string s2, string s3) is better than
3405 // Concat (string s1, params string [] srest)
3406 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3408 if (!candidate_params && best_params)
3410 if (candidate_params && !best_params)
3413 int candidate_param_count = candidate_pd.Count;
3414 int best_param_count = best_pd.Count;
3416 if (candidate_param_count != best_param_count)
3417 // can only happen if (candidate_params && best_params)
3418 return candidate_param_count > best_param_count;
3421 // now, both methods have the same number of parameters, and the parameters have the same types
3422 // Pick the "more specific" signature
3425 MethodBase orig_candidate = TypeManager.DropGenericMethodArguments (candidate);
3426 MethodBase orig_best = TypeManager.DropGenericMethodArguments (best);
3428 ParameterData orig_candidate_pd = TypeManager.GetParameterData (orig_candidate);
3429 ParameterData orig_best_pd = TypeManager.GetParameterData (orig_best);
3431 bool specific_at_least_once = false;
3432 for (int j = 0; j < candidate_param_count; ++j)
3434 Type ct = TypeManager.TypeToCoreType (orig_candidate_pd.ParameterType (j));
3435 Type bt = TypeManager.TypeToCoreType (orig_best_pd.ParameterType (j));
3438 Type specific = MoreSpecific (ct, bt);
3442 specific_at_least_once = true;
3445 if (specific_at_least_once)
3448 // FIXME: handle lifted operators
3454 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3455 SimpleName original)
3457 if (!(left is TypeExpr) &&
3458 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3459 IdenticalTypeName = true;
3461 return base.ResolveMemberAccess (ec, left, loc, original);
3464 override public Expression DoResolve (EmitContext ec)
3466 if (InstanceExpression != null) {
3467 InstanceExpression = InstanceExpression.DoResolve (ec);
3468 if (InstanceExpression == null)
3475 public void ReportUsageError ()
3477 Report.Error (654, loc, "Method `" + DeclaringType + "." +
3478 Name + "()' is referenced without parentheses");
3481 override public void Emit (EmitContext ec)
3483 ReportUsageError ();
3486 public virtual void EmitArguments (EmitContext ec, ArrayList arguments)
3488 Invocation.EmitArguments (ec, best_candidate, arguments, false, null);
3491 public virtual void EmitCall (EmitContext ec, ArrayList arguments)
3493 Invocation.EmitCall (ec, IsBase, InstanceExpression, best_candidate, arguments, loc);
3496 protected virtual void Error_InvalidArguments (EmitContext ec, Location loc, int idx, MethodBase method,
3497 Type delegate_type, Argument a, ParameterData expected_par)
3499 if (a is CollectionElementInitializer.ElementInitializerArgument) {
3500 Report.SymbolRelatedToPreviousError (method);
3501 if ((expected_par.ParameterModifier (idx) & Parameter.Modifier.ISBYREF) != 0) {
3502 Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
3503 TypeManager.CSharpSignature (method));
3506 Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
3507 TypeManager.CSharpSignature (method));
3508 } else if (delegate_type == null) {
3509 Report.SymbolRelatedToPreviousError (method);
3510 Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
3511 TypeManager.CSharpSignature (method));
3513 Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
3514 TypeManager.CSharpName (delegate_type));
3516 Parameter.Modifier mod = expected_par.ParameterModifier (idx);
3518 string index = (idx + 1).ToString ();
3519 if ((mod & Parameter.Modifier.ISBYREF) != (a.Modifier & Parameter.Modifier.ISBYREF) ||
3520 (mod & Parameter.Modifier.ISBYREF) != 0) {
3521 if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) == 0)
3522 Report.Error (1615, loc, "Argument `{0}' should not be passed with the `{1}' keyword",
3523 index, Parameter.GetModifierSignature (a.Modifier));
3525 Report.Error (1620, loc, "Argument `{0}' must be passed with the `{1}' keyword",
3526 index, Parameter.GetModifierSignature (mod));
3528 string p1 = Argument.FullDesc (a);
3529 string p2 = TypeManager.CSharpName (expected_par.ParameterType (idx));
3532 Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
3533 Report.SymbolRelatedToPreviousError (a.Expr.Type);
3534 Report.SymbolRelatedToPreviousError (expected_par.ParameterType (idx));
3536 Report.Error (1503, loc, "Argument {0}: Cannot convert type `{1}' to `{2}'", index, p1, p2);
3540 protected virtual int GetApplicableParametersCount (MethodBase method, ParameterData parameters)
3542 return parameters.Count;
3545 public static bool IsAncestralType (Type first_type, Type second_type)
3547 return first_type != second_type &&
3548 (TypeManager.IsSubclassOf (second_type, first_type) ||
3549 TypeManager.ImplementsInterface (second_type, first_type));
3553 /// Determines if the candidate method is applicable (section 14.4.2.1)
3554 /// to the given set of arguments
3555 /// A return value rates candidate method compatibility,
3556 /// 0 = the best, int.MaxValue = the worst
3558 public int IsApplicable (EmitContext ec,
3559 ArrayList arguments, int arg_count, ref MethodBase method)
3561 MethodBase candidate = method;
3563 ParameterData pd = TypeManager.GetParameterData (candidate);
3564 int param_count = GetApplicableParametersCount (candidate, pd);
3566 if (arg_count != param_count)
3567 return int.MaxValue;
3570 // 1. Infer type arguments for generic method
3573 if (!HasTypeArguments && TypeManager.IsGenericMethod (method)) {
3574 int score = TypeManager.InferTypeArguments (ec, arguments, ref candidate);
3578 if (TypeManager.IsGenericMethodDefinition (candidate))
3579 throw new InternalErrorException ("a generic method definition took part in overload resolution");
3581 pd = TypeManager.GetParameterData (candidate);
3586 // 2. Each argument has to be implicitly converible to method parameter
3588 for (int i = arg_count; i > 0; ) {
3591 Argument a = (Argument) arguments [i];
3593 Parameter.Modifier a_mod = a.Modifier &
3594 ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3596 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
3597 ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK | Parameter.Modifier.PARAMS);
3599 Type pt = pd.ParameterType (i);
3601 // FIXME: Kill this abomination (EmitContext.TempEc)
3602 EmitContext prevec = EmitContext.TempEc;
3603 EmitContext.TempEc = ec;
3606 pt = pt.GetElementType ();
3608 if (!Convert.ImplicitConversionExists (ec, a.Expr, pt))
3615 EmitContext.TempEc = prevec;
3623 public static bool IsOverride (MethodBase cand_method, MethodBase base_method)
3625 if (!IsAncestralType (base_method.DeclaringType, cand_method.DeclaringType))
3628 ParameterData cand_pd = TypeManager.GetParameterData (cand_method);
3629 ParameterData base_pd = TypeManager.GetParameterData (base_method);
3631 if (cand_pd.Count != base_pd.Count)
3634 for (int j = 0; j < cand_pd.Count; ++j)
3636 Parameter.Modifier cm = cand_pd.ParameterModifier (j);
3637 Parameter.Modifier bm = base_pd.ParameterModifier (j);
3638 Type ct = TypeManager.TypeToCoreType (cand_pd.ParameterType (j));
3639 Type bt = TypeManager.TypeToCoreType (base_pd.ParameterType (j));
3641 if (cm != bm || ct != bt)
3648 public bool IsParamsMethodApplicable (EmitContext ec,
3649 ArrayList arguments, int arg_count,
3650 ref MethodBase candidate)
3652 return IsParamsMethodApplicable (
3653 ec, arguments, arg_count, false, ref candidate) ||
3654 IsParamsMethodApplicable (
3655 ec, arguments, arg_count, true, ref candidate);
3660 bool IsParamsMethodApplicable (EmitContext ec,
3661 ArrayList arguments, int arg_count,
3662 bool do_varargs, ref MethodBase candidate)
3665 if (!HasTypeArguments &&
3666 !TypeManager.InferParamsTypeArguments (ec, arguments, ref candidate))
3669 if (TypeManager.IsGenericMethodDefinition (candidate))
3670 throw new InternalErrorException ("a generic method definition took part in overload resolution");
3673 return IsParamsMethodApplicable (
3674 ec, arguments, arg_count, candidate, do_varargs);
3678 /// Determines if the candidate method, if a params method, is applicable
3679 /// in its expanded form to the given set of arguments
3681 bool IsParamsMethodApplicable (EmitContext ec, ArrayList arguments,
3682 int arg_count, MethodBase candidate,
3685 ParameterData pd = TypeManager.GetParameterData (candidate);
3686 int pd_count = GetApplicableParametersCount (candidate, pd);
3690 int count = pd_count - 1;
3692 if (pd.ParameterModifier (count) != Parameter.Modifier.ARGLIST)
3694 if (pd_count != arg_count)
3697 if (!(((Argument) arguments [count]).Expr is Arglist))
3705 if (count > arg_count)
3708 if (pd_count == 1 && arg_count == 0)
3712 // If we have come this far, the case which
3713 // remains is when the number of parameters is
3714 // less than or equal to the argument count.
3716 int argument_index = 0;
3718 for (int i = 0; i < pd_count; ++i) {
3720 if ((pd.ParameterModifier (i) & Parameter.Modifier.PARAMS) != 0) {
3721 Type element_type = TypeManager.GetElementType (pd.ParameterType (i));
3722 int params_args_count = arg_count - pd_count;
3723 if (params_args_count < 0)
3727 a = (Argument) arguments [argument_index++];
3729 if (!Convert.ImplicitConversionExists (ec, a.Expr, element_type))
3731 } while (params_args_count-- > 0);
3735 a = (Argument) arguments [argument_index++];
3737 Parameter.Modifier a_mod = a.Modifier &
3738 (unchecked (~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK)));
3739 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
3740 (unchecked (~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK)));
3742 if (a_mod == p_mod) {
3744 if (a_mod == Parameter.Modifier.NONE)
3745 if (!Convert.ImplicitConversionExists (ec,
3747 pd.ParameterType (i)))
3750 if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {
3751 Type pt = pd.ParameterType (i);
3754 pt = TypeManager.GetReferenceType (pt);
3767 public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2, Location loc)
3769 MemberInfo [] miset;
3770 MethodGroupExpr union;
3775 return (MethodGroupExpr) mg2;
3778 return (MethodGroupExpr) mg1;
3781 MethodGroupExpr left_set = null, right_set = null;
3782 int length1 = 0, length2 = 0;
3784 left_set = (MethodGroupExpr) mg1;
3785 length1 = left_set.Methods.Length;
3787 right_set = (MethodGroupExpr) mg2;
3788 length2 = right_set.Methods.Length;
3790 ArrayList common = new ArrayList ();
3792 foreach (MethodBase r in right_set.Methods){
3793 if (TypeManager.ArrayContainsMethod (left_set.Methods, r))
3797 miset = new MemberInfo [length1 + length2 - common.Count];
3798 left_set.Methods.CopyTo (miset, 0);
3802 foreach (MethodBase r in right_set.Methods) {
3803 if (!common.Contains (r))
3807 union = new MethodGroupExpr (miset, mg1.Type, loc);
3812 static Type MoreSpecific (Type p, Type q)
3814 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
3816 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
3819 if (TypeManager.HasElementType (p))
3821 Type pe = TypeManager.GetElementType (p);
3822 Type qe = TypeManager.GetElementType (q);
3823 Type specific = MoreSpecific (pe, qe);
3829 else if (TypeManager.IsGenericType (p))
3831 Type[] pargs = TypeManager.GetTypeArguments (p);
3832 Type[] qargs = TypeManager.GetTypeArguments (q);
3834 bool p_specific_at_least_once = false;
3835 bool q_specific_at_least_once = false;
3837 for (int i = 0; i < pargs.Length; i++)
3839 Type specific = MoreSpecific (pargs [i], qargs [i]);
3840 if (specific == pargs [i])
3841 p_specific_at_least_once = true;
3842 if (specific == qargs [i])
3843 q_specific_at_least_once = true;
3846 if (p_specific_at_least_once && !q_specific_at_least_once)
3848 if (!p_specific_at_least_once && q_specific_at_least_once)
3856 /// Find the Applicable Function Members (7.4.2.1)
3858 /// me: Method Group expression with the members to select.
3859 /// it might contain constructors or methods (or anything
3860 /// that maps to a method).
3862 /// Arguments: ArrayList containing resolved Argument objects.
3864 /// loc: The location if we want an error to be reported, or a Null
3865 /// location for "probing" purposes.
3867 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3868 /// that is the best match of me on Arguments.
3871 public virtual MethodGroupExpr OverloadResolve (EmitContext ec, ArrayList Arguments,
3872 bool may_fail, Location loc)
3874 bool method_params = false;
3875 Type applicable_type = null;
3877 ArrayList candidates = new ArrayList (2);
3878 ArrayList candidate_overrides = null;
3881 // Used to keep a map between the candidate
3882 // and whether it is being considered in its
3883 // normal or expanded form
3885 // false is normal form, true is expanded form
3887 Hashtable candidate_to_form = null;
3889 if (Arguments != null)
3890 arg_count = Arguments.Count;
3892 if (RootContext.Version == LanguageVersion.ISO_1 && Name == "Invoke" && TypeManager.IsDelegateType (DeclaringType)) {
3894 Report.Error (1533, loc, "Invoke cannot be called directly on a delegate");
3898 int nmethods = Methods.Length;
3902 // Methods marked 'override' don't take part in 'applicable_type'
3903 // computation, nor in the actual overload resolution.
3904 // However, they still need to be emitted instead of a base virtual method.
3905 // So, we salt them away into the 'candidate_overrides' array.
3907 // In case of reflected methods, we replace each overriding method with
3908 // its corresponding base virtual method. This is to improve compatibility
3909 // with non-C# libraries which change the visibility of overrides (#75636)
3912 for (int i = 0; i < Methods.Length; ++i) {
3913 MethodBase m = Methods [i];
3915 Type [] gen_args = null;
3916 if (m.IsGenericMethod && !m.IsGenericMethodDefinition)
3917 gen_args = m.GetGenericArguments ();
3919 if (TypeManager.IsOverride (m)) {
3920 if (candidate_overrides == null)
3921 candidate_overrides = new ArrayList ();
3922 candidate_overrides.Add (m);
3923 m = TypeManager.TryGetBaseDefinition (m);
3925 if (m != null && gen_args != null) {
3926 if (!m.IsGenericMethodDefinition)
3927 throw new InternalErrorException ("GetBaseDefinition didn't return a GenericMethodDefinition");
3928 m = ((MethodInfo) m).MakeGenericMethod (gen_args);
3939 // Enable message recording, it's used mainly by lambda expressions
3941 Report.IMessageRecorder msg_recorder = new Report.MessageRecorder ();
3942 Report.IMessageRecorder prev_recorder = Report.SetMessageRecorder (msg_recorder);
3945 // First we construct the set of applicable methods
3947 bool is_sorted = true;
3948 int best_candidate_rate = int.MaxValue;
3949 for (int i = 0; i < nmethods; i++) {
3950 Type decl_type = Methods [i].DeclaringType;
3953 // If we have already found an applicable method
3954 // we eliminate all base types (Section 14.5.5.1)
3956 if (applicable_type != null && IsAncestralType (decl_type, applicable_type))
3960 // Check if candidate is applicable (section 14.4.2.1)
3961 // Is candidate applicable in normal form?
3963 int candidate_rate = IsApplicable (ec, Arguments, arg_count, ref Methods [i]);
3965 if (candidate_rate != 0 && IsParamsMethodApplicable (ec, Arguments, arg_count, ref Methods [i])) {
3966 MethodBase candidate = Methods [i];
3967 if (candidate_to_form == null)
3968 candidate_to_form = new PtrHashtable ();
3969 candidate_to_form [candidate] = candidate;
3970 // Candidate is applicable in expanded form
3974 if (candidate_rate < best_candidate_rate) {
3975 best_candidate_rate = candidate_rate;
3976 best_candidate = Methods [i];
3979 if (candidate_rate != 0) {
3980 if (msg_recorder != null)
3981 msg_recorder.EndSession ();
3985 msg_recorder = null;
3987 candidates.Add (Methods [i]);
3989 if (applicable_type == null)
3990 applicable_type = decl_type;
3991 else if (applicable_type != decl_type) {
3993 if (IsAncestralType (applicable_type, decl_type))
3994 applicable_type = decl_type;
3998 Report.SetMessageRecorder (prev_recorder);
3999 if (msg_recorder != null && msg_recorder.PrintMessages ())
4002 int candidate_top = candidates.Count;
4004 if (applicable_type == null) {
4005 if (ec.IsInProbingMode || may_fail)
4009 // Okay so we have failed to find exact match so we
4010 // return error info about the closest match
4012 if (best_candidate != null) {
4013 if (CustomErrorHandler != null) {
4014 if (CustomErrorHandler.NoExactMatch (ec, best_candidate))
4018 if (TypeManager.IsGenericMethod (best_candidate)) {
4019 Report.Error (411, loc,
4020 "The type arguments for method `{0}' cannot be inferred from " +
4021 "the usage. Try specifying the type arguments explicitly",
4022 TypeManager.CSharpSignature (best_candidate));
4024 VerifyArgumentsCompat (ec, Arguments, arg_count, best_candidate, false, null, may_fail, loc);
4030 if (almostMatchedMembers.Count != 0) {
4031 Error_MemberLookupFailed (ec.ContainerType, type, type, ".ctor",
4032 null, MemberTypes.Constructor, AllBindingFlags);
4037 // We failed to find any match
4039 if (Name == ConstructorInfo.ConstructorName) {
4040 Report.SymbolRelatedToPreviousError (type);
4041 Report.Error (1729, loc,
4042 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4043 TypeManager.CSharpName (type), arg_count);
4045 string report_name = Name;
4046 if (report_name == ConstructorInfo.ConstructorName)
4047 report_name = TypeManager.CSharpName (DeclaringType);
4049 Invocation.Error_WrongNumArguments (loc, report_name, arg_count);
4057 // At this point, applicable_type is _one_ of the most derived types
4058 // in the set of types containing the methods in this MethodGroup.
4059 // Filter the candidates so that they only contain methods from the
4060 // most derived types.
4063 int finalized = 0; // Number of finalized candidates
4066 // Invariant: applicable_type is a most derived type
4068 // We'll try to complete Section 14.5.5.1 for 'applicable_type' by
4069 // eliminating all it's base types. At the same time, we'll also move
4070 // every unrelated type to the end of the array, and pick the next
4071 // 'applicable_type'.
4073 Type next_applicable_type = null;
4074 int j = finalized; // where to put the next finalized candidate
4075 int k = finalized; // where to put the next undiscarded candidate
4076 for (int i = finalized; i < candidate_top; ++i) {
4077 MethodBase candidate = (MethodBase) candidates [i];
4078 Type decl_type = candidate.DeclaringType;
4080 if (decl_type == applicable_type) {
4081 candidates [k++] = candidates [j];
4082 candidates [j++] = candidates [i];
4086 if (IsAncestralType (decl_type, applicable_type))
4089 if (next_applicable_type != null &&
4090 IsAncestralType (decl_type, next_applicable_type))
4093 candidates [k++] = candidates [i];
4095 if (next_applicable_type == null ||
4096 IsAncestralType (next_applicable_type, decl_type))
4097 next_applicable_type = decl_type;
4100 applicable_type = next_applicable_type;
4103 } while (applicable_type != null);
4107 // Now we actually find the best method
4110 best_candidate = (MethodBase) candidates [0];
4111 method_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4112 for (int ix = 1; ix < candidate_top; ix++) {
4113 MethodBase candidate = (MethodBase) candidates [ix];
4115 if (candidate == best_candidate)
4118 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4120 if (BetterFunction (ec, Arguments, arg_count,
4121 candidate, cand_params,
4122 best_candidate, method_params)) {
4123 best_candidate = candidate;
4124 method_params = cand_params;
4128 // Now check that there are no ambiguities i.e the selected method
4129 // should be better than all the others
4131 MethodBase ambiguous = null;
4132 for (int ix = 0; ix < candidate_top; ix++) {
4133 MethodBase candidate = (MethodBase) candidates [ix];
4135 if (candidate == best_candidate)
4138 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4139 if (!BetterFunction (ec, Arguments, arg_count,
4140 best_candidate, method_params,
4141 candidate, cand_params))
4144 Report.SymbolRelatedToPreviousError (candidate);
4145 ambiguous = candidate;
4149 if (ambiguous != null) {
4150 Report.SymbolRelatedToPreviousError (best_candidate);
4151 Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4152 TypeManager.CSharpSignature (ambiguous), TypeManager.CSharpSignature (best_candidate));
4157 // If the method is a virtual function, pick an override closer to the LHS type.
4159 if (!IsBase && best_candidate.IsVirtual) {
4160 if (TypeManager.IsOverride (best_candidate))
4161 throw new InternalErrorException (
4162 "Should not happen. An 'override' method took part in overload resolution: " + best_candidate);
4164 if (candidate_overrides != null)
4165 foreach (MethodBase candidate in candidate_overrides) {
4166 if (IsOverride (candidate, best_candidate))
4167 best_candidate = candidate;
4171 // We can stop here when probing is on
4172 if (ec.IsInProbingMode)
4176 // And now check if the arguments are all
4177 // compatible, perform conversions if
4178 // necessary etc. and return if everything is
4181 if (!VerifyArgumentsCompat (ec, Arguments, arg_count, best_candidate,
4182 method_params, null, may_fail, loc))
4185 if (best_candidate == null)
4188 MethodBase the_method = TypeManager.DropGenericMethodArguments (best_candidate);
4190 if (the_method.IsGenericMethodDefinition &&
4191 !ConstraintChecker.CheckConstraints (ec, the_method, best_candidate, loc))
4195 IMethodData data = TypeManager.GetMethod (the_method);
4197 data.SetMemberIsUsed ();
4202 public Expression ResolveGeneric (EmitContext ec, TypeArguments args)
4205 if (!args.Resolve (ec))
4208 Type[] atypes = args.Arguments;
4210 int first_count = 0;
4211 MethodInfo first = null;
4213 ArrayList list = new ArrayList ();
4214 foreach (MethodBase mb in Methods) {
4215 MethodInfo mi = mb as MethodInfo;
4216 if ((mi == null) || !mb.IsGenericMethod)
4219 Type[] gen_params = mb.GetGenericArguments ();
4221 if (first == null) {
4223 first_count = gen_params.Length;
4226 if (gen_params.Length != atypes.Length)
4229 mi = mi.MakeGenericMethod (atypes);
4233 // MS implementation throws NotSupportedException for GetParameters
4234 // on unbaked generic method
4235 Parameters p = TypeManager.GetParameterData (mi) as Parameters;
4238 p.InflateTypes (gen_params, atypes);
4239 TypeManager.RegisterMethod (mi, p);
4244 if (list.Count > 0) {
4245 this.Methods = (MethodBase []) list.ToArray (typeof (MethodBase));
4246 has_type_arguments = true;
4250 if (first != null) {
4251 Report.SymbolRelatedToPreviousError (first);
4253 305, loc, "Using the generic method `{0}' requires `{1}' type arguments",
4254 TypeManager.CSharpSignature (first), first_count.ToString ());
4257 308, loc, "The non-generic method `{0}' " +
4258 "cannot be used with type arguments", Name);
4262 throw new NotImplementedException ();
4266 public bool VerifyArgumentsCompat (EmitContext ec, ArrayList Arguments,
4267 int arg_count, MethodBase method,
4268 bool chose_params_expanded,
4269 Type delegate_type, bool may_fail, Location loc)
4271 ParameterData pd = TypeManager.GetParameterData (method);
4272 int param_count = GetApplicableParametersCount (method, pd);
4277 int errors = Report.Errors;
4278 for (j = 0; j < param_count; j++) {
4279 Type parameter_type = pd.ParameterType (j);
4280 Parameter.Modifier pm = pd.ParameterModifier (j);
4282 if (pm == Parameter.Modifier.ARGLIST) {
4283 a = (Argument) Arguments [a_idx];
4284 if (!(a.Expr is Arglist))
4290 int params_arg_count = 1;
4291 if (pm == Parameter.Modifier.PARAMS) {
4292 pm = Parameter.Modifier.NONE;
4293 params_arg_count = arg_count - param_count + 1;
4294 if (chose_params_expanded)
4295 parameter_type = TypeManager.GetElementType (parameter_type);
4298 while (params_arg_count > 0) {
4299 a = (Argument) Arguments [a_idx];
4300 if (pm != a.Modifier)
4303 if (!TypeManager.IsEqual (a.Type, parameter_type)) {
4304 if (pm == Parameter.Modifier.OUT || pm == Parameter.Modifier.REF)
4307 Expression conv = Convert.ImplicitConversion (ec, a.Expr, parameter_type, loc);
4311 // Update the argument with the implicit conversion
4319 if (params_arg_count > 0)
4322 if (parameter_type.IsPointer && !ec.InUnsafe) {
4329 if (a_idx == arg_count)
4332 if (!may_fail && Report.Errors == errors)
4333 Error_InvalidArguments (ec, loc, a_idx, method, delegate_type, a, pd);
4339 /// Fully resolved expression that evaluates to a Field
4341 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariable {
4342 public readonly FieldInfo FieldInfo;
4343 VariableInfo variable_info;
4345 LocalTemporary temp;
4347 bool in_initializer;
4349 public FieldExpr (FieldInfo fi, Location l, bool in_initializer):
4352 this.in_initializer = in_initializer;
4355 public FieldExpr (FieldInfo fi, Location l)
4358 eclass = ExprClass.Variable;
4359 type = TypeManager.TypeToCoreType (fi.FieldType);
4363 public override string Name {
4365 return FieldInfo.Name;
4369 public override bool IsInstance {
4371 return !FieldInfo.IsStatic;
4375 public override bool IsStatic {
4377 return FieldInfo.IsStatic;
4381 public override Type DeclaringType {
4383 return FieldInfo.DeclaringType;
4387 public override string GetSignatureForError ()
4389 return TypeManager.GetFullNameSignature (FieldInfo);
4392 public VariableInfo VariableInfo {
4394 return variable_info;
4398 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
4399 SimpleName original)
4401 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
4403 Type t = fi.FieldType;
4405 if (fi.IsLiteral || (fi.IsInitOnly && t == TypeManager.decimal_type)) {
4406 IConstant ic = TypeManager.GetConstant (fi);
4409 ic = new ExternalConstant (fi);
4411 ic = ExternalConstant.CreateDecimal (fi);
4413 return base.ResolveMemberAccess (ec, left, loc, original);
4416 TypeManager.RegisterConstant (fi, ic);
4419 bool left_is_type = left is TypeExpr;
4420 if (!left_is_type && (original == null || !original.IdenticalNameAndTypeName (ec, left, loc))) {
4421 Report.SymbolRelatedToPreviousError (FieldInfo);
4422 error176 (loc, TypeManager.GetFullNameSignature (FieldInfo));
4426 if (ic.ResolveValue ()) {
4427 if (!ec.IsInObsoleteScope)
4428 ic.CheckObsoleteness (loc);
4431 return ic.CreateConstantReference (loc);
4434 if (t.IsPointer && !ec.InUnsafe) {
4438 return base.ResolveMemberAccess (ec, left, loc, original);
4441 override public Expression DoResolve (EmitContext ec)
4443 return DoResolve (ec, false, false);
4446 Expression DoResolve (EmitContext ec, bool lvalue_instance, bool out_access)
4448 if (!FieldInfo.IsStatic){
4449 if (InstanceExpression == null){
4451 // This can happen when referencing an instance field using
4452 // a fully qualified type expression: TypeName.InstanceField = xxx
4454 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4458 // Resolve the field's instance expression while flow analysis is turned
4459 // off: when accessing a field "a.b", we must check whether the field
4460 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4462 if (lvalue_instance) {
4463 using (ec.With (EmitContext.Flags.DoFlowAnalysis, false)) {
4464 Expression right_side =
4465 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4466 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side, loc);
4469 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
4470 InstanceExpression = InstanceExpression.Resolve (ec, rf);
4473 if (InstanceExpression == null)
4476 InstanceExpression.CheckMarshalByRefAccess ();
4479 if (!in_initializer && !ec.IsInFieldInitializer) {
4480 ObsoleteAttribute oa;
4481 FieldBase f = TypeManager.GetField (FieldInfo);
4483 if (!ec.IsInObsoleteScope)
4484 f.CheckObsoleteness (loc);
4486 // To be sure that type is external because we do not register generated fields
4487 } else if (!(FieldInfo.DeclaringType is TypeBuilder)) {
4488 oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
4490 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
4494 AnonymousContainer am = ec.CurrentAnonymousMethod;
4496 if (!FieldInfo.IsStatic){
4497 if (!am.IsIterator && (ec.TypeContainer is Struct)){
4498 Report.Error (1673, loc,
4499 "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",
4506 IFixedBuffer fb = AttributeTester.GetFixedBuffer (FieldInfo);
4508 if (!ec.InFixedInitializer && ec.ContainerType.IsValueType) {
4509 Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4512 if (!(InstanceExpression is LocalVariableReference) &&
4513 !(InstanceExpression is This)) {
4514 Report.SymbolRelatedToPreviousError (FieldInfo);
4515 Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4516 TypeManager.GetFullNameSignature (FieldInfo));
4519 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4522 // If the instance expression is a local variable or parameter.
4523 IVariable var = InstanceExpression as IVariable;
4524 if ((var == null) || (var.VariableInfo == null))
4527 VariableInfo vi = var.VariableInfo;
4528 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
4531 variable_info = vi.GetSubStruct (FieldInfo.Name);
4535 static readonly int [] codes = {
4536 191, // instance, write access
4537 192, // instance, out access
4538 198, // static, write access
4539 199, // static, out access
4540 1648, // member of value instance, write access
4541 1649, // member of value instance, out access
4542 1650, // member of value static, write access
4543 1651 // member of value static, out access
4546 static readonly string [] msgs = {
4547 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4548 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4549 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4550 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4551 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4552 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4553 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4554 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4557 // The return value is always null. Returning a value simplifies calling code.
4558 Expression Report_AssignToReadonly (Expression right_side)
4561 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4565 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4567 Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4572 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4574 IVariable var = InstanceExpression as IVariable;
4575 if ((var != null) && (var.VariableInfo != null))
4576 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
4578 bool lvalue_instance = !FieldInfo.IsStatic && FieldInfo.DeclaringType.IsValueType;
4579 bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
4581 Expression e = DoResolve (ec, lvalue_instance, out_access);
4586 FieldBase fb = TypeManager.GetField (FieldInfo);
4590 if (FieldInfo.IsInitOnly) {
4591 // InitOnly fields can only be assigned in constructors or initializers
4592 if (!ec.IsInFieldInitializer && !ec.IsConstructor)
4593 return Report_AssignToReadonly (right_side);
4595 if (ec.IsConstructor) {
4596 Type ctype = ec.TypeContainer.CurrentType;
4598 ctype = ec.ContainerType;
4600 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4601 if (!TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
4602 return Report_AssignToReadonly (right_side);
4603 // static InitOnly fields cannot be assigned-to in an instance constructor
4604 if (IsStatic && !ec.IsStatic)
4605 return Report_AssignToReadonly (right_side);
4606 // instance constructors can't modify InitOnly fields of other instances of the same type
4607 if (!IsStatic && !(InstanceExpression is This))
4608 return Report_AssignToReadonly (right_side);
4612 if (right_side == EmptyExpression.OutAccess &&
4613 !IsStatic && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
4614 Report.SymbolRelatedToPreviousError (DeclaringType);
4615 Report.Warning (197, 1, loc,
4616 "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",
4617 GetSignatureForError ());
4623 public override void CheckMarshalByRefAccess ()
4625 if (!IsStatic && Type.IsValueType && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
4626 Report.SymbolRelatedToPreviousError (DeclaringType);
4627 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",
4628 GetSignatureForError ());
4632 public bool VerifyFixed ()
4634 IVariable variable = InstanceExpression as IVariable;
4635 // A variable of the form V.I is fixed when V is a fixed variable of a struct type.
4636 // We defer the InstanceExpression check after the variable check to avoid a
4637 // separate null check on InstanceExpression.
4638 return variable != null && InstanceExpression.Type.IsValueType && variable.VerifyFixed ();
4641 public override int GetHashCode ()
4643 return FieldInfo.GetHashCode ();
4646 public override bool Equals (object obj)
4648 FieldExpr fe = obj as FieldExpr;
4652 if (FieldInfo != fe.FieldInfo)
4655 if (InstanceExpression == null || fe.InstanceExpression == null)
4658 return InstanceExpression.Equals (fe.InstanceExpression);
4661 public void Emit (EmitContext ec, bool leave_copy)
4663 ILGenerator ig = ec.ig;
4664 bool is_volatile = false;
4666 FieldBase f = TypeManager.GetField (FieldInfo);
4668 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4671 f.SetMemberIsUsed ();
4674 if (FieldInfo.IsStatic){
4676 ig.Emit (OpCodes.Volatile);
4678 ig.Emit (OpCodes.Ldsfld, FieldInfo);
4681 EmitInstance (ec, false);
4683 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
4685 ig.Emit (OpCodes.Ldflda, FieldInfo);
4686 ig.Emit (OpCodes.Ldflda, ff.Element);
4689 ig.Emit (OpCodes.Volatile);
4691 ig.Emit (OpCodes.Ldfld, FieldInfo);
4696 ec.ig.Emit (OpCodes.Dup);
4697 if (!FieldInfo.IsStatic) {
4698 temp = new LocalTemporary (this.Type);
4704 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4706 FieldAttributes fa = FieldInfo.Attributes;
4707 bool is_static = (fa & FieldAttributes.Static) != 0;
4708 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
4709 ILGenerator ig = ec.ig;
4711 if (is_readonly && !ec.IsConstructor){
4712 Report_AssignToReadonly (source);
4717 // String concatenation creates a new string instance
4719 prepared = prepare_for_load && !(source is StringConcat);
4720 EmitInstance (ec, prepared);
4724 ec.ig.Emit (OpCodes.Dup);
4725 if (!FieldInfo.IsStatic) {
4726 temp = new LocalTemporary (this.Type);
4731 FieldBase f = TypeManager.GetField (FieldInfo);
4733 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4734 ig.Emit (OpCodes.Volatile);
4740 ig.Emit (OpCodes.Stsfld, FieldInfo);
4742 ig.Emit (OpCodes.Stfld, FieldInfo);
4750 public override void Emit (EmitContext ec)
4755 public void AddressOf (EmitContext ec, AddressOp mode)
4757 ILGenerator ig = ec.ig;
4759 FieldBase f = TypeManager.GetField (FieldInfo);
4761 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
4762 Report.Warning (420, 1, loc, "`{0}': A volatile field references will not be treated as volatile",
4763 f.GetSignatureForError ());
4766 if ((mode & AddressOp.Store) != 0)
4768 if ((mode & AddressOp.Load) != 0)
4769 f.SetMemberIsUsed ();
4773 // Handle initonly fields specially: make a copy and then
4774 // get the address of the copy.
4777 if (FieldInfo.IsInitOnly){
4779 if (ec.IsConstructor){
4780 if (FieldInfo.IsStatic){
4792 local = ig.DeclareLocal (type);
4793 ig.Emit (OpCodes.Stloc, local);
4794 ig.Emit (OpCodes.Ldloca, local);
4799 if (FieldInfo.IsStatic){
4800 ig.Emit (OpCodes.Ldsflda, FieldInfo);
4803 EmitInstance (ec, false);
4804 ig.Emit (OpCodes.Ldflda, FieldInfo);
4810 // A FieldExpr whose address can not be taken
4812 public class FieldExprNoAddress : FieldExpr, IMemoryLocation {
4813 public FieldExprNoAddress (FieldInfo fi, Location loc) : base (fi, loc)
4817 public new void AddressOf (EmitContext ec, AddressOp mode)
4819 Report.Error (-215, "Report this: Taking the address of a remapped parameter not supported");
4824 /// Expression that evaluates to a Property. The Assign class
4825 /// might set the `Value' expression if we are in an assignment.
4827 /// This is not an LValue because we need to re-write the expression, we
4828 /// can not take data from the stack and store it.
4830 public class PropertyExpr : MemberExpr, IAssignMethod {
4831 public readonly PropertyInfo PropertyInfo;
4834 // This is set externally by the `BaseAccess' class
4837 MethodInfo getter, setter;
4842 LocalTemporary temp;
4845 public PropertyExpr (Type containerType, PropertyInfo pi, Location l)
4848 eclass = ExprClass.PropertyAccess;
4852 type = TypeManager.TypeToCoreType (pi.PropertyType);
4854 ResolveAccessors (containerType);
4857 public override string Name {
4859 return PropertyInfo.Name;
4863 public override bool IsInstance {
4869 public override bool IsStatic {
4875 public override Type DeclaringType {
4877 return PropertyInfo.DeclaringType;
4881 public override string GetSignatureForError ()
4883 return TypeManager.GetFullNameSignature (PropertyInfo);
4886 void FindAccessors (Type invocation_type)
4888 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
4889 BindingFlags.Static | BindingFlags.Instance |
4890 BindingFlags.DeclaredOnly;
4892 Type current = PropertyInfo.DeclaringType;
4893 for (; current != null; current = current.BaseType) {
4894 MemberInfo[] group = TypeManager.MemberLookup (
4895 invocation_type, invocation_type, current,
4896 MemberTypes.Property, flags, PropertyInfo.Name, null);
4901 if (group.Length != 1)
4902 // Oooops, can this ever happen ?
4905 PropertyInfo pi = (PropertyInfo) group [0];
4908 getter = pi.GetGetMethod (true);
4911 setter = pi.GetSetMethod (true);
4913 MethodInfo accessor = getter != null ? getter : setter;
4915 if (!accessor.IsVirtual)
4921 // We also perform the permission checking here, as the PropertyInfo does not
4922 // hold the information for the accessibility of its setter/getter
4924 // TODO: Refactor to use some kind of cache together with GetPropertyFromAccessor
4925 void ResolveAccessors (Type containerType)
4927 FindAccessors (containerType);
4929 if (getter != null) {
4930 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
4931 IMethodData md = TypeManager.GetMethod (the_getter);
4933 md.SetMemberIsUsed ();
4935 is_static = getter.IsStatic;
4938 if (setter != null) {
4939 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
4940 IMethodData md = TypeManager.GetMethod (the_setter);
4942 md.SetMemberIsUsed ();
4944 is_static = setter.IsStatic;
4948 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
4951 InstanceExpression = null;
4955 if (InstanceExpression == null) {
4956 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4960 InstanceExpression = InstanceExpression.DoResolve (ec);
4961 if (lvalue_instance && InstanceExpression != null)
4962 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
4964 if (InstanceExpression == null)
4967 InstanceExpression.CheckMarshalByRefAccess ();
4969 if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) &&
4970 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
4971 !TypeManager.IsNestedChildOf (ec.ContainerType, InstanceExpression.Type) &&
4972 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.ContainerType)) {
4973 Report.SymbolRelatedToPreviousError (PropertyInfo);
4974 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
4981 void Error_PropertyNotFound (MethodInfo mi, bool getter)
4983 // TODO: correctly we should compare arguments but it will lead to bigger changes
4984 if (mi is MethodBuilder) {
4985 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
4989 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
4991 ParameterData iparams = TypeManager.GetParameterData (mi);
4992 sig.Append (getter ? "get_" : "set_");
4994 sig.Append (iparams.GetSignatureForError ());
4996 Report.SymbolRelatedToPreviousError (mi);
4997 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
4998 Name, sig.ToString ());
5001 public bool IsAccessibleFrom (Type invocation_type, bool lvalue)
5004 MethodInfo accessor = lvalue ? setter : getter;
5005 if (accessor == null && lvalue)
5007 return accessor != null && IsAccessorAccessible (invocation_type, accessor, out dummy);
5010 override public Expression DoResolve (EmitContext ec)
5015 if (getter != null){
5016 if (TypeManager.GetParameterData (getter).Count != 0){
5017 Error_PropertyNotFound (getter, true);
5022 if (getter == null){
5024 // The following condition happens if the PropertyExpr was
5025 // created, but is invalid (ie, the property is inaccessible),
5026 // and we did not want to embed the knowledge about this in
5027 // the caller routine. This only avoids double error reporting.
5032 if (InstanceExpression != EmptyExpression.Null) {
5033 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5034 TypeManager.GetFullNameSignature (PropertyInfo));
5039 bool must_do_cs1540_check = false;
5040 if (getter != null &&
5041 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
5042 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
5043 if (pm != null && pm.HasCustomAccessModifier) {
5044 Report.SymbolRelatedToPreviousError (pm);
5045 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5046 TypeManager.CSharpSignature (getter));
5049 Report.SymbolRelatedToPreviousError (getter);
5050 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
5055 if (!InstanceResolve (ec, false, must_do_cs1540_check))
5059 // Only base will allow this invocation to happen.
5061 if (IsBase && getter.IsAbstract) {
5062 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5066 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
5076 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
5078 if (right_side == EmptyExpression.OutAccess) {
5079 if (ec.CurrentBlock.Toplevel.GetTransparentIdentifier (PropertyInfo.Name) != null) {
5080 Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5083 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as `ref' or `out' parameter",
5084 GetSignatureForError ());
5089 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5090 Report.Error (1612, loc, "Cannot modify the return value of `{0}' because it is not a variable",
5091 GetSignatureForError ());
5095 if (setter == null){
5097 // The following condition happens if the PropertyExpr was
5098 // created, but is invalid (ie, the property is inaccessible),
5099 // and we did not want to embed the knowledge about this in
5100 // the caller routine. This only avoids double error reporting.
5104 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
5105 GetSignatureForError ());
5109 if (TypeManager.GetParameterData (setter).Count != 1){
5110 Error_PropertyNotFound (setter, false);
5114 bool must_do_cs1540_check;
5115 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
5116 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
5117 if (pm != null && pm.HasCustomAccessModifier) {
5118 Report.SymbolRelatedToPreviousError (pm);
5119 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5120 TypeManager.CSharpSignature (setter));
5123 Report.SymbolRelatedToPreviousError (setter);
5124 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
5129 if (!InstanceResolve (ec, PropertyInfo.DeclaringType.IsValueType, must_do_cs1540_check))
5133 // Only base will allow this invocation to happen.
5135 if (IsBase && setter.IsAbstract){
5136 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5143 public override void Emit (EmitContext ec)
5148 public void Emit (EmitContext ec, bool leave_copy)
5151 // Special case: length of single dimension array property is turned into ldlen
5153 if ((getter == TypeManager.system_int_array_get_length) ||
5154 (getter == TypeManager.int_array_get_length)){
5155 Type iet = InstanceExpression.Type;
5158 // System.Array.Length can be called, but the Type does not
5159 // support invoking GetArrayRank, so test for that case first
5161 if (iet != TypeManager.array_type && (iet.GetArrayRank () == 1)) {
5163 EmitInstance (ec, false);
5164 ec.ig.Emit (OpCodes.Ldlen);
5165 ec.ig.Emit (OpCodes.Conv_I4);
5170 Invocation.EmitCall (ec, IsBase, InstanceExpression, getter, null, loc, prepared, false);
5173 ec.ig.Emit (OpCodes.Dup);
5175 temp = new LocalTemporary (this.Type);
5182 // Implements the IAssignMethod interface for assignments
5184 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5186 Expression my_source = source;
5188 if (prepare_for_load) {
5189 if (source is StringConcat)
5190 EmitInstance (ec, false);
5198 ec.ig.Emit (OpCodes.Dup);
5200 temp = new LocalTemporary (this.Type);
5204 } else if (leave_copy) {
5206 temp = new LocalTemporary (this.Type);
5211 ArrayList args = new ArrayList (1);
5212 args.Add (new Argument (my_source, Argument.AType.Expression));
5214 Invocation.EmitCall (ec, IsBase, InstanceExpression, setter, args, loc, false, prepared);
5224 /// Fully resolved expression that evaluates to an Event
5226 public class EventExpr : MemberExpr {
5227 public readonly EventInfo EventInfo;
5231 MethodInfo add_accessor, remove_accessor;
5233 public EventExpr (EventInfo ei, Location loc)
5237 eclass = ExprClass.EventAccess;
5239 add_accessor = TypeManager.GetAddMethod (ei);
5240 remove_accessor = TypeManager.GetRemoveMethod (ei);
5241 if (add_accessor.IsStatic || remove_accessor.IsStatic)
5244 if (EventInfo is MyEventBuilder){
5245 MyEventBuilder eb = (MyEventBuilder) EventInfo;
5246 type = eb.EventType;
5249 type = EventInfo.EventHandlerType;
5252 public override string Name {
5254 return EventInfo.Name;
5258 public override bool IsInstance {
5264 public override bool IsStatic {
5270 public override Type DeclaringType {
5272 return EventInfo.DeclaringType;
5276 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
5277 SimpleName original)
5280 // If the event is local to this class, we transform ourselves into a FieldExpr
5283 if (EventInfo.DeclaringType == ec.ContainerType ||
5284 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
5285 EventField mi = TypeManager.GetEventField (EventInfo);
5288 if (!ec.IsInObsoleteScope)
5289 mi.CheckObsoleteness (loc);
5291 FieldExpr ml = new FieldExpr (mi.FieldBuilder, loc);
5293 InstanceExpression = null;
5295 return ml.ResolveMemberAccess (ec, left, loc, original);
5299 return base.ResolveMemberAccess (ec, left, loc, original);
5303 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
5306 InstanceExpression = null;
5310 if (InstanceExpression == null) {
5311 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5315 InstanceExpression = InstanceExpression.DoResolve (ec);
5316 if (InstanceExpression == null)
5319 if (IsBase && add_accessor.IsAbstract) {
5320 Error_CannotCallAbstractBase(TypeManager.CSharpSignature(add_accessor));
5325 // This is using the same mechanism as the CS1540 check in PropertyExpr.
5326 // However, in the Event case, we reported a CS0122 instead.
5328 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
5329 InstanceExpression.Type != ec.ContainerType &&
5330 ec.ContainerType.IsSubclassOf (InstanceExpression.Type)) {
5331 Report.SymbolRelatedToPreviousError (EventInfo);
5332 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5339 public bool IsAccessibleFrom (Type invocation_type)
5342 return IsAccessorAccessible (invocation_type, add_accessor, out dummy) &&
5343 IsAccessorAccessible (invocation_type, remove_accessor, out dummy);
5346 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5348 return DoResolve (ec);
5351 public override Expression DoResolve (EmitContext ec)
5353 bool must_do_cs1540_check;
5354 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
5355 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
5356 Report.SymbolRelatedToPreviousError (EventInfo);
5357 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5361 if (!InstanceResolve (ec, must_do_cs1540_check))
5367 public override void Emit (EmitContext ec)
5369 if (InstanceExpression is This)
5370 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of += or -=", GetSignatureForError ());
5372 Report.Error (70, loc, "The event `{0}' can only appear on the left hand side of += or -= "+
5373 "(except on the defining type)", Name);
5376 public override string GetSignatureForError ()
5378 return TypeManager.CSharpSignature (EventInfo);
5381 public void EmitAddOrRemove (EmitContext ec, Expression source)
5383 BinaryDelegate source_del = source as BinaryDelegate;
5384 if (source_del == null) {
5388 Expression handler = source_del.Right;
5390 Argument arg = new Argument (handler, Argument.AType.Expression);
5391 ArrayList args = new ArrayList ();
5395 if (source_del.IsAddition)
5396 Invocation.EmitCall (
5397 ec, IsBase, InstanceExpression, add_accessor, args, loc);
5399 Invocation.EmitCall (
5400 ec, IsBase, InstanceExpression, remove_accessor, args, loc);
5404 public class TemporaryVariable : Expression, IMemoryLocation
5409 public TemporaryVariable (Type type, Location loc)
5413 eclass = ExprClass.Value;
5416 public override Expression DoResolve (EmitContext ec)
5421 TypeExpr te = new TypeExpression (type, loc);
5422 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
5423 if (!li.Resolve (ec))
5426 if (ec.MustCaptureVariable (li)) {
5427 ScopeInfo scope = li.Block.CreateScopeInfo ();
5428 var = scope.AddLocal (li);
5435 public Variable Variable {
5436 get { return var != null ? var : li.Variable; }
5439 public override void Emit (EmitContext ec)
5441 Variable.EmitInstance (ec);
5445 public void EmitLoadAddress (EmitContext ec)
5447 Variable.EmitInstance (ec);
5448 Variable.EmitAddressOf (ec);
5451 public void Store (EmitContext ec, Expression right_side)
5453 Variable.EmitInstance (ec);
5454 right_side.Emit (ec);
5455 Variable.EmitAssign (ec);
5458 public void EmitThis (EmitContext ec)
5460 Variable.EmitInstance (ec);
5463 public void EmitStore (EmitContext ec)
5465 Variable.EmitAssign (ec);
5468 public void AddressOf (EmitContext ec, AddressOp mode)
5470 EmitLoadAddress (ec);
5475 /// Handles `var' contextual keyword; var becomes a keyword only
5476 /// if no type called var exists in a variable scope
5478 public class VarExpr : SimpleName
5480 // Used for error reporting only
5481 ArrayList initializer;
5483 public VarExpr (string name, Location loc)
5488 public ArrayList VariableInitializer {
5490 this.initializer = value;
5494 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5497 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
5499 type = right_side.Type;
5500 if (type == TypeManager.null_type || type == TypeManager.void_type || type == TypeManager.anonymous_method_type) {
5501 Report.Error (815, loc, "An implicitly typed local variable declaration cannot be initialized with `{0}'",
5502 right_side.GetSignatureForError ());
5506 eclass = ExprClass.Variable;
5510 protected override void Error_TypeOrNamespaceNotFound (IResolveContext ec)
5512 if (ec is FieldBase) {
5513 Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");
5517 base.Error_TypeOrNamespaceNotFound (ec);
5520 public override TypeExpr ResolveAsContextualType (IResolveContext rc, bool silent)
5522 TypeExpr te = base.ResolveAsContextualType (rc, true);
5526 if (initializer == null)
5529 // TODO: refactor, the error is reported too many times
5530 if (initializer.Count > 1) {
5531 Location loc = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [1]).Location;
5532 Report.Error (819, loc, "An implicitly typed local variable declaration cannot include multiple declarators");
5536 Expression variable_initializer = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [0]).expression_or_array_initializer;
5537 if (variable_initializer == null) {
5538 Report.Error (818, loc, "An implicitly typed local variable declarator must include an initializer");