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 // This is used to resolve the expression as a type, a null
233 // value will be returned if the expression is not a type
236 public virtual TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
238 TypeExpr te = ResolveAsBaseTerminal (ec, silent);
242 if (!silent) { // && !(te is TypeParameterExpr)) {
243 ObsoleteAttribute obsolete_attr = AttributeTester.GetObsoleteAttribute (te.Type);
244 if (obsolete_attr != null && !ec.IsInObsoleteScope) {
245 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location);
249 // Constrains don't need to be checked for overrides
250 GenericMethod gm = ec.GenericDeclContainer as GenericMethod;
251 if (gm != null && (gm.ModFlags & Modifiers.OVERRIDE) != 0) {
256 ConstructedType ct = te as ConstructedType;
257 if ((ct != null) && !ct.CheckConstraints (ec))
263 public TypeExpr ResolveAsBaseTerminal (IResolveContext ec, bool silent)
265 int errors = Report.Errors;
267 FullNamedExpression fne = ResolveAsTypeStep (ec, silent);
272 if (fne.eclass != ExprClass.Type) {
273 if (!silent && errors == Report.Errors)
274 fne.Error_UnexpectedKind (null, "type", loc);
278 TypeExpr te = fne as TypeExpr;
280 if (!te.CheckAccessLevel (ec.DeclContainer)) {
281 Report.SymbolRelatedToPreviousError (te.Type);
282 ErrorIsInaccesible (loc, TypeManager.CSharpName (te.Type));
290 public static void ErrorIsInaccesible (Location loc, string name)
292 Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", name);
295 protected static void Error_CannotAccessProtected (Location loc, MemberInfo m, Type qualifier, Type container)
297 Report.Error (1540, loc, "Cannot access protected member `{0}' via a qualifier of type `{1}'."
298 + " The qualifier must be of type `{2}' or derived from it",
299 TypeManager.GetFullNameSignature (m),
300 TypeManager.CSharpName (qualifier),
301 TypeManager.CSharpName (container));
305 public static void Error_InvalidExpressionStatement (Location loc)
307 Report.Error (201, loc, "Only assignment, call, increment, decrement, and new object " +
308 "expressions can be used as a statement");
311 public void Error_InvalidExpressionStatement ()
313 Error_InvalidExpressionStatement (loc);
316 protected void Error_CannotAssign (string to, string roContext)
318 Report.Error (1656, loc, "Cannot assign to `{0}' because it is a `{1}'",
322 public static void Error_VoidInvalidInTheContext (Location loc)
324 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
327 public virtual void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl)
329 if (Type.FullName == target.FullName){
330 Report.ExtraInformation (loc,
332 "The type {0} has two conflicting definitions, one comes from {1} and the other from {2}",
333 Type.FullName, Type.Assembly.FullName, target.Assembly.FullName));
338 Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
339 GetSignatureForError (), TypeManager.CSharpName (target));
343 Expression e = (this is EnumConstant) ? ((EnumConstant)this).Child : this;
344 bool b = Convert.ExplicitNumericConversion (e, target) != null;
347 Convert.ExplicitReferenceConversionExists (Type, target) ||
348 Convert.ExplicitUnsafe (e, target) != null ||
349 (ec != null && Convert.UserDefinedConversion (ec, this, target, Location.Null, true) != null))
351 Report.Error (266, loc, "Cannot implicitly convert type `{0}' to `{1}'. " +
352 "An explicit conversion exists (are you missing a cast?)",
353 TypeManager.CSharpName (Type), TypeManager.CSharpName (target));
357 if (Type != TypeManager.string_type && this is Constant && !(this is EmptyConstantCast)) {
358 Report.Error (31, loc, "Constant value `{0}' cannot be converted to a `{1}'",
359 ((Constant)(this)).GetValue ().ToString (), TypeManager.CSharpName (target));
363 Report.Error (29, loc, "Cannot implicitly convert type {0} to `{1}'",
364 Type == TypeManager.anonymous_method_type ?
365 "anonymous method" : "`" + GetSignatureForError () + "'",
366 TypeManager.CSharpName (target));
369 public static void Error_TypeDoesNotContainDefinition (Location loc, Type type, string name)
371 Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
372 TypeManager.CSharpName (type), name);
375 protected static void Error_ValueAssignment (Location loc)
377 Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
380 ResolveFlags ExprClassToResolveFlags
385 case ExprClass.Namespace:
386 return ResolveFlags.Type;
388 case ExprClass.MethodGroup:
389 return ResolveFlags.MethodGroup;
391 case ExprClass.Value:
392 case ExprClass.Variable:
393 case ExprClass.PropertyAccess:
394 case ExprClass.EventAccess:
395 case ExprClass.IndexerAccess:
396 return ResolveFlags.VariableOrValue;
399 throw new Exception ("Expression " + GetType () +
400 " ExprClass is Invalid after resolve");
406 /// Resolves an expression and performs semantic analysis on it.
410 /// Currently Resolve wraps DoResolve to perform sanity
411 /// checking and assertion checking on what we expect from Resolve.
413 public Expression Resolve (EmitContext ec, ResolveFlags flags)
415 if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type)
416 return ResolveAsTypeStep (ec, false);
418 bool do_flow_analysis = ec.DoFlowAnalysis;
419 bool omit_struct_analysis = ec.OmitStructFlowAnalysis;
420 if ((flags & ResolveFlags.DisableFlowAnalysis) != 0)
421 do_flow_analysis = false;
422 if ((flags & ResolveFlags.DisableStructFlowAnalysis) != 0)
423 omit_struct_analysis = true;
426 using (ec.WithFlowAnalysis (do_flow_analysis, omit_struct_analysis)) {
427 if (this is SimpleName) {
428 bool intermediate = (flags & ResolveFlags.Intermediate) == ResolveFlags.Intermediate;
429 e = ((SimpleName) this).DoResolve (ec, intermediate);
438 if ((flags & e.ExprClassToResolveFlags) == 0) {
439 e.Error_UnexpectedKind (flags, loc);
443 if (e.type == null && !(e is Namespace)) {
444 throw new Exception (
445 "Expression " + e.GetType () +
446 " did not set its type after Resolve\n" +
447 "called from: " + this.GetType ());
454 /// Resolves an expression and performs semantic analysis on it.
456 public Expression Resolve (EmitContext ec)
458 Expression e = Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
460 if (e != null && e.eclass == ExprClass.MethodGroup && RootContext.Version == LanguageVersion.ISO_1) {
461 ((MethodGroupExpr) e).ReportUsageError ();
467 public Constant ResolveAsConstant (EmitContext ec, MemberCore mc)
469 Expression e = Resolve (ec);
473 Constant c = e as Constant;
477 Const.Error_ExpressionMustBeConstant (loc, mc.GetSignatureForError ());
482 /// Resolves an expression for LValue assignment
486 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
487 /// checking and assertion checking on what we expect from Resolve
489 public Expression ResolveLValue (EmitContext ec, Expression right_side, Location loc)
491 int errors = Report.Errors;
492 bool out_access = right_side == EmptyExpression.OutAccess;
494 Expression e = DoResolveLValue (ec, right_side);
496 if (e != null && out_access && !(e is IMemoryLocation)) {
497 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
498 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
500 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
501 // e.GetType () + " " + e.GetSignatureForError ());
506 if (errors == Report.Errors) {
508 Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
510 Error_ValueAssignment (loc);
515 if (e.eclass == ExprClass.Invalid)
516 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
518 if (e.eclass == ExprClass.MethodGroup) {
519 ((MethodGroupExpr) e).ReportUsageError ();
523 if ((e.type == null) && !(e is ConstructedType))
524 throw new Exception ("Expression " + e + " did not set its type after Resolve");
530 /// Emits the code for the expression
534 /// The Emit method is invoked to generate the code
535 /// for the expression.
537 public abstract void Emit (EmitContext ec);
539 public virtual void EmitBranchable (EmitContext ec, Label target, bool onTrue)
542 ec.ig.Emit (onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target);
546 /// Protected constructor. Only derivate types should
547 /// be able to be created
550 protected Expression ()
552 eclass = ExprClass.Invalid;
557 /// Returns a fully formed expression after a MemberLookup
560 public static Expression ExprClassFromMemberInfo (Type containerType, MemberInfo mi, Location loc)
563 return new EventExpr ((EventInfo) mi, loc);
564 else if (mi is FieldInfo)
565 return new FieldExpr ((FieldInfo) mi, loc);
566 else if (mi is PropertyInfo)
567 return new PropertyExpr (containerType, (PropertyInfo) mi, loc);
568 else if (mi is Type){
569 return new TypeExpression ((System.Type) mi, loc);
575 protected static ArrayList almostMatchedMembers = new ArrayList (4);
578 // FIXME: Probably implement a cache for (t,name,current_access_set)?
580 // This code could use some optimizations, but we need to do some
581 // measurements. For example, we could use a delegate to `flag' when
582 // something can not any longer be a method-group (because it is something
586 // If the return value is an Array, then it is an array of
589 // If the return value is an MemberInfo, it is anything, but a Method
593 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
594 // the arguments here and have MemberLookup return only the methods that
595 // match the argument count/type, unlike we are doing now (we delay this
598 // This is so we can catch correctly attempts to invoke instance methods
599 // from a static body (scan for error 120 in ResolveSimpleName).
602 // FIXME: Potential optimization, have a static ArrayList
605 public static Expression MemberLookup (Type container_type, Type queried_type, string name,
606 MemberTypes mt, BindingFlags bf, Location loc)
608 return MemberLookup (container_type, null, queried_type, name, mt, bf, loc);
612 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
613 // `qualifier_type' or null to lookup members in the current class.
616 public static Expression MemberLookup (Type container_type,
617 Type qualifier_type, Type queried_type,
618 string name, MemberTypes mt,
619 BindingFlags bf, Location loc)
621 almostMatchedMembers.Clear ();
623 MemberInfo [] mi = TypeManager.MemberLookup (container_type, qualifier_type,
624 queried_type, mt, bf, name, almostMatchedMembers);
630 bool is_interface = qualifier_type != null && qualifier_type.IsInterface;
631 ArrayList methods = new ArrayList (2);
632 ArrayList non_methods = null;
634 foreach (MemberInfo m in mi) {
635 if (m is MethodBase) {
640 if (non_methods == null) {
641 non_methods = new ArrayList (2);
646 foreach (MemberInfo n_m in non_methods) {
647 if (m.DeclaringType.IsInterface && TypeManager.ImplementsInterface (m.DeclaringType, n_m.DeclaringType))
650 Report.SymbolRelatedToPreviousError (m);
651 Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
652 TypeManager.GetFullNameSignature (m), TypeManager.GetFullNameSignature (n_m));
657 if (methods.Count == 0)
658 return ExprClassFromMemberInfo (container_type, (MemberInfo)non_methods [0], loc);
660 if (non_methods != null) {
661 MethodBase method = (MethodBase) methods [0];
662 MemberInfo non_method = (MemberInfo) non_methods [0];
663 if (method.DeclaringType == non_method.DeclaringType) {
664 // Cannot happen with C# code, but is valid in IL
665 Report.SymbolRelatedToPreviousError (method);
666 Report.SymbolRelatedToPreviousError (non_method);
667 Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
668 TypeManager.GetFullNameSignature (non_method),
669 TypeManager.CSharpSignature (method));
674 Report.SymbolRelatedToPreviousError (method);
675 Report.SymbolRelatedToPreviousError (non_method);
676 Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and non-method `{1}'. Using method `{0}'",
677 TypeManager.CSharpSignature (method), TypeManager.GetFullNameSignature (non_method));
681 return new MethodGroupExpr (methods, loc);
684 if (mi [0] is MethodBase)
685 return new MethodGroupExpr (mi, loc);
687 return ExprClassFromMemberInfo (container_type, mi [0], loc);
690 public const MemberTypes AllMemberTypes =
691 MemberTypes.Constructor |
695 MemberTypes.NestedType |
696 MemberTypes.Property;
698 public const BindingFlags AllBindingFlags =
699 BindingFlags.Public |
700 BindingFlags.Static |
701 BindingFlags.Instance;
703 public static Expression MemberLookup (Type container_type, Type queried_type,
704 string name, Location loc)
706 return MemberLookup (container_type, null, queried_type, name,
707 AllMemberTypes, AllBindingFlags, loc);
710 public static Expression MemberLookup (Type container_type, Type qualifier_type,
711 Type queried_type, string name, Location loc)
713 return MemberLookup (container_type, qualifier_type, queried_type,
714 name, AllMemberTypes, AllBindingFlags, loc);
717 public static MethodGroupExpr MethodLookup (Type container_type, Type queried_type,
718 string name, Location loc)
720 return (MethodGroupExpr)MemberLookup (container_type, null, queried_type, name,
721 MemberTypes.Method, AllBindingFlags, loc);
725 /// This is a wrapper for MemberLookup that is not used to "probe", but
726 /// to find a final definition. If the final definition is not found, we
727 /// look for private members and display a useful debugging message if we
730 public static Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
731 Type queried_type, string name, Location loc)
733 return MemberLookupFinal (ec, qualifier_type, queried_type, name,
734 AllMemberTypes, AllBindingFlags, loc);
737 public static Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
738 Type queried_type, string name,
739 MemberTypes mt, BindingFlags bf,
744 int errors = Report.Errors;
746 e = MemberLookup (ec.ContainerType, qualifier_type, queried_type, name, mt, bf, loc);
748 if (e == null && errors == Report.Errors)
749 // No errors were reported by MemberLookup, but there was an error.
750 MemberLookupFailed (ec.ContainerType, qualifier_type, queried_type, name, null, true, loc);
755 public static void MemberLookupFailed (Type container_type, Type qualifier_type,
756 Type queried_type, string name,
757 string class_name, bool complain_if_none_found,
760 if (almostMatchedMembers.Count != 0) {
761 for (int i = 0; i < almostMatchedMembers.Count; ++i) {
762 MemberInfo m = (MemberInfo) almostMatchedMembers [i];
763 for (int j = 0; j < i; ++j) {
764 if (m == almostMatchedMembers [j]) {
772 Type declaring_type = m.DeclaringType;
774 Report.SymbolRelatedToPreviousError (m);
775 if (qualifier_type == null) {
776 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
777 TypeManager.CSharpName (m.DeclaringType),
778 TypeManager.CSharpName (container_type));
780 } else if (qualifier_type != container_type &&
781 TypeManager.IsNestedFamilyAccessible (container_type, declaring_type)) {
782 // Although a derived class can access protected members of
783 // its base class it cannot do so through an instance of the
784 // base class (CS1540). If the qualifier_type is a base of the
785 // ec.ContainerType and the lookup succeeds with the latter one,
786 // then we are in this situation.
787 Error_CannotAccessProtected (loc, m, qualifier_type, container_type);
789 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (m));
792 almostMatchedMembers.Clear ();
796 MemberInfo[] lookup = null;
797 if (queried_type == null) {
798 class_name = "global::";
800 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
801 AllMemberTypes, AllBindingFlags |
802 BindingFlags.NonPublic, name, null);
805 if (lookup == null) {
806 if (!complain_if_none_found)
809 if (class_name != null)
810 Report.Error (103, loc, "The name `{0}' does not exist in the context of `{1}'",
813 Error_TypeDoesNotContainDefinition (loc, queried_type, name);
817 if (TypeManager.MemberLookup (queried_type, null, queried_type,
818 AllMemberTypes, AllBindingFlags |
819 BindingFlags.NonPublic, name, null) == null) {
820 if ((lookup.Length == 1) && (lookup [0] is Type)) {
821 Type t = (Type) lookup [0];
823 Report.Error (305, loc,
824 "Using the generic type `{0}' " +
825 "requires {1} type arguments",
826 TypeManager.CSharpName (t),
827 TypeManager.GetNumberOfTypeArguments (t).ToString ());
832 MemberList ml = TypeManager.FindMembers (queried_type, MemberTypes.Constructor,
833 BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly, null, null);
834 if (name == ".ctor" && ml.Count == 0)
836 Report.Error (143, loc, "The type `{0}' has no constructors defined", TypeManager.CSharpName (queried_type));
840 Report.SymbolRelatedToPreviousError (lookup [0]);
841 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (lookup [0]));
845 /// Returns an expression that can be used to invoke operator true
846 /// on the expression if it exists.
848 static public Expression GetOperatorTrue (EmitContext ec, Expression e, Location loc)
850 return GetOperatorTrueOrFalse (ec, e, true, loc);
854 /// Returns an expression that can be used to invoke operator false
855 /// on the expression if it exists.
857 static public Expression GetOperatorFalse (EmitContext ec, Expression e, Location loc)
859 return GetOperatorTrueOrFalse (ec, e, false, loc);
862 static Expression GetOperatorTrueOrFalse (EmitContext ec, Expression e, bool is_true, Location loc)
865 Expression operator_group;
868 if (TypeManager.IsNullableType (e.Type))
869 return new Nullable.OperatorTrueOrFalse (e, is_true, loc).Resolve (ec);
872 operator_group = MethodLookup (ec.ContainerType, e.Type, is_true ? "op_True" : "op_False", loc);
873 if (operator_group == null)
876 ArrayList arguments = new ArrayList ();
877 arguments.Add (new Argument (e, Argument.AType.Expression));
878 method = ((MethodGroupExpr) operator_group).OverloadResolve (
879 ec, arguments, false, loc);
884 return new StaticCallExpr ((MethodInfo) method, arguments, loc);
888 /// Resolves the expression `e' into a boolean expression: either through
889 /// an implicit conversion, or through an `operator true' invocation
891 public static Expression ResolveBoolean (EmitContext ec, Expression e, Location loc)
897 if (e.Type == TypeManager.bool_type)
900 Expression converted = Convert.ImplicitConversion (ec, e, TypeManager.bool_type, Location.Null);
902 if (converted != null)
906 // If no implicit conversion to bool exists, try using `operator true'
908 converted = Expression.GetOperatorTrue (ec, e, loc);
909 if (converted == null){
910 e.Error_ValueCannotBeConverted (ec, loc, TypeManager.bool_type, false);
916 public virtual string ExprClassName
920 case ExprClass.Invalid:
922 case ExprClass.Value:
924 case ExprClass.Variable:
926 case ExprClass.Namespace:
930 case ExprClass.MethodGroup:
931 return "method group";
932 case ExprClass.PropertyAccess:
933 return "property access";
934 case ExprClass.EventAccess:
935 return "event access";
936 case ExprClass.IndexerAccess:
937 return "indexer access";
938 case ExprClass.Nothing:
941 throw new Exception ("Should not happen");
946 /// Reports that we were expecting `expr' to be of class `expected'
948 public void Error_UnexpectedKind (DeclSpace ds, string expected, Location loc)
950 Error_UnexpectedKind (ds, expected, ExprClassName, loc);
953 public void Error_UnexpectedKind (DeclSpace ds, string expected, string was, Location loc)
955 string name = GetSignatureForError ();
957 name = ds.GetSignatureForError () + '.' + name;
959 Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
960 name, was, expected);
963 public void Error_UnexpectedKind (ResolveFlags flags, Location loc)
965 string [] valid = new string [4];
968 if ((flags & ResolveFlags.VariableOrValue) != 0) {
969 valid [count++] = "variable";
970 valid [count++] = "value";
973 if ((flags & ResolveFlags.Type) != 0)
974 valid [count++] = "type";
976 if ((flags & ResolveFlags.MethodGroup) != 0)
977 valid [count++] = "method group";
980 valid [count++] = "unknown";
982 StringBuilder sb = new StringBuilder (valid [0]);
983 for (int i = 1; i < count - 1; i++) {
985 sb.Append (valid [i]);
988 sb.Append ("' or `");
989 sb.Append (valid [count - 1]);
992 Report.Error (119, loc,
993 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
996 public static void UnsafeError (Location loc)
998 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1002 // Load the object from the pointer.
1004 public static void LoadFromPtr (ILGenerator ig, Type t)
1006 if (t == TypeManager.int32_type)
1007 ig.Emit (OpCodes.Ldind_I4);
1008 else if (t == TypeManager.uint32_type)
1009 ig.Emit (OpCodes.Ldind_U4);
1010 else if (t == TypeManager.short_type)
1011 ig.Emit (OpCodes.Ldind_I2);
1012 else if (t == TypeManager.ushort_type)
1013 ig.Emit (OpCodes.Ldind_U2);
1014 else if (t == TypeManager.char_type)
1015 ig.Emit (OpCodes.Ldind_U2);
1016 else if (t == TypeManager.byte_type)
1017 ig.Emit (OpCodes.Ldind_U1);
1018 else if (t == TypeManager.sbyte_type)
1019 ig.Emit (OpCodes.Ldind_I1);
1020 else if (t == TypeManager.uint64_type)
1021 ig.Emit (OpCodes.Ldind_I8);
1022 else if (t == TypeManager.int64_type)
1023 ig.Emit (OpCodes.Ldind_I8);
1024 else if (t == TypeManager.float_type)
1025 ig.Emit (OpCodes.Ldind_R4);
1026 else if (t == TypeManager.double_type)
1027 ig.Emit (OpCodes.Ldind_R8);
1028 else if (t == TypeManager.bool_type)
1029 ig.Emit (OpCodes.Ldind_I1);
1030 else if (t == TypeManager.intptr_type)
1031 ig.Emit (OpCodes.Ldind_I);
1032 else if (TypeManager.IsEnumType (t)) {
1033 if (t == TypeManager.enum_type)
1034 ig.Emit (OpCodes.Ldind_Ref);
1036 LoadFromPtr (ig, TypeManager.EnumToUnderlying (t));
1037 } else if (t.IsValueType || TypeManager.IsGenericParameter (t))
1038 ig.Emit (OpCodes.Ldobj, t);
1039 else if (t.IsPointer)
1040 ig.Emit (OpCodes.Ldind_I);
1042 ig.Emit (OpCodes.Ldind_Ref);
1046 // The stack contains the pointer and the value of type `type'
1048 public static void StoreFromPtr (ILGenerator ig, Type type)
1050 if (TypeManager.IsEnumType (type))
1051 type = TypeManager.EnumToUnderlying (type);
1052 if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
1053 ig.Emit (OpCodes.Stind_I4);
1054 else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
1055 ig.Emit (OpCodes.Stind_I8);
1056 else if (type == TypeManager.char_type || type == TypeManager.short_type ||
1057 type == TypeManager.ushort_type)
1058 ig.Emit (OpCodes.Stind_I2);
1059 else if (type == TypeManager.float_type)
1060 ig.Emit (OpCodes.Stind_R4);
1061 else if (type == TypeManager.double_type)
1062 ig.Emit (OpCodes.Stind_R8);
1063 else if (type == TypeManager.byte_type || type == TypeManager.sbyte_type ||
1064 type == TypeManager.bool_type)
1065 ig.Emit (OpCodes.Stind_I1);
1066 else if (type == TypeManager.intptr_type)
1067 ig.Emit (OpCodes.Stind_I);
1068 else if (type.IsValueType || TypeManager.IsGenericParameter (type))
1069 ig.Emit (OpCodes.Stobj, type);
1071 ig.Emit (OpCodes.Stind_Ref);
1075 // Returns the size of type `t' if known, otherwise, 0
1077 public static int GetTypeSize (Type t)
1079 t = TypeManager.TypeToCoreType (t);
1080 if (t == TypeManager.int32_type ||
1081 t == TypeManager.uint32_type ||
1082 t == TypeManager.float_type)
1084 else if (t == TypeManager.int64_type ||
1085 t == TypeManager.uint64_type ||
1086 t == TypeManager.double_type)
1088 else if (t == TypeManager.byte_type ||
1089 t == TypeManager.sbyte_type ||
1090 t == TypeManager.bool_type)
1092 else if (t == TypeManager.short_type ||
1093 t == TypeManager.char_type ||
1094 t == TypeManager.ushort_type)
1096 else if (t == TypeManager.decimal_type)
1102 public static void Error_NegativeArrayIndex (Location loc)
1104 Report.Error (248, loc, "Cannot create an array with a negative size");
1107 protected void Error_CannotCallAbstractBase (string name)
1109 Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
1113 // Converts `source' to an int, uint, long or ulong.
1115 public Expression ExpressionToArrayArgument (EmitContext ec, Expression source, Location loc)
1119 using (ec.With (EmitContext.Flags.CheckState, true)) {
1120 target = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, loc);
1122 target = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, loc);
1124 target = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, loc);
1126 target = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, loc);
1128 if (target == null) {
1129 source.Error_ValueCannotBeConverted (ec, loc, TypeManager.int32_type, false);
1135 // Only positive constants are allowed at compile time
1137 if (target is Constant){
1138 if (target is IntConstant){
1139 if (((IntConstant) target).Value < 0){
1140 Error_NegativeArrayIndex (loc);
1145 if (target is LongConstant){
1146 if (((LongConstant) target).Value < 0){
1147 Error_NegativeArrayIndex (loc);
1158 // Derived classes implement this method by cloning the fields that
1159 // could become altered during the Resolve stage
1161 // Only expressions that are created for the parser need to implement
1164 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1166 throw new NotImplementedException (
1168 "CloneTo not implemented for expression {0}", this.GetType ()));
1172 // Clones an expression created by the parser.
1174 // We only support expressions created by the parser so far, not
1175 // expressions that have been resolved (many more classes would need
1176 // to implement CloneTo).
1178 // This infrastructure is here merely for Lambda expressions which
1179 // compile the same code using different type values for the same
1180 // arguments to find the correct overload
1182 public Expression Clone (CloneContext clonectx)
1184 Expression cloned = (Expression) MemberwiseClone ();
1185 CloneTo (clonectx, cloned);
1192 /// This is just a base class for expressions that can
1193 /// appear on statements (invocations, object creation,
1194 /// assignments, post/pre increment and decrement). The idea
1195 /// being that they would support an extra Emition interface that
1196 /// does not leave a result on the stack.
1198 public abstract class ExpressionStatement : Expression {
1200 public virtual ExpressionStatement ResolveStatement (EmitContext ec)
1202 Expression e = Resolve (ec);
1206 ExpressionStatement es = e as ExpressionStatement;
1208 Error_InvalidExpressionStatement ();
1214 /// Requests the expression to be emitted in a `statement'
1215 /// context. This means that no new value is left on the
1216 /// stack after invoking this method (constrasted with
1217 /// Emit that will always leave a value on the stack).
1219 public abstract void EmitStatement (EmitContext ec);
1223 /// This kind of cast is used to encapsulate the child
1224 /// whose type is child.Type into an expression that is
1225 /// reported to return "return_type". This is used to encapsulate
1226 /// expressions which have compatible types, but need to be dealt
1227 /// at higher levels with.
1229 /// For example, a "byte" expression could be encapsulated in one
1230 /// of these as an "unsigned int". The type for the expression
1231 /// would be "unsigned int".
1234 public class EmptyCast : Expression {
1235 protected Expression child;
1237 public EmptyCast (Expression child, Type return_type)
1239 eclass = child.eclass;
1240 loc = child.Location;
1245 public override Expression DoResolve (EmitContext ec)
1247 // This should never be invoked, we are born in fully
1248 // initialized state.
1253 public override void Emit (EmitContext ec)
1258 public override bool GetAttributableValue (Type valueType, out object value)
1260 return child.GetAttributableValue (valueType, out value);
1263 protected override void CloneTo (CloneContext clonectx, Expression t)
1265 EmptyCast target = (EmptyCast) t;
1267 target.child = child.Clone (clonectx);
1272 /// Performs a cast using an operator (op_Explicit or op_Implicit)
1274 public class OperatorCast : EmptyCast {
1275 MethodInfo conversion_operator;
1278 public OperatorCast (Expression child, Type target_type) : this (child, target_type, false) {}
1280 public OperatorCast (Expression child, Type target_type, bool find_explicit)
1281 : base (child, target_type)
1283 this.find_explicit = find_explicit;
1286 // Returns the implicit operator that converts from
1287 // 'child.Type' to our target type (type)
1288 MethodInfo GetConversionOperator (bool find_explicit)
1290 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1294 mi = TypeManager.MemberLookup (child.Type, child.Type, child.Type, MemberTypes.Method,
1295 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1298 mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1299 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1302 foreach (MethodInfo oper in mi) {
1303 ParameterData pd = TypeManager.GetParameterData (oper);
1305 if (pd.ParameterType (0) == child.Type && oper.ReturnType == type)
1313 public override void Emit (EmitContext ec)
1315 ILGenerator ig = ec.ig;
1318 conversion_operator = GetConversionOperator (find_explicit);
1320 if (conversion_operator == null)
1321 throw new InternalErrorException ("Outer conversion routine is out of sync");
1323 ig.Emit (OpCodes.Call, conversion_operator);
1329 /// This is a numeric cast to a Decimal
1331 public class CastToDecimal : EmptyCast {
1332 MethodInfo conversion_operator;
1334 public CastToDecimal (Expression child)
1335 : this (child, false)
1339 public CastToDecimal (Expression child, bool find_explicit)
1340 : base (child, TypeManager.decimal_type)
1342 conversion_operator = GetConversionOperator (find_explicit);
1344 if (conversion_operator == null)
1345 throw new InternalErrorException ("Outer conversion routine is out of sync");
1348 // Returns the implicit operator that converts from
1349 // 'child.Type' to System.Decimal.
1350 MethodInfo GetConversionOperator (bool find_explicit)
1352 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1354 MemberInfo [] mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1355 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1357 foreach (MethodInfo oper in mi) {
1358 ParameterData pd = TypeManager.GetParameterData (oper);
1360 if (pd.ParameterType (0) == child.Type && oper.ReturnType == type)
1366 public override void Emit (EmitContext ec)
1368 ILGenerator ig = ec.ig;
1371 ig.Emit (OpCodes.Call, conversion_operator);
1376 /// This is an explicit numeric cast from a Decimal
1378 public class CastFromDecimal : EmptyCast
1380 static IDictionary operators;
1382 public CastFromDecimal (Expression child, Type return_type)
1383 : base (child, return_type)
1385 if (child.Type != TypeManager.decimal_type)
1386 throw new InternalErrorException (
1387 "The expected type is Decimal, instead it is " + child.Type.FullName);
1390 // Returns the explicit operator that converts from an
1391 // express of type System.Decimal to 'type'.
1392 public Expression Resolve ()
1394 if (operators == null) {
1395 MemberInfo[] all_oper = TypeManager.MemberLookup (TypeManager.decimal_type,
1396 TypeManager.decimal_type, TypeManager.decimal_type, MemberTypes.Method,
1397 BindingFlags.Static | BindingFlags.Public, "op_Explicit", null);
1399 operators = new System.Collections.Specialized.HybridDictionary ();
1400 foreach (MethodInfo oper in all_oper) {
1401 ParameterData pd = TypeManager.GetParameterData (oper);
1402 if (pd.ParameterType (0) == TypeManager.decimal_type)
1403 operators.Add (oper.ReturnType, oper);
1407 return operators.Contains (type) ? this : null;
1410 public override void Emit (EmitContext ec)
1412 ILGenerator ig = ec.ig;
1415 ig.Emit (OpCodes.Call, (MethodInfo)operators [type]);
1421 // Constant specialization of EmptyCast.
1422 // We need to special case this since an empty cast of
1423 // a constant is still a constant.
1425 public class EmptyConstantCast : Constant
1427 public readonly Constant child;
1429 public EmptyConstantCast(Constant child, Type type)
1430 : base (child.Location)
1432 eclass = child.eclass;
1437 public override string AsString ()
1439 return child.AsString ();
1442 public override object GetValue ()
1444 return child.GetValue ();
1447 public override Constant ConvertExplicitly (bool inCheckedContext, Type target_type)
1449 // FIXME: check that 'type' can be converted to 'target_type' first
1450 return child.ConvertExplicitly (inCheckedContext, target_type);
1453 public override Constant Increment ()
1455 return child.Increment ();
1458 public override bool IsDefaultValue {
1459 get { return child.IsDefaultValue; }
1462 public override bool IsNegative {
1463 get { return child.IsNegative; }
1466 public override void Emit (EmitContext ec)
1471 public override Constant ConvertImplicitly (Type target_type)
1473 // FIXME: Do we need to check user conversions?
1474 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1476 return child.ConvertImplicitly (target_type);
1482 /// This class is used to wrap literals which belong inside Enums
1484 public class EnumConstant : Constant {
1485 public Constant Child;
1487 public EnumConstant (Constant child, Type enum_type):
1488 base (child.Location)
1490 eclass = child.eclass;
1495 public override Expression DoResolve (EmitContext ec)
1497 // This should never be invoked, we are born in fully
1498 // initialized state.
1503 public override void Emit (EmitContext ec)
1508 public override bool GetAttributableValue (Type valueType, out object value)
1510 value = GetTypedValue ();
1514 public override string GetSignatureForError()
1516 return TypeManager.CSharpName (Type);
1519 public override object GetValue ()
1521 return Child.GetValue ();
1524 public override object GetTypedValue ()
1526 // FIXME: runtime is not ready to work with just emited enums
1527 if (!RootContext.StdLib) {
1528 return Child.GetValue ();
1531 return System.Enum.ToObject (type, Child.GetValue ());
1534 public override string AsString ()
1536 return TypeManager.CSharpEnumValue (type, Child.GetValue ());
1539 public override Constant Increment()
1541 return new EnumConstant (Child.Increment (), type);
1544 public override bool IsDefaultValue {
1546 return Child.IsDefaultValue;
1550 public override bool IsZeroInteger {
1551 get { return Child.IsZeroInteger; }
1554 public override bool IsNegative {
1556 return Child.IsNegative;
1560 public override Constant ConvertExplicitly(bool inCheckedContext, Type target_type)
1562 if (Child.Type == target_type)
1565 return Child.ConvertExplicitly (inCheckedContext, target_type);
1568 public override Constant ConvertImplicitly (Type type)
1570 Type this_type = TypeManager.DropGenericTypeArguments (Type);
1571 type = TypeManager.DropGenericTypeArguments (type);
1573 if (this_type == type) {
1574 // This is workaround of mono bug. It can be removed when the latest corlib spreads enough
1575 if (TypeManager.IsEnumType (type.UnderlyingSystemType))
1578 Type child_type = TypeManager.DropGenericTypeArguments (Child.Type);
1579 if (type.UnderlyingSystemType != child_type)
1580 Child = Child.ConvertImplicitly (type.UnderlyingSystemType);
1584 if (!Convert.ImplicitStandardConversionExists (this, type)){
1588 return Child.ConvertImplicitly(type);
1594 /// This kind of cast is used to encapsulate Value Types in objects.
1596 /// The effect of it is to box the value type emitted by the previous
1599 public class BoxedCast : EmptyCast {
1601 public BoxedCast (Expression expr, Type target_type)
1602 : base (expr, target_type)
1604 eclass = ExprClass.Value;
1607 public override Expression DoResolve (EmitContext ec)
1609 // This should never be invoked, we are born in fully
1610 // initialized state.
1615 public override void Emit (EmitContext ec)
1619 ec.ig.Emit (OpCodes.Box, child.Type);
1623 public class UnboxCast : EmptyCast {
1624 public UnboxCast (Expression expr, Type return_type)
1625 : base (expr, return_type)
1629 public override Expression DoResolve (EmitContext ec)
1631 // This should never be invoked, we are born in fully
1632 // initialized state.
1637 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1639 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
1640 Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
1641 return base.DoResolveLValue (ec, right_side);
1644 public override void Emit (EmitContext ec)
1647 ILGenerator ig = ec.ig;
1651 if (t.IsGenericParameter || t.IsGenericType && t.IsValueType)
1652 ig.Emit (OpCodes.Unbox_Any, t);
1656 ig.Emit (OpCodes.Unbox, t);
1658 LoadFromPtr (ig, t);
1664 /// This is used to perform explicit numeric conversions.
1666 /// Explicit numeric conversions might trigger exceptions in a checked
1667 /// context, so they should generate the conv.ovf opcodes instead of
1670 public class ConvCast : EmptyCast {
1671 public enum Mode : byte {
1672 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1674 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1675 U2_I1, U2_U1, U2_I2, U2_CH,
1676 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1677 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1678 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH,
1679 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH,
1680 CH_I1, CH_U1, CH_I2,
1681 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1682 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4
1687 public ConvCast (Expression child, Type return_type, Mode m)
1688 : base (child, return_type)
1693 public override Expression DoResolve (EmitContext ec)
1695 // This should never be invoked, we are born in fully
1696 // initialized state.
1701 public override string ToString ()
1703 return String.Format ("ConvCast ({0}, {1})", mode, child);
1706 public override void Emit (EmitContext ec)
1708 ILGenerator ig = ec.ig;
1714 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1715 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1716 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1717 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1718 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1720 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1721 case Mode.U1_CH: /* nothing */ break;
1723 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1724 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1725 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1726 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1727 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1728 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1730 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1731 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1732 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1733 case Mode.U2_CH: /* nothing */ break;
1735 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1736 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1737 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1738 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1739 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1740 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1741 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1743 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1744 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1745 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1746 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1747 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1748 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1750 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1751 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1752 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1753 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1754 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1755 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1756 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1757 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1759 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1760 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1761 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1762 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1763 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1764 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1765 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1766 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1768 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1769 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1770 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1772 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1773 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1774 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1775 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1776 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1777 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1778 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1779 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1780 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1782 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1783 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1784 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1785 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1786 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1787 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1788 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1789 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1790 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1791 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1795 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
1796 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
1797 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
1798 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
1799 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
1801 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
1802 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
1804 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
1805 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
1806 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
1807 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
1808 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
1809 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
1811 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
1812 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
1813 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
1814 case Mode.U2_CH: /* nothing */ break;
1816 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
1817 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
1818 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
1819 case Mode.I4_U4: /* nothing */ break;
1820 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
1821 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
1822 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
1824 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
1825 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
1826 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
1827 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
1828 case Mode.U4_I4: /* nothing */ break;
1829 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
1831 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
1832 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
1833 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
1834 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
1835 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
1836 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
1837 case Mode.I8_U8: /* nothing */ break;
1838 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
1840 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
1841 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
1842 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
1843 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
1844 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
1845 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
1846 case Mode.U8_I8: /* nothing */ break;
1847 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
1849 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
1850 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
1851 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
1853 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
1854 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
1855 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
1856 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
1857 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
1858 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
1859 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
1860 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
1861 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
1863 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
1864 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
1865 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
1866 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
1867 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
1868 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
1869 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
1870 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
1871 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
1872 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1878 public class OpcodeCast : EmptyCast {
1882 public OpcodeCast (Expression child, Type return_type, OpCode op)
1883 : base (child, return_type)
1887 second_valid = false;
1890 public OpcodeCast (Expression child, Type return_type, OpCode op, OpCode op2)
1891 : base (child, return_type)
1896 second_valid = true;
1899 public override Expression DoResolve (EmitContext ec)
1901 // This should never be invoked, we are born in fully
1902 // initialized state.
1907 public override void Emit (EmitContext ec)
1918 /// This kind of cast is used to encapsulate a child and cast it
1919 /// to the class requested
1921 public class ClassCast : EmptyCast {
1922 public ClassCast (Expression child, Type return_type)
1923 : base (child, return_type)
1928 public override Expression DoResolve (EmitContext ec)
1930 // This should never be invoked, we are born in fully
1931 // initialized state.
1936 public override void Emit (EmitContext ec)
1940 if (TypeManager.IsGenericParameter (child.Type))
1941 ec.ig.Emit (OpCodes.Box, child.Type);
1944 if (type.IsGenericParameter)
1945 ec.ig.Emit (OpCodes.Unbox_Any, type);
1948 ec.ig.Emit (OpCodes.Castclass, type);
1953 /// SimpleName expressions are formed of a single word and only happen at the beginning
1954 /// of a dotted-name.
1956 public class SimpleName : Expression {
1958 public readonly TypeArguments Arguments;
1961 public SimpleName (string name, Location l)
1967 public SimpleName (string name, TypeArguments args, Location l)
1974 public SimpleName (string name, TypeParameter[] type_params, Location l)
1979 Arguments = new TypeArguments (l);
1980 foreach (TypeParameter type_param in type_params)
1981 Arguments.Add (new TypeParameterExpr (type_param, l));
1984 public static string RemoveGenericArity (string name)
1987 StringBuilder sb = null;
1989 int pos = name.IndexOf ('`', start);
1994 sb.Append (name.Substring (start));
1999 sb = new StringBuilder ();
2000 sb.Append (name.Substring (start, pos-start));
2003 while ((pos < name.Length) && Char.IsNumber (name [pos]))
2007 } while (start < name.Length);
2009 return sb.ToString ();
2012 public SimpleName GetMethodGroup ()
2014 return new SimpleName (RemoveGenericArity (Name), Arguments, loc);
2017 public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
2019 if (ec.IsFieldInitializer)
2020 Report.Error (236, l,
2021 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2025 120, l, "`{0}': An object reference is required for the nonstatic field, method or property",
2029 public bool IdenticalNameAndTypeName (EmitContext ec, Expression resolved_to, Location loc)
2031 return resolved_to != null && resolved_to.Type != null &&
2032 resolved_to.Type.Name == Name &&
2033 (ec.DeclContainer.LookupNamespaceOrType (Name, loc, /* ignore_cs0104 = */ true) != null);
2036 public override Expression DoResolve (EmitContext ec)
2038 return SimpleNameResolve (ec, null, false);
2041 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
2043 return SimpleNameResolve (ec, right_side, false);
2047 public Expression DoResolve (EmitContext ec, bool intermediate)
2049 return SimpleNameResolve (ec, null, intermediate);
2052 private bool IsNestedChild (Type t, Type parent)
2057 while (parent != null) {
2058 parent = TypeManager.DropGenericTypeArguments (parent);
2059 if (TypeManager.IsNestedChildOf (t, parent))
2062 parent = parent.BaseType;
2068 FullNamedExpression ResolveNested (IResolveContext ec, Type t)
2070 if (!TypeManager.IsGenericTypeDefinition (t))
2073 DeclSpace ds = ec.DeclContainer;
2074 while (ds != null) {
2075 if (IsNestedChild (t, ds.TypeBuilder))
2084 Type[] gen_params = TypeManager.GetTypeArguments (t);
2086 int arg_count = Arguments != null ? Arguments.Count : 0;
2088 for (; (ds != null) && ds.IsGeneric; ds = ds.Parent) {
2089 if (arg_count + ds.CountTypeParameters == gen_params.Length) {
2090 TypeArguments new_args = new TypeArguments (loc);
2091 foreach (TypeParameter param in ds.TypeParameters)
2092 new_args.Add (new TypeParameterExpr (param, loc));
2094 if (Arguments != null)
2095 new_args.Add (Arguments);
2097 return new ConstructedType (t, new_args, loc);
2104 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2106 FullNamedExpression fne = ec.GenericDeclContainer.LookupGeneric (Name, loc);
2108 return fne.ResolveAsTypeStep (ec, silent);
2110 int errors = Report.Errors;
2111 fne = ec.DeclContainer.LookupNamespaceOrType (Name, loc, /*ignore_cs0104=*/ false);
2114 if (fne.Type == null)
2117 FullNamedExpression nested = ResolveNested (ec, fne.Type);
2119 return nested.ResolveAsTypeStep (ec, false);
2121 if (Arguments != null) {
2122 ConstructedType ct = new ConstructedType (fne, Arguments, loc);
2123 return ct.ResolveAsTypeStep (ec, false);
2129 if (silent || errors != Report.Errors)
2132 MemberCore mc = ec.DeclContainer.GetDefinition (Name);
2134 Error_UnexpectedKind (ec.DeclContainer, "type", GetMemberType (mc), loc);
2138 string ns = ec.DeclContainer.NamespaceEntry.NS.Name;
2139 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2140 foreach (Assembly a in RootNamespace.Global.Assemblies) {
2141 Type type = a.GetType (fullname);
2143 Report.SymbolRelatedToPreviousError (type);
2144 Expression.ErrorIsInaccesible (loc, fullname);
2149 Type t = ec.DeclContainer.LookupAnyGeneric (Name);
2151 Namespace.Error_InvalidNumberOfTypeArguments (t, loc);
2155 NamespaceEntry.Error_NamespaceNotFound (loc, Name);
2159 // TODO: I am still not convinced about this. If someone else will need it
2160 // implement this as virtual property in MemberCore hierarchy
2161 public static string GetMemberType (MemberCore mc)
2167 if (mc is FieldBase)
2169 if (mc is MethodCore)
2171 if (mc is EnumMember)
2179 Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2185 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2189 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2196 /// 7.5.2: Simple Names.
2198 /// Local Variables and Parameters are handled at
2199 /// parse time, so they never occur as SimpleNames.
2201 /// The `intermediate' flag is used by MemberAccess only
2202 /// and it is used to inform us that it is ok for us to
2203 /// avoid the static check, because MemberAccess might end
2204 /// up resolving the Name as a Type name and the access as
2205 /// a static type access.
2207 /// ie: Type Type; .... { Type.GetType (""); }
2209 /// Type is both an instance variable and a Type; Type.GetType
2210 /// is the static method not an instance method of type.
2212 Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2214 Expression e = null;
2217 // Stage 1: Performed by the parser (binding to locals or parameters).
2219 Block current_block = ec.CurrentBlock;
2220 if (current_block != null){
2221 LocalInfo vi = current_block.GetLocalInfo (Name);
2223 if (Arguments != null) {
2224 Report.Error (307, loc,
2225 "The variable `{0}' cannot be used with type arguments",
2230 LocalVariableReference var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2231 if (right_side != null) {
2232 return var.ResolveLValue (ec, right_side, loc);
2234 ResolveFlags rf = ResolveFlags.VariableOrValue;
2236 rf |= ResolveFlags.DisableFlowAnalysis;
2237 return var.Resolve (ec, rf);
2241 ParameterReference pref = current_block.Toplevel.GetParameterReference (Name, loc);
2243 if (Arguments != null) {
2244 Report.Error (307, loc,
2245 "The variable `{0}' cannot be used with type arguments",
2250 if (right_side != null)
2251 return pref.ResolveLValue (ec, right_side, loc);
2253 return pref.Resolve (ec);
2258 // Stage 2: Lookup members
2261 DeclSpace lookup_ds = ec.DeclContainer;
2262 Type almost_matched_type = null;
2263 ArrayList almost_matched = null;
2265 if (lookup_ds.TypeBuilder == null)
2268 e = MemberLookup (ec.ContainerType, lookup_ds.TypeBuilder, Name, loc);
2272 if (almost_matched == null && almostMatchedMembers.Count > 0) {
2273 almost_matched_type = lookup_ds.TypeBuilder;
2274 almost_matched = (ArrayList) almostMatchedMembers.Clone ();
2277 lookup_ds =lookup_ds.Parent;
2278 } while (lookup_ds != null);
2280 if (e == null && ec.ContainerType != null)
2281 e = MemberLookup (ec.ContainerType, ec.ContainerType, Name, loc);
2284 if (almost_matched == null && almostMatchedMembers.Count > 0) {
2285 almost_matched_type = ec.ContainerType;
2286 almost_matched = (ArrayList) almostMatchedMembers.Clone ();
2288 e = ResolveAsTypeStep (ec, true);
2292 if (almost_matched != null)
2293 almostMatchedMembers = almost_matched;
2294 if (almost_matched_type == null)
2295 almost_matched_type = ec.ContainerType;
2296 MemberLookupFailed (ec.ContainerType, null, almost_matched_type, ((SimpleName) this).Name, ec.DeclContainer.Name, true, loc);
2300 if (e is TypeExpr) {
2301 if (Arguments == null)
2304 ConstructedType ct = new ConstructedType (
2305 (FullNamedExpression) e, Arguments, loc);
2306 return ct.ResolveAsTypeStep (ec, false);
2309 if (e is MemberExpr) {
2310 MemberExpr me = (MemberExpr) e;
2313 if (me.IsInstance) {
2314 if (ec.IsStatic || ec.IsFieldInitializer) {
2316 // Note that an MemberExpr can be both IsInstance and IsStatic.
2317 // An unresolved MethodGroupExpr can contain both kinds of methods
2318 // and each predicate is true if the MethodGroupExpr contains
2319 // at least one of that kind of method.
2323 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2324 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2325 return EmptyExpression.Null;
2329 // Pass the buck to MemberAccess and Invocation.
2331 left = EmptyExpression.Null;
2333 left = ec.GetThis (loc);
2336 left = new TypeExpression (ec.ContainerType, loc);
2339 e = me.ResolveMemberAccess (ec, left, loc, null);
2343 me = e as MemberExpr;
2347 if (Arguments != null) {
2348 MethodGroupExpr mg = me as MethodGroupExpr;
2352 return mg.ResolveGeneric (ec, Arguments);
2355 if (!me.IsStatic && (me.InstanceExpression != null) &&
2356 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2357 me.InstanceExpression.Type != me.DeclaringType &&
2358 !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2359 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2360 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2361 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2365 return (right_side != null)
2366 ? me.DoResolveLValue (ec, right_side)
2367 : me.DoResolve (ec);
2373 public override void Emit (EmitContext ec)
2376 // If this is ever reached, then we failed to
2377 // find the name as a namespace
2380 Error (103, "The name `" + Name +
2381 "' does not exist in the class `" +
2382 ec.DeclContainer.Name + "'");
2385 public override string ToString ()
2390 public override string GetSignatureForError ()
2395 protected override void CloneTo (CloneContext clonectx, Expression target)
2397 // CloneTo: Nothing, we do not keep any state on this expression
2402 /// Represents a namespace or a type. The name of the class was inspired by
2403 /// section 10.8.1 (Fully Qualified Names).
2405 public abstract class FullNamedExpression : Expression {
2406 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2411 public abstract string FullName {
2417 /// Expression that evaluates to a type
2419 public abstract class TypeExpr : FullNamedExpression {
2420 override public FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2422 TypeExpr t = DoResolveAsTypeStep (ec);
2426 eclass = ExprClass.Type;
2430 override public Expression DoResolve (EmitContext ec)
2432 return ResolveAsTypeTerminal (ec, false);
2435 override public void Emit (EmitContext ec)
2437 throw new Exception ("Should never be called");
2440 public virtual bool CheckAccessLevel (DeclSpace ds)
2442 return ds.CheckAccessLevel (Type);
2445 public virtual bool AsAccessible (DeclSpace ds, int flags)
2447 return ds.AsAccessible (Type, flags);
2450 public virtual bool IsClass {
2451 get { return Type.IsClass; }
2454 public virtual bool IsValueType {
2455 get { return Type.IsValueType; }
2458 public virtual bool IsInterface {
2459 get { return Type.IsInterface; }
2462 public virtual bool IsSealed {
2463 get { return Type.IsSealed; }
2466 public virtual bool CanInheritFrom ()
2468 if (Type == TypeManager.enum_type ||
2469 (Type == TypeManager.value_type && RootContext.StdLib) ||
2470 Type == TypeManager.multicast_delegate_type ||
2471 Type == TypeManager.delegate_type ||
2472 Type == TypeManager.array_type)
2478 protected abstract TypeExpr DoResolveAsTypeStep (IResolveContext ec);
2480 public abstract string Name {
2484 public override bool Equals (object obj)
2486 TypeExpr tobj = obj as TypeExpr;
2490 return Type == tobj.Type;
2493 public override int GetHashCode ()
2495 return Type.GetHashCode ();
2498 public override string ToString ()
2505 /// Fully resolved Expression that already evaluated to a type
2507 public class TypeExpression : TypeExpr {
2508 public TypeExpression (Type t, Location l)
2511 eclass = ExprClass.Type;
2515 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2520 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2525 public override string Name {
2526 get { return Type.ToString (); }
2529 public override string FullName {
2530 get { return Type.FullName; }
2535 /// Used to create types from a fully qualified name. These are just used
2536 /// by the parser to setup the core types. A TypeLookupExpression is always
2537 /// classified as a type.
2539 public sealed class TypeLookupExpression : TypeExpr {
2540 readonly string name;
2542 public TypeLookupExpression (string name)
2545 eclass = ExprClass.Type;
2548 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2550 // It's null for corlib compilation only
2552 return DoResolveAsTypeStep (ec);
2557 static readonly char [] dot_array = { '.' };
2558 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2560 // If name is of the form `N.I', first lookup `N', then search a member `I' in it.
2562 string lookup_name = name;
2563 int pos = name.IndexOf ('.');
2565 rest = name.Substring (pos + 1);
2566 lookup_name = name.Substring (0, pos);
2569 FullNamedExpression resolved = RootNamespace.Global.Lookup (ec.DeclContainer, lookup_name, Location.Null);
2571 if (resolved != null && rest != null) {
2572 // Now handle the rest of the the name.
2573 string [] elements = rest.Split (dot_array);
2575 int count = elements.Length;
2577 while (i < count && resolved != null && resolved is Namespace) {
2578 Namespace ns = resolved as Namespace;
2579 element = elements [i++];
2580 lookup_name += "." + element;
2581 resolved = ns.Lookup (ec.DeclContainer, element, Location.Null);
2584 if (resolved != null && resolved is TypeExpr) {
2585 Type t = ((TypeExpr) resolved).Type;
2587 if (!ec.DeclContainer.CheckAccessLevel (t)) {
2589 lookup_name = t.FullName;
2596 t = TypeManager.GetNestedType (t, elements [i++]);
2601 if (resolved == null) {
2602 NamespaceEntry.Error_NamespaceNotFound (loc, lookup_name);
2606 if (!(resolved is TypeExpr)) {
2607 resolved.Error_UnexpectedKind (ec.DeclContainer, "type", loc);
2611 type = resolved.Type;
2615 public override string Name {
2616 get { return name; }
2619 public override string FullName {
2620 get { return name; }
2623 protected override void CloneTo (CloneContext clonectx, Expression target)
2625 // CloneTo: Nothing, we do not keep any state on this expression
2630 /// Represents an "unbound generic type", ie. typeof (Foo<>).
2633 public class UnboundTypeExpression : TypeExpr
2637 public UnboundTypeExpression (MemberName name, Location l)
2643 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2646 if (name.Left != null) {
2647 Expression lexpr = name.Left.GetTypeExpression ();
2648 expr = new MemberAccess (lexpr, name.Basename);
2650 expr = new SimpleName (name.Basename, loc);
2653 FullNamedExpression fne = expr.ResolveAsTypeStep (ec, false);
2658 return new TypeExpression (type, loc);
2661 public override string Name {
2662 get { return name.FullName; }
2665 public override string FullName {
2666 get { return name.FullName; }
2670 public class TypeAliasExpression : TypeExpr {
2671 FullNamedExpression alias;
2676 public TypeAliasExpression (FullNamedExpression alias, TypeArguments args, Location l)
2682 eclass = ExprClass.Type;
2684 name = alias.FullName + "<" + args.ToString () + ">";
2686 name = alias.FullName;
2689 public override string Name {
2690 get { return alias.FullName; }
2693 public override string FullName {
2694 get { return name; }
2697 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2699 texpr = alias.ResolveAsTypeTerminal (ec, false);
2703 Type type = texpr.Type;
2704 int num_args = TypeManager.GetNumberOfTypeArguments (type);
2707 if (num_args == 0) {
2708 Report.Error (308, loc,
2709 "The non-generic type `{0}' cannot " +
2710 "be used with type arguments.",
2711 TypeManager.CSharpName (type));
2715 ConstructedType ctype = new ConstructedType (type, args, loc);
2716 return ctype.ResolveAsTypeTerminal (ec, false);
2717 } else if (num_args > 0) {
2718 Report.Error (305, loc,
2719 "Using the generic type `{0}' " +
2720 "requires {1} type arguments",
2721 TypeManager.CSharpName (type), num_args.ToString ());
2728 public override bool CheckAccessLevel (DeclSpace ds)
2730 return texpr.CheckAccessLevel (ds);
2733 public override bool AsAccessible (DeclSpace ds, int flags)
2735 return texpr.AsAccessible (ds, flags);
2738 public override bool IsClass {
2739 get { return texpr.IsClass; }
2742 public override bool IsValueType {
2743 get { return texpr.IsValueType; }
2746 public override bool IsInterface {
2747 get { return texpr.IsInterface; }
2750 public override bool IsSealed {
2751 get { return texpr.IsSealed; }
2756 /// This class denotes an expression which evaluates to a member
2757 /// of a struct or a class.
2759 public abstract class MemberExpr : Expression
2762 /// The name of this member.
2764 public abstract string Name {
2769 /// Whether this is an instance member.
2771 public abstract bool IsInstance {
2776 /// Whether this is a static member.
2778 public abstract bool IsStatic {
2783 /// The type which declares this member.
2785 public abstract Type DeclaringType {
2790 /// The instance expression associated with this member, if it's a
2791 /// non-static member.
2793 public Expression InstanceExpression;
2795 public static void error176 (Location loc, string name)
2797 Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
2798 "with an instance reference, qualify it with a type name instead", name);
2801 // TODO: possible optimalization
2802 // Cache resolved constant result in FieldBuilder <-> expression map
2803 public virtual Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
2804 SimpleName original)
2808 // original == null || original.Resolve (...) ==> left
2811 if (left is TypeExpr) {
2813 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
2821 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
2824 error176 (loc, GetSignatureForError ());
2828 InstanceExpression = left;
2833 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
2838 if (InstanceExpression == EmptyExpression.Null) {
2839 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
2843 if (InstanceExpression.Type.IsValueType) {
2844 if (InstanceExpression is IMemoryLocation) {
2845 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
2847 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
2848 InstanceExpression.Emit (ec);
2850 t.AddressOf (ec, AddressOp.Store);
2853 InstanceExpression.Emit (ec);
2855 if (prepare_for_load)
2856 ec.ig.Emit (OpCodes.Dup);
2861 /// Represents group of extension methods
2863 public class ExtensionMethodGroupExpr : MethodGroupExpr
2865 NamespaceEntry namespaceEntry;
2866 readonly bool usingCandidates;
2868 public ExtensionMethodGroupExpr (ArrayList list, NamespaceEntry n, bool usingCandidates,
2869 Type extensionType, Location l)
2872 this.namespaceEntry = n;
2873 this.usingCandidates = usingCandidates;
2874 this.type = extensionType;
2877 public override bool IsBase {
2878 get { return true; }
2881 public override bool IsStatic {
2882 get { return true; }
2885 public bool IsTopLevel {
2886 get { return namespaceEntry == null; }
2889 public override MethodBase OverloadExtensionResolve (EmitContext ec, ref ArrayList arguments, ref MethodGroupExpr mg,
2890 Expression expr, Location loc)
2892 if (arguments == null)
2893 arguments = new ArrayList (1);
2895 Argument a = new Argument (((MemberAccess)expr).Expr);
2896 a.Resolve (ec, loc);
2897 arguments.Insert (0, a);
2901 MethodBase method = mg.OverloadResolve (ec, arguments, true, loc);
2905 ExtensionMethodGroupExpr e = namespaceEntry.LookupExtensionMethod (type, usingCandidates, Name);
2907 return mg.OverloadResolve (ec, arguments, false, loc);
2910 namespaceEntry = e.namespaceEntry;
2916 /// MethodGroup Expression.
2918 /// This is a fully resolved expression that evaluates to a type
2920 public class MethodGroupExpr : MemberExpr {
2921 public MethodBase [] Methods;
2922 bool has_type_arguments = false;
2923 bool identical_type_name = false;
2926 public MethodGroupExpr (MemberInfo [] mi, Location l)
2928 Methods = new MethodBase [mi.Length];
2929 mi.CopyTo (Methods, 0);
2930 eclass = ExprClass.MethodGroup;
2932 // Set the type to something that will never be useful, which will
2933 // trigger the proper conversions.
2934 type = typeof (MethodGroupExpr);
2938 public MethodGroupExpr (ArrayList list, Location l)
2941 Methods = (MethodBase[])list.ToArray (typeof (MethodBase));
2943 foreach (MemberInfo m in list){
2944 if (!(m is MethodBase)){
2945 Console.WriteLine ("Name " + m.Name);
2946 Console.WriteLine ("Found a: " + m.GetType ().FullName);
2953 eclass = ExprClass.MethodGroup;
2954 type = TypeManager.object_type;
2957 public override Type DeclaringType {
2960 // We assume that the top-level type is in the end
2962 return Methods [Methods.Length - 1].DeclaringType;
2963 //return Methods [0].DeclaringType;
2967 public bool HasTypeArguments {
2969 return has_type_arguments;
2973 has_type_arguments = value;
2977 public bool IdenticalTypeName {
2979 return identical_type_name;
2983 identical_type_name = value;
2987 public virtual bool IsBase {
2996 public override string GetSignatureForError ()
2998 return TypeManager.CSharpSignature (Methods [0]);
3001 public override string Name {
3003 return Methods [0].Name;
3007 public override bool IsInstance {
3009 foreach (MethodBase mb in Methods)
3017 public override bool IsStatic {
3019 foreach (MethodBase mb in Methods)
3028 /// Determines "better conversion" as specified in 14.4.2.3
3030 /// Returns : p if a->p is better,
3031 /// q if a->q is better,
3032 /// null if neither is better
3034 static Type BetterConversion (EmitContext ec, Argument a, Type p, Type q)
3036 Type argument_type = TypeManager.TypeToCoreType (a.Type);
3037 Expression argument_expr = a.Expr;
3039 if (argument_type == null)
3040 throw new Exception ("Expression of type " + a.Expr +
3041 " does not resolve its type");
3043 if (p == null || q == null)
3044 throw new InternalErrorException ("BetterConversion Got a null conversion");
3049 if (argument_expr is NullLiteral)
3052 // If the argument is null and one of the types to compare is 'object' and
3053 // the other is a reference type, we prefer the other.
3055 // This follows from the usual rules:
3056 // * There is an implicit conversion from 'null' to type 'object'
3057 // * There is an implicit conversion from 'null' to any reference type
3058 // * There is an implicit conversion from any reference type to type 'object'
3059 // * There is no implicit conversion from type 'object' to other reference types
3060 // => Conversion of 'null' to a reference type is better than conversion to 'object'
3062 // FIXME: This probably isn't necessary, since the type of a NullLiteral is the
3063 // null type. I think it used to be 'object' and thus needed a special
3064 // case to avoid the immediately following two checks.
3066 if (!p.IsValueType && q == TypeManager.object_type)
3068 if (!q.IsValueType && p == TypeManager.object_type)
3072 if (argument_type == p)
3075 if (argument_type == q)
3078 Expression p_tmp = new EmptyExpression (p);
3079 Expression q_tmp = new EmptyExpression (q);
3081 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3082 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3084 if (p_to_q && !q_to_p)
3087 if (q_to_p && !p_to_q)
3090 if (p == TypeManager.sbyte_type)
3091 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3092 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3094 if (q == TypeManager.sbyte_type)
3095 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3096 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3099 if (p == TypeManager.short_type)
3100 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3101 q == TypeManager.uint64_type)
3103 if (q == TypeManager.short_type)
3104 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3105 p == TypeManager.uint64_type)
3108 if (p == TypeManager.int32_type)
3109 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3111 if (q == TypeManager.int32_type)
3112 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3115 if (p == TypeManager.int64_type)
3116 if (q == TypeManager.uint64_type)
3118 if (q == TypeManager.int64_type)
3119 if (p == TypeManager.uint64_type)
3126 /// Determines "Better function" between candidate
3127 /// and the current best match
3130 /// Returns a boolean indicating :
3131 /// false if candidate ain't better
3132 /// true if candidate is better than the current best match
3134 static bool BetterFunction (EmitContext ec, ArrayList args, int argument_count,
3135 MethodBase candidate, bool candidate_params,
3136 MethodBase best, bool best_params)
3138 ParameterData candidate_pd = TypeManager.GetParameterData (candidate);
3139 ParameterData best_pd = TypeManager.GetParameterData (best);
3141 bool better_at_least_one = false;
3143 for (int j = 0, c_idx = 0, b_idx = 0; j < argument_count; ++j, ++c_idx, ++b_idx)
3145 Argument a = (Argument) args [j];
3147 Type ct = TypeManager.TypeToCoreType (candidate_pd.ParameterType (c_idx));
3148 Type bt = TypeManager.TypeToCoreType (best_pd.ParameterType (b_idx));
3150 if (candidate_params && candidate_pd.ParameterModifier (c_idx) == Parameter.Modifier.PARAMS)
3152 ct = TypeManager.GetElementType (ct);
3156 if (best_params && best_pd.ParameterModifier (b_idx) == Parameter.Modifier.PARAMS)
3158 bt = TypeManager.GetElementType (bt);
3166 Type better = BetterConversion (ec, a, ct, bt);
3168 // for each argument, the conversion to 'ct' should be no worse than
3169 // the conversion to 'bt'.
3173 // for at least one argument, the conversion to 'ct' should be better than
3174 // the conversion to 'bt'.
3176 better_at_least_one = true;
3179 if (better_at_least_one)
3183 // This handles the case
3185 // Add (float f1, float f2, float f3);
3186 // Add (params decimal [] foo);
3188 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3189 // first candidate would've chosen as better.
3195 // The two methods have equal parameter types. Now apply tie-breaking rules
3197 if (TypeManager.IsGenericMethod (best) && !TypeManager.IsGenericMethod (candidate))
3199 if (!TypeManager.IsGenericMethod (best) && TypeManager.IsGenericMethod (candidate))
3203 // This handles the following cases:
3205 // Trim () is better than Trim (params char[] chars)
3206 // Concat (string s1, string s2, string s3) is better than
3207 // Concat (string s1, params string [] srest)
3208 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3210 if (!candidate_params && best_params)
3212 if (candidate_params && !best_params)
3215 int candidate_param_count = candidate_pd.Count;
3216 int best_param_count = best_pd.Count;
3218 if (candidate_param_count != best_param_count)
3219 // can only happen if (candidate_params && best_params)
3220 return candidate_param_count > best_param_count;
3223 // now, both methods have the same number of parameters, and the parameters have the same types
3224 // Pick the "more specific" signature
3227 MethodBase orig_candidate = TypeManager.DropGenericMethodArguments (candidate);
3228 MethodBase orig_best = TypeManager.DropGenericMethodArguments (best);
3230 ParameterData orig_candidate_pd = TypeManager.GetParameterData (orig_candidate);
3231 ParameterData orig_best_pd = TypeManager.GetParameterData (orig_best);
3233 bool specific_at_least_once = false;
3234 for (int j = 0; j < candidate_param_count; ++j)
3236 Type ct = TypeManager.TypeToCoreType (orig_candidate_pd.ParameterType (j));
3237 Type bt = TypeManager.TypeToCoreType (orig_best_pd.ParameterType (j));
3240 Type specific = MoreSpecific (ct, bt);
3244 specific_at_least_once = true;
3247 if (specific_at_least_once)
3250 // FIXME: handle lifted operators
3256 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3257 SimpleName original)
3259 if (!(left is TypeExpr) &&
3260 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3261 IdenticalTypeName = true;
3263 return base.ResolveMemberAccess (ec, left, loc, original);
3266 override public Expression DoResolve (EmitContext ec)
3269 InstanceExpression = null;
3271 if (InstanceExpression != null) {
3272 InstanceExpression = InstanceExpression.DoResolve (ec);
3273 if (InstanceExpression == null)
3280 public void ReportUsageError ()
3282 Report.Error (654, loc, "Method `" + DeclaringType + "." +
3283 Name + "()' is referenced without parentheses");
3286 override public void Emit (EmitContext ec)
3288 ReportUsageError ();
3291 public static bool IsAncestralType (Type first_type, Type second_type)
3293 return first_type != second_type &&
3294 (TypeManager.IsSubclassOf (second_type, first_type) ||
3295 TypeManager.ImplementsInterface (second_type, first_type));
3298 public static bool IsOverride (MethodBase cand_method, MethodBase base_method)
3300 if (!IsAncestralType (base_method.DeclaringType, cand_method.DeclaringType))
3303 ParameterData cand_pd = TypeManager.GetParameterData (cand_method);
3304 ParameterData base_pd = TypeManager.GetParameterData (base_method);
3306 if (cand_pd.Count != base_pd.Count)
3309 for (int j = 0; j < cand_pd.Count; ++j)
3311 Parameter.Modifier cm = cand_pd.ParameterModifier (j);
3312 Parameter.Modifier bm = base_pd.ParameterModifier (j);
3313 Type ct = TypeManager.TypeToCoreType (cand_pd.ParameterType (j));
3314 Type bt = TypeManager.TypeToCoreType (base_pd.ParameterType (j));
3316 if (cm != bm || ct != bt)
3323 static Type MoreSpecific (Type p, Type q)
3325 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
3327 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
3330 if (TypeManager.HasElementType (p))
3332 Type pe = TypeManager.GetElementType (p);
3333 Type qe = TypeManager.GetElementType (q);
3334 Type specific = MoreSpecific (pe, qe);
3340 else if (TypeManager.IsGenericType (p))
3342 Type[] pargs = TypeManager.GetTypeArguments (p);
3343 Type[] qargs = TypeManager.GetTypeArguments (q);
3345 bool p_specific_at_least_once = false;
3346 bool q_specific_at_least_once = false;
3348 for (int i = 0; i < pargs.Length; i++)
3350 Type specific = MoreSpecific (pargs [i], qargs [i]);
3351 if (specific == pargs [i])
3352 p_specific_at_least_once = true;
3353 if (specific == qargs [i])
3354 q_specific_at_least_once = true;
3357 if (p_specific_at_least_once && !q_specific_at_least_once)
3359 if (!p_specific_at_least_once && q_specific_at_least_once)
3366 public virtual MethodBase OverloadExtensionResolve (EmitContext ec, ref ArrayList arguments, ref MethodGroupExpr mg,
3367 Expression expr, Location loc)
3369 MethodBase method = OverloadResolve (ec, arguments, true, loc);
3370 if (method != null) {
3375 MemberAccess mexpr = expr as MemberAccess;
3376 if (mexpr != null) {
3377 ExtensionMethodGroupExpr emg = ec.DeclContainer.LookupExtensionMethod (mexpr.Expr.Type, Name);
3379 return OverloadExtensionResolve (ec, ref arguments, ref mg, expr, loc);
3383 return OverloadResolve (ec, arguments, false, loc);
3387 /// Find the Applicable Function Members (7.4.2.1)
3389 /// me: Method Group expression with the members to select.
3390 /// it might contain constructors or methods (or anything
3391 /// that maps to a method).
3393 /// Arguments: ArrayList containing resolved Argument objects.
3395 /// loc: The location if we want an error to be reported, or a Null
3396 /// location for "probing" purposes.
3398 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3399 /// that is the best match of me on Arguments.
3402 public virtual MethodBase OverloadResolve (EmitContext ec, ArrayList Arguments,
3403 bool may_fail, Location loc)
3405 MethodBase method = null;
3406 bool method_params = false;
3407 Type applicable_type = null;
3409 ArrayList candidates = new ArrayList (2);
3410 ArrayList candidate_overrides = null;
3413 // Used to keep a map between the candidate
3414 // and whether it is being considered in its
3415 // normal or expanded form
3417 // false is normal form, true is expanded form
3419 Hashtable candidate_to_form = null;
3421 if (Arguments != null)
3422 arg_count = Arguments.Count;
3424 if (RootContext.Version == LanguageVersion.ISO_1 && Name == "Invoke" && TypeManager.IsDelegateType (DeclaringType)) {
3426 Report.Error (1533, loc, "Invoke cannot be called directly on a delegate");
3430 int nmethods = Methods.Length;
3434 // Methods marked 'override' don't take part in 'applicable_type'
3435 // computation, nor in the actual overload resolution.
3436 // However, they still need to be emitted instead of a base virtual method.
3437 // So, we salt them away into the 'candidate_overrides' array.
3439 // In case of reflected methods, we replace each overriding method with
3440 // its corresponding base virtual method. This is to improve compatibility
3441 // with non-C# libraries which change the visibility of overrides (#75636)
3444 for (int i = 0; i < Methods.Length; ++i) {
3445 MethodBase m = Methods [i];
3447 Type [] gen_args = null;
3448 if (m.IsGenericMethod && !m.IsGenericMethodDefinition)
3449 gen_args = m.GetGenericArguments ();
3451 if (TypeManager.IsOverride (m)) {
3452 if (candidate_overrides == null)
3453 candidate_overrides = new ArrayList ();
3454 candidate_overrides.Add (m);
3455 m = TypeManager.TryGetBaseDefinition (m);
3457 if (m != null && gen_args != null) {
3458 if (!m.IsGenericMethodDefinition)
3459 throw new InternalErrorException ("GetBaseDefinition didn't return a GenericMethodDefinition");
3460 m = ((MethodInfo) m).MakeGenericMethod (gen_args);
3470 int applicable_errors = Report.Errors;
3473 // First we construct the set of applicable methods
3475 bool is_sorted = true;
3476 for (int i = 0; i < nmethods; i++) {
3477 Type decl_type = Methods [i].DeclaringType;
3480 // If we have already found an applicable method
3481 // we eliminate all base types (Section 14.5.5.1)
3483 if (applicable_type != null && IsAncestralType (decl_type, applicable_type))
3487 // Check if candidate is applicable (section 14.4.2.1)
3488 // Is candidate applicable in normal form?
3490 bool is_applicable = Invocation.IsApplicable (ec, this, Arguments, arg_count, ref Methods [i]);
3492 if (!is_applicable && Invocation.IsParamsMethodApplicable (ec, this, Arguments, arg_count, ref Methods [i])) {
3493 MethodBase candidate = Methods [i];
3494 if (candidate_to_form == null)
3495 candidate_to_form = new PtrHashtable ();
3496 candidate_to_form [candidate] = candidate;
3497 // Candidate is applicable in expanded form
3498 is_applicable = true;
3504 candidates.Add (Methods [i]);
3506 if (applicable_type == null)
3507 applicable_type = decl_type;
3508 else if (applicable_type != decl_type) {
3510 if (IsAncestralType (applicable_type, decl_type))
3511 applicable_type = decl_type;
3515 if (applicable_errors != Report.Errors)
3518 int candidate_top = candidates.Count;
3520 if (applicable_type == null) {
3522 // Okay so we have failed to find anything so we
3523 // return by providing info about the closest match
3525 int errors = Report.Errors;
3526 for (int i = 0; i < nmethods; ++i) {
3527 MethodBase c = Methods [i];
3528 ParameterData pd = TypeManager.GetParameterData (c);
3530 if (pd.Count != arg_count)
3534 if (!TypeManager.InferTypeArguments (ec, Arguments, ref c))
3536 if (TypeManager.IsGenericMethodDefinition (c))
3540 Invocation.VerifyArgumentsCompat (ec, Arguments, arg_count,
3541 c, false, null, may_fail, loc);
3543 if (!may_fail && errors == Report.Errors){
3545 throw new InternalErrorException (
3546 "VerifyArgumentsCompat and IsApplicable do not agree; " +
3547 "likely reason: ImplicitConversion and ImplicitConversionExists have gone out of sync");
3553 if (!may_fail && errors == Report.Errors) {
3554 string report_name = Name;
3555 if (report_name == ".ctor")
3556 report_name = TypeManager.CSharpName (DeclaringType);
3562 for (int i = 0; i < Methods.Length; ++i) {
3563 MethodBase c = Methods [i];
3564 ParameterData pd = TypeManager.GetParameterData (c);
3566 if (pd.Count != arg_count)
3569 if (TypeManager.InferTypeArguments (ec, Arguments, ref c))
3573 411, loc, "The type arguments for " +
3574 "method `{0}' cannot be inferred from " +
3575 "the usage. Try specifying the type " +
3576 "arguments explicitly.", report_name);
3581 Invocation.Error_WrongNumArguments (loc, report_name, arg_count);
3589 // At this point, applicable_type is _one_ of the most derived types
3590 // in the set of types containing the methods in this MethodGroup.
3591 // Filter the candidates so that they only contain methods from the
3592 // most derived types.
3595 int finalized = 0; // Number of finalized candidates
3598 // Invariant: applicable_type is a most derived type
3600 // We'll try to complete Section 14.5.5.1 for 'applicable_type' by
3601 // eliminating all it's base types. At the same time, we'll also move
3602 // every unrelated type to the end of the array, and pick the next
3603 // 'applicable_type'.
3605 Type next_applicable_type = null;
3606 int j = finalized; // where to put the next finalized candidate
3607 int k = finalized; // where to put the next undiscarded candidate
3608 for (int i = finalized; i < candidate_top; ++i) {
3609 MethodBase candidate = (MethodBase) candidates [i];
3610 Type decl_type = candidate.DeclaringType;
3612 if (decl_type == applicable_type) {
3613 candidates [k++] = candidates [j];
3614 candidates [j++] = candidates [i];
3618 if (IsAncestralType (decl_type, applicable_type))
3621 if (next_applicable_type != null &&
3622 IsAncestralType (decl_type, next_applicable_type))
3625 candidates [k++] = candidates [i];
3627 if (next_applicable_type == null ||
3628 IsAncestralType (next_applicable_type, decl_type))
3629 next_applicable_type = decl_type;
3632 applicable_type = next_applicable_type;
3635 } while (applicable_type != null);
3639 // Now we actually find the best method
3642 method = (MethodBase) candidates [0];
3643 method_params = candidate_to_form != null && candidate_to_form.Contains (method);
3644 for (int ix = 1; ix < candidate_top; ix++) {
3645 MethodBase candidate = (MethodBase) candidates [ix];
3647 if (candidate == method)
3650 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
3652 if (BetterFunction (ec, Arguments, arg_count,
3653 candidate, cand_params,
3654 method, method_params)) {
3656 method_params = cand_params;
3660 // Now check that there are no ambiguities i.e the selected method
3661 // should be better than all the others
3663 MethodBase ambiguous = null;
3664 for (int ix = 0; ix < candidate_top; ix++) {
3665 MethodBase candidate = (MethodBase) candidates [ix];
3667 if (candidate == method)
3670 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
3671 if (!BetterFunction (ec, Arguments, arg_count,
3672 method, method_params,
3673 candidate, cand_params))
3676 Report.SymbolRelatedToPreviousError (candidate);
3677 ambiguous = candidate;
3681 if (ambiguous != null) {
3682 Report.SymbolRelatedToPreviousError (method);
3683 Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
3684 TypeManager.CSharpSignature (ambiguous), TypeManager.CSharpSignature (method));
3689 // If the method is a virtual function, pick an override closer to the LHS type.
3691 if (!IsBase && method.IsVirtual) {
3692 if (TypeManager.IsOverride (method))
3693 throw new InternalErrorException (
3694 "Should not happen. An 'override' method took part in overload resolution: " + method);
3696 if (candidate_overrides != null)
3697 foreach (MethodBase candidate in candidate_overrides) {
3698 if (IsOverride (candidate, method))
3704 // And now check if the arguments are all
3705 // compatible, perform conversions if
3706 // necessary etc. and return if everything is
3709 if (!Invocation.VerifyArgumentsCompat (ec, Arguments, arg_count, method,
3710 method_params, null, may_fail, loc))
3716 MethodBase the_method = TypeManager.DropGenericMethodArguments (method);
3718 if (the_method.IsGenericMethodDefinition &&
3719 !ConstraintChecker.CheckConstraints (ec, the_method, method, loc))
3723 IMethodData data = TypeManager.GetMethod (the_method);
3725 data.SetMemberIsUsed ();
3731 bool RemoveMethods (bool keep_static)
3733 ArrayList smethods = new ArrayList ();
3735 foreach (MethodBase mb in Methods){
3736 if (mb.IsStatic == keep_static)
3740 if (smethods.Count == 0)
3743 Methods = new MethodBase [smethods.Count];
3744 smethods.CopyTo (Methods, 0);
3750 /// Removes any instance methods from the MethodGroup, returns
3751 /// false if the resulting set is empty.
3753 public bool RemoveInstanceMethods ()
3755 return RemoveMethods (true);
3759 /// Removes any static methods from the MethodGroup, returns
3760 /// false if the resulting set is empty.
3762 public bool RemoveStaticMethods ()
3764 return RemoveMethods (false);
3767 public Expression ResolveGeneric (EmitContext ec, TypeArguments args)
3770 if (!args.Resolve (ec))
3773 Type[] atypes = args.Arguments;
3775 int first_count = 0;
3776 MethodInfo first = null;
3778 ArrayList list = new ArrayList ();
3779 foreach (MethodBase mb in Methods) {
3780 MethodInfo mi = mb as MethodInfo;
3781 if ((mi == null) || !mb.IsGenericMethod)
3784 Type[] gen_params = mb.GetGenericArguments ();
3786 if (first == null) {
3788 first_count = gen_params.Length;
3791 if (gen_params.Length != atypes.Length)
3794 mi = mi.MakeGenericMethod (atypes);
3798 // MS implementation throws NotSupportedException for GetParameters
3799 // on unbaked generic method
3800 Parameters p = ((Parameters)TypeManager.GetParameterData (mi)).Clone ();
3801 p.InflateTypes (atypes);
3802 TypeManager.RegisterMethod (mi, p);
3806 if (list.Count > 0) {
3807 MethodGroupExpr new_mg = new MethodGroupExpr (list, Location);
3808 new_mg.InstanceExpression = InstanceExpression;
3809 new_mg.HasTypeArguments = true;
3810 new_mg.IsBase = IsBase;
3814 if (first != null) {
3815 Report.SymbolRelatedToPreviousError (first);
3817 305, loc, "Using the generic method `{0}' requires `{1}' type arguments",
3818 TypeManager.CSharpSignature (first), first_count.ToString ());
3821 308, loc, "The non-generic method `{0}' " +
3822 "cannot be used with type arguments", Name);
3826 throw new NotImplementedException ();
3832 /// Fully resolved expression that evaluates to a Field
3834 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariable {
3835 public readonly FieldInfo FieldInfo;
3836 VariableInfo variable_info;
3838 LocalTemporary temp;
3840 bool in_initializer;
3842 public FieldExpr (FieldInfo fi, Location l, bool in_initializer):
3845 this.in_initializer = in_initializer;
3848 public FieldExpr (FieldInfo fi, Location l)
3851 eclass = ExprClass.Variable;
3852 type = TypeManager.TypeToCoreType (fi.FieldType);
3856 public override string Name {
3858 return FieldInfo.Name;
3862 public override bool IsInstance {
3864 return !FieldInfo.IsStatic;
3868 public override bool IsStatic {
3870 return FieldInfo.IsStatic;
3874 public override Type DeclaringType {
3876 return FieldInfo.DeclaringType;
3880 public override string GetSignatureForError ()
3882 return TypeManager.GetFullNameSignature (FieldInfo);
3885 public VariableInfo VariableInfo {
3887 return variable_info;
3891 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3892 SimpleName original)
3894 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
3896 Type t = fi.FieldType;
3898 if (fi.IsLiteral || (fi.IsInitOnly && t == TypeManager.decimal_type)) {
3899 IConstant ic = TypeManager.GetConstant (fi);
3902 ic = new ExternalConstant (fi);
3904 ic = ExternalConstant.CreateDecimal (fi);
3906 return base.ResolveMemberAccess (ec, left, loc, original);
3909 TypeManager.RegisterConstant (fi, ic);
3912 bool left_is_type = left is TypeExpr;
3913 if (!left_is_type && (original == null || !original.IdenticalNameAndTypeName (ec, left, loc))) {
3914 Report.SymbolRelatedToPreviousError (FieldInfo);
3915 error176 (loc, TypeManager.GetFullNameSignature (FieldInfo));
3919 if (ic.ResolveValue ()) {
3920 if (!ec.IsInObsoleteScope)
3921 ic.CheckObsoleteness (loc);
3924 return ic.CreateConstantReference (loc);
3927 if (t.IsPointer && !ec.InUnsafe) {
3932 return base.ResolveMemberAccess (ec, left, loc, original);
3935 override public Expression DoResolve (EmitContext ec)
3937 return DoResolve (ec, false, false);
3940 Expression DoResolve (EmitContext ec, bool lvalue_instance, bool out_access)
3942 if (!FieldInfo.IsStatic){
3943 if (InstanceExpression == null){
3945 // This can happen when referencing an instance field using
3946 // a fully qualified type expression: TypeName.InstanceField = xxx
3948 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3952 // Resolve the field's instance expression while flow analysis is turned
3953 // off: when accessing a field "a.b", we must check whether the field
3954 // "a.b" is initialized, not whether the whole struct "a" is initialized.
3956 if (lvalue_instance) {
3957 using (ec.With (EmitContext.Flags.DoFlowAnalysis, false)) {
3958 Expression right_side =
3959 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
3960 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side, loc);
3963 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
3964 InstanceExpression = InstanceExpression.Resolve (ec, rf);
3967 if (InstanceExpression == null)
3970 InstanceExpression.CheckMarshalByRefAccess ();
3973 if (!in_initializer && !ec.IsFieldInitializer) {
3974 ObsoleteAttribute oa;
3975 FieldBase f = TypeManager.GetField (FieldInfo);
3977 if (!ec.IsInObsoleteScope)
3978 f.CheckObsoleteness (loc);
3980 // To be sure that type is external because we do not register generated fields
3981 } else if (!(FieldInfo.DeclaringType is TypeBuilder)) {
3982 oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
3984 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
3988 AnonymousContainer am = ec.CurrentAnonymousMethod;
3990 if (!FieldInfo.IsStatic){
3991 if (!am.IsIterator && (ec.TypeContainer is Struct)){
3992 Report.Error (1673, loc,
3993 "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",
4000 // If the instance expression is a local variable or parameter.
4001 IVariable var = InstanceExpression as IVariable;
4002 if ((var == null) || (var.VariableInfo == null))
4005 VariableInfo vi = var.VariableInfo;
4006 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
4009 variable_info = vi.GetSubStruct (FieldInfo.Name);
4013 static readonly int [] codes = {
4014 191, // instance, write access
4015 192, // instance, out access
4016 198, // static, write access
4017 199, // static, out access
4018 1648, // member of value instance, write access
4019 1649, // member of value instance, out access
4020 1650, // member of value static, write access
4021 1651 // member of value static, out access
4024 static readonly string [] msgs = {
4025 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4026 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4027 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4028 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4029 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4030 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4031 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4032 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4035 // The return value is always null. Returning a value simplifies calling code.
4036 Expression Report_AssignToReadonly (Expression right_side)
4039 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4043 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4045 Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4050 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4052 IVariable var = InstanceExpression as IVariable;
4053 if ((var != null) && (var.VariableInfo != null))
4054 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
4056 bool lvalue_instance = !FieldInfo.IsStatic && FieldInfo.DeclaringType.IsValueType;
4057 bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
4059 Expression e = DoResolve (ec, lvalue_instance, out_access);
4064 FieldBase fb = TypeManager.GetField (FieldInfo);
4068 if (FieldInfo.IsInitOnly) {
4069 // InitOnly fields can only be assigned in constructors or initializers
4070 if (!ec.IsFieldInitializer && !ec.IsConstructor)
4071 return Report_AssignToReadonly (right_side);
4073 if (ec.IsConstructor) {
4074 Type ctype = ec.TypeContainer.CurrentType;
4076 ctype = ec.ContainerType;
4078 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4079 if (!TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
4080 return Report_AssignToReadonly (right_side);
4081 // static InitOnly fields cannot be assigned-to in an instance constructor
4082 if (IsStatic && !ec.IsStatic)
4083 return Report_AssignToReadonly (right_side);
4084 // instance constructors can't modify InitOnly fields of other instances of the same type
4085 if (!IsStatic && !(InstanceExpression is This))
4086 return Report_AssignToReadonly (right_side);
4090 if (right_side == EmptyExpression.OutAccess &&
4091 !IsStatic && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
4092 Report.SymbolRelatedToPreviousError (DeclaringType);
4093 Report.Warning (197, 1, loc,
4094 "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",
4095 GetSignatureForError ());
4101 public override void CheckMarshalByRefAccess ()
4103 if (!IsStatic && Type.IsValueType && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
4104 Report.SymbolRelatedToPreviousError (DeclaringType);
4105 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",
4106 GetSignatureForError ());
4110 public bool VerifyFixed ()
4112 IVariable variable = InstanceExpression as IVariable;
4113 // A variable of the form V.I is fixed when V is a fixed variable of a struct type.
4114 // We defer the InstanceExpression check after the variable check to avoid a
4115 // separate null check on InstanceExpression.
4116 return variable != null && InstanceExpression.Type.IsValueType && variable.VerifyFixed ();
4119 public override int GetHashCode ()
4121 return FieldInfo.GetHashCode ();
4124 public override bool Equals (object obj)
4126 FieldExpr fe = obj as FieldExpr;
4130 if (FieldInfo != fe.FieldInfo)
4133 if (InstanceExpression == null || fe.InstanceExpression == null)
4136 return InstanceExpression.Equals (fe.InstanceExpression);
4139 public void Emit (EmitContext ec, bool leave_copy)
4141 ILGenerator ig = ec.ig;
4142 bool is_volatile = false;
4144 FieldBase f = TypeManager.GetField (FieldInfo);
4146 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4149 f.SetMemberIsUsed ();
4152 if (FieldInfo.IsStatic){
4154 ig.Emit (OpCodes.Volatile);
4156 ig.Emit (OpCodes.Ldsfld, FieldInfo);
4159 EmitInstance (ec, false);
4162 ig.Emit (OpCodes.Volatile);
4164 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
4167 ig.Emit (OpCodes.Ldflda, FieldInfo);
4168 ig.Emit (OpCodes.Ldflda, ff.Element);
4171 ig.Emit (OpCodes.Ldfld, FieldInfo);
4176 ec.ig.Emit (OpCodes.Dup);
4177 if (!FieldInfo.IsStatic) {
4178 temp = new LocalTemporary (this.Type);
4184 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4186 FieldAttributes fa = FieldInfo.Attributes;
4187 bool is_static = (fa & FieldAttributes.Static) != 0;
4188 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
4189 ILGenerator ig = ec.ig;
4190 prepared = prepare_for_load;
4192 if (is_readonly && !ec.IsConstructor){
4193 Report_AssignToReadonly (source);
4197 EmitInstance (ec, prepare_for_load);
4201 ec.ig.Emit (OpCodes.Dup);
4202 if (!FieldInfo.IsStatic) {
4203 temp = new LocalTemporary (this.Type);
4208 FieldBase f = TypeManager.GetField (FieldInfo);
4210 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4211 ig.Emit (OpCodes.Volatile);
4217 ig.Emit (OpCodes.Stsfld, FieldInfo);
4219 ig.Emit (OpCodes.Stfld, FieldInfo);
4227 public override void Emit (EmitContext ec)
4232 public void AddressOf (EmitContext ec, AddressOp mode)
4234 ILGenerator ig = ec.ig;
4236 FieldBase f = TypeManager.GetField (FieldInfo);
4238 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
4239 Report.Warning (420, 1, loc, "`{0}': A volatile fields cannot be passed using a ref or out parameter",
4240 f.GetSignatureForError ());
4244 if ((mode & AddressOp.Store) != 0)
4246 if ((mode & AddressOp.Load) != 0)
4247 f.SetMemberIsUsed ();
4251 // Handle initonly fields specially: make a copy and then
4252 // get the address of the copy.
4255 if (FieldInfo.IsInitOnly){
4257 if (ec.IsConstructor){
4258 if (FieldInfo.IsStatic){
4270 local = ig.DeclareLocal (type);
4271 ig.Emit (OpCodes.Stloc, local);
4272 ig.Emit (OpCodes.Ldloca, local);
4277 if (FieldInfo.IsStatic){
4278 ig.Emit (OpCodes.Ldsflda, FieldInfo);
4281 EmitInstance (ec, false);
4282 ig.Emit (OpCodes.Ldflda, FieldInfo);
4288 // A FieldExpr whose address can not be taken
4290 public class FieldExprNoAddress : FieldExpr, IMemoryLocation {
4291 public FieldExprNoAddress (FieldInfo fi, Location loc) : base (fi, loc)
4295 public new void AddressOf (EmitContext ec, AddressOp mode)
4297 Report.Error (-215, "Report this: Taking the address of a remapped parameter not supported");
4302 /// Expression that evaluates to a Property. The Assign class
4303 /// might set the `Value' expression if we are in an assignment.
4305 /// This is not an LValue because we need to re-write the expression, we
4306 /// can not take data from the stack and store it.
4308 public class PropertyExpr : MemberExpr, IAssignMethod {
4309 public readonly PropertyInfo PropertyInfo;
4312 // This is set externally by the `BaseAccess' class
4315 MethodInfo getter, setter;
4320 LocalTemporary temp;
4323 public PropertyExpr (Type containerType, PropertyInfo pi, Location l)
4326 eclass = ExprClass.PropertyAccess;
4330 type = TypeManager.TypeToCoreType (pi.PropertyType);
4332 ResolveAccessors (containerType);
4335 public override string Name {
4337 return PropertyInfo.Name;
4341 public override bool IsInstance {
4347 public override bool IsStatic {
4353 public override Type DeclaringType {
4355 return PropertyInfo.DeclaringType;
4359 public override string GetSignatureForError ()
4361 return TypeManager.GetFullNameSignature (PropertyInfo);
4364 void FindAccessors (Type invocation_type)
4366 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
4367 BindingFlags.Static | BindingFlags.Instance |
4368 BindingFlags.DeclaredOnly;
4370 Type current = PropertyInfo.DeclaringType;
4371 for (; current != null; current = current.BaseType) {
4372 MemberInfo[] group = TypeManager.MemberLookup (
4373 invocation_type, invocation_type, current,
4374 MemberTypes.Property, flags, PropertyInfo.Name, null);
4379 if (group.Length != 1)
4380 // Oooops, can this ever happen ?
4383 PropertyInfo pi = (PropertyInfo) group [0];
4386 getter = pi.GetGetMethod (true);
4389 setter = pi.GetSetMethod (true);
4391 MethodInfo accessor = getter != null ? getter : setter;
4393 if (!accessor.IsVirtual)
4399 // We also perform the permission checking here, as the PropertyInfo does not
4400 // hold the information for the accessibility of its setter/getter
4402 // TODO: Refactor to use some kind of cache together with GetPropertyFromAccessor
4403 void ResolveAccessors (Type containerType)
4405 FindAccessors (containerType);
4407 if (getter != null) {
4408 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
4409 IMethodData md = TypeManager.GetMethod (the_getter);
4411 md.SetMemberIsUsed ();
4413 is_static = getter.IsStatic;
4416 if (setter != null) {
4417 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
4418 IMethodData md = TypeManager.GetMethod (the_setter);
4420 md.SetMemberIsUsed ();
4422 is_static = setter.IsStatic;
4426 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
4429 InstanceExpression = null;
4433 if (InstanceExpression == null) {
4434 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4438 InstanceExpression = InstanceExpression.DoResolve (ec);
4439 if (lvalue_instance && InstanceExpression != null)
4440 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
4442 if (InstanceExpression == null)
4445 InstanceExpression.CheckMarshalByRefAccess ();
4447 if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) &&
4448 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
4449 !TypeManager.IsNestedChildOf (ec.ContainerType, InstanceExpression.Type) &&
4450 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.ContainerType)) {
4451 Report.SymbolRelatedToPreviousError (PropertyInfo);
4452 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
4459 void Error_PropertyNotFound (MethodInfo mi, bool getter)
4461 // TODO: correctly we should compare arguments but it will lead to bigger changes
4462 if (mi is MethodBuilder) {
4463 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
4467 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
4469 ParameterData iparams = TypeManager.GetParameterData (mi);
4470 sig.Append (getter ? "get_" : "set_");
4472 sig.Append (iparams.GetSignatureForError ());
4474 Report.SymbolRelatedToPreviousError (mi);
4475 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
4476 Name, sig.ToString ());
4479 override public Expression DoResolve (EmitContext ec)
4484 if (getter != null){
4485 if (TypeManager.GetParameterData (getter).Count != 0){
4486 Error_PropertyNotFound (getter, true);
4491 if (getter == null){
4493 // The following condition happens if the PropertyExpr was
4494 // created, but is invalid (ie, the property is inaccessible),
4495 // and we did not want to embed the knowledge about this in
4496 // the caller routine. This only avoids double error reporting.
4501 if (InstanceExpression != EmptyExpression.Null) {
4502 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
4503 TypeManager.GetFullNameSignature (PropertyInfo));
4508 bool must_do_cs1540_check = false;
4509 if (getter != null &&
4510 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
4511 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
4512 if (pm != null && pm.HasCustomAccessModifier) {
4513 Report.SymbolRelatedToPreviousError (pm);
4514 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
4515 TypeManager.CSharpSignature (getter));
4518 Report.SymbolRelatedToPreviousError (getter);
4519 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
4524 if (!InstanceResolve (ec, false, must_do_cs1540_check))
4528 // Only base will allow this invocation to happen.
4530 if (IsBase && getter.IsAbstract) {
4531 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
4535 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
4545 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4547 if (right_side == EmptyExpression.OutAccess) {
4548 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
4549 GetSignatureForError ());
4553 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
4554 Report.Error (1612, loc, "Cannot modify the return value of `{0}' because it is not a variable",
4555 GetSignatureForError ());
4559 if (setter == null){
4561 // The following condition happens if the PropertyExpr was
4562 // created, but is invalid (ie, the property is inaccessible),
4563 // and we did not want to embed the knowledge about this in
4564 // the caller routine. This only avoids double error reporting.
4568 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
4569 GetSignatureForError ());
4573 if (TypeManager.GetParameterData (setter).Count != 1){
4574 Error_PropertyNotFound (setter, false);
4578 bool must_do_cs1540_check;
4579 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
4580 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
4581 if (pm != null && pm.HasCustomAccessModifier) {
4582 Report.SymbolRelatedToPreviousError (pm);
4583 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
4584 TypeManager.CSharpSignature (setter));
4587 Report.SymbolRelatedToPreviousError (setter);
4588 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
4593 if (!InstanceResolve (ec, PropertyInfo.DeclaringType.IsValueType, must_do_cs1540_check))
4597 // Only base will allow this invocation to happen.
4599 if (IsBase && setter.IsAbstract){
4600 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
4607 public override void Emit (EmitContext ec)
4612 public void Emit (EmitContext ec, bool leave_copy)
4615 // Special case: length of single dimension array property is turned into ldlen
4617 if ((getter == TypeManager.system_int_array_get_length) ||
4618 (getter == TypeManager.int_array_get_length)){
4619 Type iet = InstanceExpression.Type;
4622 // System.Array.Length can be called, but the Type does not
4623 // support invoking GetArrayRank, so test for that case first
4625 if (iet != TypeManager.array_type && (iet.GetArrayRank () == 1)) {
4627 EmitInstance (ec, false);
4628 ec.ig.Emit (OpCodes.Ldlen);
4629 ec.ig.Emit (OpCodes.Conv_I4);
4634 Invocation.EmitCall (ec, IsBase, IsStatic, InstanceExpression, getter, null, loc, prepared, false);
4637 ec.ig.Emit (OpCodes.Dup);
4639 temp = new LocalTemporary (this.Type);
4646 // Implements the IAssignMethod interface for assignments
4648 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4650 Expression my_source = source;
4652 prepared = prepare_for_load;
4657 ec.ig.Emit (OpCodes.Dup);
4659 temp = new LocalTemporary (this.Type);
4663 } else if (leave_copy) {
4666 temp = new LocalTemporary (this.Type);
4672 ArrayList args = new ArrayList (1);
4673 args.Add (new Argument (my_source, Argument.AType.Expression));
4675 Invocation.EmitCall (ec, IsBase, IsStatic, InstanceExpression, setter, args, loc, false, prepared);
4685 /// Fully resolved expression that evaluates to an Event
4687 public class EventExpr : MemberExpr {
4688 public readonly EventInfo EventInfo;
4691 MethodInfo add_accessor, remove_accessor;
4693 public EventExpr (EventInfo ei, Location loc)
4697 eclass = ExprClass.EventAccess;
4699 add_accessor = TypeManager.GetAddMethod (ei);
4700 remove_accessor = TypeManager.GetRemoveMethod (ei);
4701 if (add_accessor.IsStatic || remove_accessor.IsStatic)
4704 if (EventInfo is MyEventBuilder){
4705 MyEventBuilder eb = (MyEventBuilder) EventInfo;
4706 type = eb.EventType;
4709 type = EventInfo.EventHandlerType;
4712 public override string Name {
4714 return EventInfo.Name;
4718 public override bool IsInstance {
4724 public override bool IsStatic {
4730 public override Type DeclaringType {
4732 return EventInfo.DeclaringType;
4736 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
4737 SimpleName original)
4740 // If the event is local to this class, we transform ourselves into a FieldExpr
4743 if (EventInfo.DeclaringType == ec.ContainerType ||
4744 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
4745 EventField mi = TypeManager.GetEventField (EventInfo);
4748 if (!ec.IsInObsoleteScope)
4749 mi.CheckObsoleteness (loc);
4751 FieldExpr ml = new FieldExpr (mi.FieldBuilder, loc);
4753 InstanceExpression = null;
4755 return ml.ResolveMemberAccess (ec, left, loc, original);
4759 return base.ResolveMemberAccess (ec, left, loc, original);
4763 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
4766 InstanceExpression = null;
4770 if (InstanceExpression == null) {
4771 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4775 InstanceExpression = InstanceExpression.DoResolve (ec);
4776 if (InstanceExpression == null)
4780 // This is using the same mechanism as the CS1540 check in PropertyExpr.
4781 // However, in the Event case, we reported a CS0122 instead.
4783 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
4784 InstanceExpression.Type != ec.ContainerType &&
4785 ec.ContainerType.IsSubclassOf (InstanceExpression.Type)) {
4786 Report.SymbolRelatedToPreviousError (EventInfo);
4787 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
4794 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
4796 return DoResolve (ec);
4799 public override Expression DoResolve (EmitContext ec)
4801 bool must_do_cs1540_check;
4802 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
4803 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
4804 Report.SymbolRelatedToPreviousError (EventInfo);
4805 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
4809 if (!InstanceResolve (ec, must_do_cs1540_check))
4815 public override void Emit (EmitContext ec)
4817 if (InstanceExpression is This)
4818 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of += or -=", GetSignatureForError ());
4820 Report.Error (70, loc, "The event `{0}' can only appear on the left hand side of += or -= "+
4821 "(except on the defining type)", Name);
4824 public override string GetSignatureForError ()
4826 return TypeManager.CSharpSignature (EventInfo);
4829 public void EmitAddOrRemove (EmitContext ec, Expression source)
4831 BinaryDelegate source_del = source as BinaryDelegate;
4832 if (source_del == null) {
4836 Expression handler = source_del.Right;
4838 Argument arg = new Argument (handler, Argument.AType.Expression);
4839 ArrayList args = new ArrayList ();
4843 if (source_del.IsAddition)
4844 Invocation.EmitCall (
4845 ec, false, IsStatic, InstanceExpression, add_accessor, args, loc);
4847 Invocation.EmitCall (
4848 ec, false, IsStatic, InstanceExpression, remove_accessor, args, loc);
4852 public class TemporaryVariable : Expression, IMemoryLocation
4857 public TemporaryVariable (Type type, Location loc)
4861 eclass = ExprClass.Value;
4864 public override Expression DoResolve (EmitContext ec)
4869 TypeExpr te = new TypeExpression (type, loc);
4870 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
4871 if (!li.Resolve (ec))
4874 if (ec.MustCaptureVariable (li)) {
4875 ScopeInfo scope = li.Block.CreateScopeInfo ();
4876 var = scope.AddLocal (li);
4883 public Variable Variable {
4884 get { return var != null ? var : li.Variable; }
4887 public override void Emit (EmitContext ec)
4889 Variable.EmitInstance (ec);
4893 public void EmitLoadAddress (EmitContext ec)
4895 Variable.EmitInstance (ec);
4896 Variable.EmitAddressOf (ec);
4899 public void Store (EmitContext ec, Expression right_side)
4901 Variable.EmitInstance (ec);
4902 right_side.Emit (ec);
4903 Variable.EmitAssign (ec);
4906 public void EmitThis (EmitContext ec)
4908 Variable.EmitInstance (ec);
4911 public void EmitStore (EmitContext ec)
4913 Variable.EmitAssign (ec);
4916 public void AddressOf (EmitContext ec, AddressOp mode)
4918 EmitLoadAddress (ec);