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) && !TypeManager.IsGenericType (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 private class UnexpectedType
2561 // This performes recursive type lookup, providing support for generic types.
2562 // For example, given the type:
2564 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]]
2566 // The types will be checked in the following order:
2569 // System.Collections |
2570 // System.Collections.Generic |
2572 // System | recursive call 1 |
2573 // System.Int32 _| | main method call
2575 // System | recursive call 2 |
2576 // System.String _| |
2578 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]] _|
2580 private Type TypeLookup (IResolveContext ec, string name)
2585 FullNamedExpression resolved = null;
2587 Type recursive_type = null;
2588 while (index < name.Length) {
2589 if (name[index] == '[') {
2594 if (name[index] == '[')
2596 else if (name[index] == ']')
2598 } while (braces > 0);
2599 recursive_type = TypeLookup (ec, name.Substring (open + 1, index - open - 1));
2600 if (recursive_type == null || (recursive_type == typeof(UnexpectedType)))
2601 return recursive_type;
2604 if (name[index] == ',')
2606 else if ((name[index] == '.' && !done) || (index == name.Length && name[0] != '[')) {
2607 string substring = name.Substring(dot, index - dot);
2609 if (resolved == null)
2610 resolved = RootNamespace.Global.Lookup (ec.DeclContainer, substring, Location.Null);
2611 else if (resolved is Namespace)
2612 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
2613 else if (type != null)
2614 type = TypeManager.GetNestedType (type, substring);
2618 if (resolved == null)
2620 else if (type == null && resolved is TypeExpr)
2621 type = resolved.Type;
2628 if (name[0] != '[') {
2629 string substring = name.Substring(dot, index - dot);
2632 return TypeManager.GetNestedType (type, substring);
2633 else if (resolved != null) {
2634 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
2635 if (resolved is TypeExpr)
2636 return resolved.Type;
2638 resolved.Error_UnexpectedKind (ec.DeclContainer, "type", loc);
2639 return typeof (UnexpectedType);
2646 return recursive_type;
2649 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2651 Type t = TypeLookup (ec, name);
2652 if (t == null || !ec.DeclContainer.CheckAccessLevel (t)) {
2653 NamespaceEntry.Error_NamespaceNotFound (loc, name);
2656 else if (t == typeof(UnexpectedType))
2662 public override string Name {
2663 get { return name; }
2666 public override string FullName {
2667 get { return name; }
2670 protected override void CloneTo (CloneContext clonectx, Expression target)
2672 // CloneTo: Nothing, we do not keep any state on this expression
2677 /// Represents an "unbound generic type", ie. typeof (Foo<>).
2680 public class UnboundTypeExpression : TypeExpr
2684 public UnboundTypeExpression (MemberName name, Location l)
2690 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2693 if (name.Left != null) {
2694 Expression lexpr = name.Left.GetTypeExpression ();
2695 expr = new MemberAccess (lexpr, name.Basename);
2697 expr = new SimpleName (name.Basename, loc);
2700 FullNamedExpression fne = expr.ResolveAsTypeStep (ec, false);
2705 return new TypeExpression (type, loc);
2708 public override string Name {
2709 get { return name.FullName; }
2712 public override string FullName {
2713 get { return name.FullName; }
2717 public class TypeAliasExpression : TypeExpr {
2718 FullNamedExpression alias;
2723 public TypeAliasExpression (FullNamedExpression alias, TypeArguments args, Location l)
2729 eclass = ExprClass.Type;
2731 name = alias.FullName + "<" + args.ToString () + ">";
2733 name = alias.FullName;
2736 public override string Name {
2737 get { return alias.FullName; }
2740 public override string FullName {
2741 get { return name; }
2744 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2746 texpr = alias.ResolveAsTypeTerminal (ec, false);
2750 Type type = texpr.Type;
2751 int num_args = TypeManager.GetNumberOfTypeArguments (type);
2754 if (num_args == 0) {
2755 Report.Error (308, loc,
2756 "The non-generic type `{0}' cannot " +
2757 "be used with type arguments.",
2758 TypeManager.CSharpName (type));
2762 ConstructedType ctype = new ConstructedType (type, args, loc);
2763 return ctype.ResolveAsTypeTerminal (ec, false);
2764 } else if (num_args > 0) {
2765 Report.Error (305, loc,
2766 "Using the generic type `{0}' " +
2767 "requires {1} type arguments",
2768 TypeManager.CSharpName (type), num_args.ToString ());
2775 public override bool CheckAccessLevel (DeclSpace ds)
2777 return texpr.CheckAccessLevel (ds);
2780 public override bool AsAccessible (DeclSpace ds, int flags)
2782 return texpr.AsAccessible (ds, flags);
2785 public override bool IsClass {
2786 get { return texpr.IsClass; }
2789 public override bool IsValueType {
2790 get { return texpr.IsValueType; }
2793 public override bool IsInterface {
2794 get { return texpr.IsInterface; }
2797 public override bool IsSealed {
2798 get { return texpr.IsSealed; }
2803 /// This class denotes an expression which evaluates to a member
2804 /// of a struct or a class.
2806 public abstract class MemberExpr : Expression
2809 /// The name of this member.
2811 public abstract string Name {
2816 /// Whether this is an instance member.
2818 public abstract bool IsInstance {
2823 /// Whether this is a static member.
2825 public abstract bool IsStatic {
2830 /// The type which declares this member.
2832 public abstract Type DeclaringType {
2837 /// The instance expression associated with this member, if it's a
2838 /// non-static member.
2840 public Expression InstanceExpression;
2842 public static void error176 (Location loc, string name)
2844 Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
2845 "with an instance reference, qualify it with a type name instead", name);
2848 // TODO: possible optimalization
2849 // Cache resolved constant result in FieldBuilder <-> expression map
2850 public virtual Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
2851 SimpleName original)
2855 // original == null || original.Resolve (...) ==> left
2858 if (left is TypeExpr) {
2859 left = left.ResolveAsTypeTerminal (ec, true);
2864 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
2872 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
2875 error176 (loc, GetSignatureForError ());
2879 InstanceExpression = left;
2884 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
2889 if (InstanceExpression == EmptyExpression.Null) {
2890 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
2894 if (InstanceExpression.Type.IsValueType) {
2895 if (InstanceExpression is IMemoryLocation) {
2896 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
2898 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
2899 InstanceExpression.Emit (ec);
2901 t.AddressOf (ec, AddressOp.Store);
2904 InstanceExpression.Emit (ec);
2906 if (prepare_for_load)
2907 ec.ig.Emit (OpCodes.Dup);
2912 /// Represents group of extension methods
2914 public class ExtensionMethodGroupExpr : MethodGroupExpr
2916 NamespaceEntry namespaceEntry;
2918 public ExtensionMethodGroupExpr (ArrayList list, NamespaceEntry n, Type extensionType, Location l)
2921 this.namespaceEntry = n;
2922 this.type = extensionType;
2925 public override bool IsBase {
2926 get { return true; }
2929 public override bool IsStatic {
2930 get { return true; }
2933 public bool IsTopLevel {
2934 get { return namespaceEntry == null; }
2937 public override MethodBase OverloadExtensionResolve (EmitContext ec, ref ArrayList arguments, ref MethodGroupExpr mg,
2938 Expression expr, Location loc)
2940 if (arguments == null)
2941 arguments = new ArrayList (1);
2943 Expression extension_argument = ((MemberAccess)expr).Expr;
2944 if ((extension_argument.eclass & (ExprClass.Value | ExprClass.Variable)) == 0)
2947 Argument a = new Argument (extension_argument);
2948 a.Resolve (ec, loc);
2949 arguments.Insert (0, a);
2953 MethodBase method = mg.OverloadResolve (ec, arguments, true, loc);
2957 ExtensionMethodGroupExpr e = namespaceEntry.LookupExtensionMethod (type, null, Name);
2959 return mg.OverloadResolve (ec, arguments, false, loc);
2962 namespaceEntry = e.namespaceEntry;
2968 /// MethodGroup Expression.
2970 /// This is a fully resolved expression that evaluates to a type
2972 public class MethodGroupExpr : MemberExpr {
2973 public MethodBase [] Methods;
2974 bool has_type_arguments = false;
2975 bool identical_type_name = false;
2978 public MethodGroupExpr (MemberInfo [] mi, Location l)
2980 Methods = new MethodBase [mi.Length];
2981 mi.CopyTo (Methods, 0);
2982 eclass = ExprClass.MethodGroup;
2984 // Set the type to something that will never be useful, which will
2985 // trigger the proper conversions.
2986 type = typeof (MethodGroupExpr);
2990 public MethodGroupExpr (ArrayList list, Location l)
2993 Methods = (MethodBase[])list.ToArray (typeof (MethodBase));
2995 foreach (MemberInfo m in list){
2996 if (!(m is MethodBase)){
2997 Console.WriteLine ("Name " + m.Name);
2998 Console.WriteLine ("Found a: " + m.GetType ().FullName);
3005 eclass = ExprClass.MethodGroup;
3006 type = TypeManager.object_type;
3009 public override Type DeclaringType {
3012 // We assume that the top-level type is in the end
3014 return Methods [Methods.Length - 1].DeclaringType;
3015 //return Methods [0].DeclaringType;
3019 public bool HasTypeArguments {
3021 return has_type_arguments;
3025 has_type_arguments = value;
3029 public bool IdenticalTypeName {
3031 return identical_type_name;
3035 identical_type_name = value;
3039 public virtual bool IsBase {
3048 public override string GetSignatureForError ()
3050 return TypeManager.CSharpSignature (Methods [0]);
3053 public override string Name {
3055 return Methods [0].Name;
3059 public override bool IsInstance {
3061 foreach (MethodBase mb in Methods)
3069 public override bool IsStatic {
3071 foreach (MethodBase mb in Methods)
3080 /// Determines "better conversion" as specified in 14.4.2.3
3082 /// Returns : p if a->p is better,
3083 /// q if a->q is better,
3084 /// null if neither is better
3086 static Type BetterConversion (EmitContext ec, Argument a, Type p, Type q)
3088 Type argument_type = TypeManager.TypeToCoreType (a.Type);
3089 Expression argument_expr = a.Expr;
3091 if (argument_type == null)
3092 throw new Exception ("Expression of type " + a.Expr +
3093 " does not resolve its type");
3095 if (p == null || q == null)
3096 throw new InternalErrorException ("BetterConversion Got a null conversion");
3101 if (argument_expr is NullLiteral)
3104 // If the argument is null and one of the types to compare is 'object' and
3105 // the other is a reference type, we prefer the other.
3107 // This follows from the usual rules:
3108 // * There is an implicit conversion from 'null' to type 'object'
3109 // * There is an implicit conversion from 'null' to any reference type
3110 // * There is an implicit conversion from any reference type to type 'object'
3111 // * There is no implicit conversion from type 'object' to other reference types
3112 // => Conversion of 'null' to a reference type is better than conversion to 'object'
3114 // FIXME: This probably isn't necessary, since the type of a NullLiteral is the
3115 // null type. I think it used to be 'object' and thus needed a special
3116 // case to avoid the immediately following two checks.
3118 if (!p.IsValueType && q == TypeManager.object_type)
3120 if (!q.IsValueType && p == TypeManager.object_type)
3124 if (argument_type == p)
3127 if (argument_type == q)
3130 Expression p_tmp = new EmptyExpression (p);
3131 Expression q_tmp = new EmptyExpression (q);
3133 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3134 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3136 if (p_to_q && !q_to_p)
3139 if (q_to_p && !p_to_q)
3142 if (p == TypeManager.sbyte_type)
3143 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3144 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3146 if (q == TypeManager.sbyte_type)
3147 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3148 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3151 if (p == TypeManager.short_type)
3152 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3153 q == TypeManager.uint64_type)
3155 if (q == TypeManager.short_type)
3156 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3157 p == TypeManager.uint64_type)
3160 if (p == TypeManager.int32_type)
3161 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3163 if (q == TypeManager.int32_type)
3164 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3167 if (p == TypeManager.int64_type)
3168 if (q == TypeManager.uint64_type)
3170 if (q == TypeManager.int64_type)
3171 if (p == TypeManager.uint64_type)
3178 /// Determines "Better function" between candidate
3179 /// and the current best match
3182 /// Returns a boolean indicating :
3183 /// false if candidate ain't better
3184 /// true if candidate is better than the current best match
3186 static bool BetterFunction (EmitContext ec, ArrayList args, int argument_count,
3187 MethodBase candidate, bool candidate_params,
3188 MethodBase best, bool best_params)
3190 ParameterData candidate_pd = TypeManager.GetParameterData (candidate);
3191 ParameterData best_pd = TypeManager.GetParameterData (best);
3193 bool better_at_least_one = false;
3195 for (int j = 0, c_idx = 0, b_idx = 0; j < argument_count; ++j, ++c_idx, ++b_idx)
3197 Argument a = (Argument) args [j];
3199 Type ct = TypeManager.TypeToCoreType (candidate_pd.ParameterType (c_idx));
3200 Type bt = TypeManager.TypeToCoreType (best_pd.ParameterType (b_idx));
3202 if (candidate_params && candidate_pd.ParameterModifier (c_idx) == Parameter.Modifier.PARAMS)
3204 ct = TypeManager.GetElementType (ct);
3208 if (best_params && best_pd.ParameterModifier (b_idx) == Parameter.Modifier.PARAMS)
3210 bt = TypeManager.GetElementType (bt);
3218 Type better = BetterConversion (ec, a, ct, bt);
3220 // for each argument, the conversion to 'ct' should be no worse than
3221 // the conversion to 'bt'.
3225 // for at least one argument, the conversion to 'ct' should be better than
3226 // the conversion to 'bt'.
3228 better_at_least_one = true;
3231 if (better_at_least_one)
3235 // This handles the case
3237 // Add (float f1, float f2, float f3);
3238 // Add (params decimal [] foo);
3240 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3241 // first candidate would've chosen as better.
3247 // The two methods have equal parameter types. Now apply tie-breaking rules
3249 if (TypeManager.IsGenericMethod (best) && !TypeManager.IsGenericMethod (candidate))
3251 if (!TypeManager.IsGenericMethod (best) && TypeManager.IsGenericMethod (candidate))
3255 // This handles the following cases:
3257 // Trim () is better than Trim (params char[] chars)
3258 // Concat (string s1, string s2, string s3) is better than
3259 // Concat (string s1, params string [] srest)
3260 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3262 if (!candidate_params && best_params)
3264 if (candidate_params && !best_params)
3267 int candidate_param_count = candidate_pd.Count;
3268 int best_param_count = best_pd.Count;
3270 if (candidate_param_count != best_param_count)
3271 // can only happen if (candidate_params && best_params)
3272 return candidate_param_count > best_param_count;
3275 // now, both methods have the same number of parameters, and the parameters have the same types
3276 // Pick the "more specific" signature
3279 MethodBase orig_candidate = TypeManager.DropGenericMethodArguments (candidate);
3280 MethodBase orig_best = TypeManager.DropGenericMethodArguments (best);
3282 ParameterData orig_candidate_pd = TypeManager.GetParameterData (orig_candidate);
3283 ParameterData orig_best_pd = TypeManager.GetParameterData (orig_best);
3285 bool specific_at_least_once = false;
3286 for (int j = 0; j < candidate_param_count; ++j)
3288 Type ct = TypeManager.TypeToCoreType (orig_candidate_pd.ParameterType (j));
3289 Type bt = TypeManager.TypeToCoreType (orig_best_pd.ParameterType (j));
3292 Type specific = MoreSpecific (ct, bt);
3296 specific_at_least_once = true;
3299 if (specific_at_least_once)
3302 // FIXME: handle lifted operators
3308 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3309 SimpleName original)
3311 if (!(left is TypeExpr) &&
3312 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3313 IdenticalTypeName = true;
3315 return base.ResolveMemberAccess (ec, left, loc, original);
3318 override public Expression DoResolve (EmitContext ec)
3321 InstanceExpression = null;
3323 if (InstanceExpression != null) {
3324 InstanceExpression = InstanceExpression.DoResolve (ec);
3325 if (InstanceExpression == null)
3332 public void ReportUsageError ()
3334 Report.Error (654, loc, "Method `" + DeclaringType + "." +
3335 Name + "()' is referenced without parentheses");
3338 override public void Emit (EmitContext ec)
3340 ReportUsageError ();
3343 public static bool IsAncestralType (Type first_type, Type second_type)
3345 return first_type != second_type &&
3346 (TypeManager.IsSubclassOf (second_type, first_type) ||
3347 TypeManager.ImplementsInterface (second_type, first_type));
3350 public static bool IsOverride (MethodBase cand_method, MethodBase base_method)
3352 if (!IsAncestralType (base_method.DeclaringType, cand_method.DeclaringType))
3355 ParameterData cand_pd = TypeManager.GetParameterData (cand_method);
3356 ParameterData base_pd = TypeManager.GetParameterData (base_method);
3358 if (cand_pd.Count != base_pd.Count)
3361 for (int j = 0; j < cand_pd.Count; ++j)
3363 Parameter.Modifier cm = cand_pd.ParameterModifier (j);
3364 Parameter.Modifier bm = base_pd.ParameterModifier (j);
3365 Type ct = TypeManager.TypeToCoreType (cand_pd.ParameterType (j));
3366 Type bt = TypeManager.TypeToCoreType (base_pd.ParameterType (j));
3368 if (cm != bm || ct != bt)
3375 static Type MoreSpecific (Type p, Type q)
3377 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
3379 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
3382 if (TypeManager.HasElementType (p))
3384 Type pe = TypeManager.GetElementType (p);
3385 Type qe = TypeManager.GetElementType (q);
3386 Type specific = MoreSpecific (pe, qe);
3392 else if (TypeManager.IsGenericType (p))
3394 Type[] pargs = TypeManager.GetTypeArguments (p);
3395 Type[] qargs = TypeManager.GetTypeArguments (q);
3397 bool p_specific_at_least_once = false;
3398 bool q_specific_at_least_once = false;
3400 for (int i = 0; i < pargs.Length; i++)
3402 Type specific = MoreSpecific (pargs [i], qargs [i]);
3403 if (specific == pargs [i])
3404 p_specific_at_least_once = true;
3405 if (specific == qargs [i])
3406 q_specific_at_least_once = true;
3409 if (p_specific_at_least_once && !q_specific_at_least_once)
3411 if (!p_specific_at_least_once && q_specific_at_least_once)
3418 public virtual MethodBase OverloadExtensionResolve (EmitContext ec, ref ArrayList arguments, ref MethodGroupExpr mg,
3419 Expression expr, Location loc)
3421 MethodBase method = OverloadResolve (ec, arguments, true, loc);
3422 if (method != null) {
3427 MemberAccess mexpr = expr as MemberAccess;
3428 if (mexpr != null) {
3429 ExtensionMethodGroupExpr emg = ec.DeclContainer.LookupExtensionMethod (mexpr.Expr.Type, Name);
3431 return OverloadExtensionResolve (ec, ref arguments, ref mg, expr, loc);
3435 return OverloadResolve (ec, arguments, false, loc);
3439 /// Find the Applicable Function Members (7.4.2.1)
3441 /// me: Method Group expression with the members to select.
3442 /// it might contain constructors or methods (or anything
3443 /// that maps to a method).
3445 /// Arguments: ArrayList containing resolved Argument objects.
3447 /// loc: The location if we want an error to be reported, or a Null
3448 /// location for "probing" purposes.
3450 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3451 /// that is the best match of me on Arguments.
3454 public virtual MethodBase OverloadResolve (EmitContext ec, ArrayList Arguments,
3455 bool may_fail, Location loc)
3457 MethodBase method = null;
3458 bool method_params = false;
3459 Type applicable_type = null;
3461 ArrayList candidates = new ArrayList (2);
3462 ArrayList candidate_overrides = null;
3465 // Used to keep a map between the candidate
3466 // and whether it is being considered in its
3467 // normal or expanded form
3469 // false is normal form, true is expanded form
3471 Hashtable candidate_to_form = null;
3473 if (Arguments != null)
3474 arg_count = Arguments.Count;
3476 if (RootContext.Version == LanguageVersion.ISO_1 && Name == "Invoke" && TypeManager.IsDelegateType (DeclaringType)) {
3478 Report.Error (1533, loc, "Invoke cannot be called directly on a delegate");
3482 int nmethods = Methods.Length;
3486 // Methods marked 'override' don't take part in 'applicable_type'
3487 // computation, nor in the actual overload resolution.
3488 // However, they still need to be emitted instead of a base virtual method.
3489 // So, we salt them away into the 'candidate_overrides' array.
3491 // In case of reflected methods, we replace each overriding method with
3492 // its corresponding base virtual method. This is to improve compatibility
3493 // with non-C# libraries which change the visibility of overrides (#75636)
3496 for (int i = 0; i < Methods.Length; ++i) {
3497 MethodBase m = Methods [i];
3499 Type [] gen_args = null;
3500 if (m.IsGenericMethod && !m.IsGenericMethodDefinition)
3501 gen_args = m.GetGenericArguments ();
3503 if (TypeManager.IsOverride (m)) {
3504 if (candidate_overrides == null)
3505 candidate_overrides = new ArrayList ();
3506 candidate_overrides.Add (m);
3507 m = TypeManager.TryGetBaseDefinition (m);
3509 if (m != null && gen_args != null) {
3510 if (!m.IsGenericMethodDefinition)
3511 throw new InternalErrorException ("GetBaseDefinition didn't return a GenericMethodDefinition");
3512 m = ((MethodInfo) m).MakeGenericMethod (gen_args);
3522 int applicable_errors = Report.Errors;
3525 // First we construct the set of applicable methods
3527 bool is_sorted = true;
3528 for (int i = 0; i < nmethods; i++) {
3529 Type decl_type = Methods [i].DeclaringType;
3532 // If we have already found an applicable method
3533 // we eliminate all base types (Section 14.5.5.1)
3535 if (applicable_type != null && IsAncestralType (decl_type, applicable_type))
3539 // Check if candidate is applicable (section 14.4.2.1)
3540 // Is candidate applicable in normal form?
3542 bool is_applicable = Invocation.IsApplicable (ec, this, Arguments, arg_count, ref Methods [i]);
3544 if (!is_applicable && Invocation.IsParamsMethodApplicable (ec, this, Arguments, arg_count, ref Methods [i])) {
3545 MethodBase candidate = Methods [i];
3546 if (candidate_to_form == null)
3547 candidate_to_form = new PtrHashtable ();
3548 candidate_to_form [candidate] = candidate;
3549 // Candidate is applicable in expanded form
3550 is_applicable = true;
3556 candidates.Add (Methods [i]);
3558 if (applicable_type == null)
3559 applicable_type = decl_type;
3560 else if (applicable_type != decl_type) {
3562 if (IsAncestralType (applicable_type, decl_type))
3563 applicable_type = decl_type;
3567 if (applicable_errors != Report.Errors)
3570 int candidate_top = candidates.Count;
3572 if (applicable_type == null) {
3574 // Okay so we have failed to find anything so we
3575 // return by providing info about the closest match
3577 int errors = Report.Errors;
3578 for (int i = 0; i < nmethods; ++i) {
3579 MethodBase c = Methods [i];
3580 ParameterData pd = TypeManager.GetParameterData (c);
3582 if (pd.Count != arg_count)
3586 if (!TypeManager.InferTypeArguments (ec, Arguments, ref c))
3588 if (TypeManager.IsGenericMethodDefinition (c))
3592 Invocation.VerifyArgumentsCompat (ec, Arguments, arg_count,
3593 c, false, null, may_fail, loc);
3595 if (!may_fail && errors == Report.Errors){
3597 throw new InternalErrorException (
3598 "VerifyArgumentsCompat and IsApplicable do not agree; " +
3599 "likely reason: ImplicitConversion and ImplicitConversionExists have gone out of sync");
3605 if (!may_fail && errors == Report.Errors) {
3606 string report_name = Name;
3607 if (report_name == ".ctor")
3608 report_name = TypeManager.CSharpName (DeclaringType);
3614 for (int i = 0; i < Methods.Length; ++i) {
3615 MethodBase c = Methods [i];
3616 ParameterData pd = TypeManager.GetParameterData (c);
3618 if (pd.Count != arg_count)
3621 if (TypeManager.InferTypeArguments (ec, Arguments, ref c))
3625 411, loc, "The type arguments for " +
3626 "method `{0}' cannot be inferred from " +
3627 "the usage. Try specifying the type " +
3628 "arguments explicitly.", report_name);
3633 Invocation.Error_WrongNumArguments (loc, report_name, arg_count);
3641 // At this point, applicable_type is _one_ of the most derived types
3642 // in the set of types containing the methods in this MethodGroup.
3643 // Filter the candidates so that they only contain methods from the
3644 // most derived types.
3647 int finalized = 0; // Number of finalized candidates
3650 // Invariant: applicable_type is a most derived type
3652 // We'll try to complete Section 14.5.5.1 for 'applicable_type' by
3653 // eliminating all it's base types. At the same time, we'll also move
3654 // every unrelated type to the end of the array, and pick the next
3655 // 'applicable_type'.
3657 Type next_applicable_type = null;
3658 int j = finalized; // where to put the next finalized candidate
3659 int k = finalized; // where to put the next undiscarded candidate
3660 for (int i = finalized; i < candidate_top; ++i) {
3661 MethodBase candidate = (MethodBase) candidates [i];
3662 Type decl_type = candidate.DeclaringType;
3664 if (decl_type == applicable_type) {
3665 candidates [k++] = candidates [j];
3666 candidates [j++] = candidates [i];
3670 if (IsAncestralType (decl_type, applicable_type))
3673 if (next_applicable_type != null &&
3674 IsAncestralType (decl_type, next_applicable_type))
3677 candidates [k++] = candidates [i];
3679 if (next_applicable_type == null ||
3680 IsAncestralType (next_applicable_type, decl_type))
3681 next_applicable_type = decl_type;
3684 applicable_type = next_applicable_type;
3687 } while (applicable_type != null);
3691 // Now we actually find the best method
3694 method = (MethodBase) candidates [0];
3695 method_params = candidate_to_form != null && candidate_to_form.Contains (method);
3696 for (int ix = 1; ix < candidate_top; ix++) {
3697 MethodBase candidate = (MethodBase) candidates [ix];
3699 if (candidate == method)
3702 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
3704 if (BetterFunction (ec, Arguments, arg_count,
3705 candidate, cand_params,
3706 method, method_params)) {
3708 method_params = cand_params;
3712 // Now check that there are no ambiguities i.e the selected method
3713 // should be better than all the others
3715 MethodBase ambiguous = null;
3716 for (int ix = 0; ix < candidate_top; ix++) {
3717 MethodBase candidate = (MethodBase) candidates [ix];
3719 if (candidate == method)
3722 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
3723 if (!BetterFunction (ec, Arguments, arg_count,
3724 method, method_params,
3725 candidate, cand_params))
3728 Report.SymbolRelatedToPreviousError (candidate);
3729 ambiguous = candidate;
3733 if (ambiguous != null) {
3734 Report.SymbolRelatedToPreviousError (method);
3735 Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
3736 TypeManager.CSharpSignature (ambiguous), TypeManager.CSharpSignature (method));
3741 // If the method is a virtual function, pick an override closer to the LHS type.
3743 if (!IsBase && method.IsVirtual) {
3744 if (TypeManager.IsOverride (method))
3745 throw new InternalErrorException (
3746 "Should not happen. An 'override' method took part in overload resolution: " + method);
3748 if (candidate_overrides != null)
3749 foreach (MethodBase candidate in candidate_overrides) {
3750 if (IsOverride (candidate, method))
3756 // And now check if the arguments are all
3757 // compatible, perform conversions if
3758 // necessary etc. and return if everything is
3761 if (!Invocation.VerifyArgumentsCompat (ec, Arguments, arg_count, method,
3762 method_params, null, may_fail, loc))
3768 MethodBase the_method = TypeManager.DropGenericMethodArguments (method);
3770 if (the_method.IsGenericMethodDefinition &&
3771 !ConstraintChecker.CheckConstraints (ec, the_method, method, loc))
3775 IMethodData data = TypeManager.GetMethod (the_method);
3777 data.SetMemberIsUsed ();
3783 bool RemoveMethods (bool keep_static)
3785 ArrayList smethods = new ArrayList ();
3787 foreach (MethodBase mb in Methods){
3788 if (mb.IsStatic == keep_static)
3792 if (smethods.Count == 0)
3795 Methods = new MethodBase [smethods.Count];
3796 smethods.CopyTo (Methods, 0);
3802 /// Removes any instance methods from the MethodGroup, returns
3803 /// false if the resulting set is empty.
3805 public bool RemoveInstanceMethods ()
3807 return RemoveMethods (true);
3811 /// Removes any static methods from the MethodGroup, returns
3812 /// false if the resulting set is empty.
3814 public bool RemoveStaticMethods ()
3816 return RemoveMethods (false);
3819 public Expression ResolveGeneric (EmitContext ec, TypeArguments args)
3822 if (!args.Resolve (ec))
3825 Type[] atypes = args.Arguments;
3827 int first_count = 0;
3828 MethodInfo first = null;
3830 ArrayList list = new ArrayList ();
3831 foreach (MethodBase mb in Methods) {
3832 MethodInfo mi = mb as MethodInfo;
3833 if ((mi == null) || !mb.IsGenericMethod)
3836 Type[] gen_params = mb.GetGenericArguments ();
3838 if (first == null) {
3840 first_count = gen_params.Length;
3843 if (gen_params.Length != atypes.Length)
3846 mi = mi.MakeGenericMethod (atypes);
3850 // MS implementation throws NotSupportedException for GetParameters
3851 // on unbaked generic method
3852 Parameters p = ((Parameters)TypeManager.GetParameterData (mi)).Clone ();
3853 p.InflateTypes (gen_params, atypes);
3854 TypeManager.RegisterMethod (mi, p);
3858 if (list.Count > 0) {
3859 MethodGroupExpr new_mg = new MethodGroupExpr (list, Location);
3860 new_mg.InstanceExpression = InstanceExpression;
3861 new_mg.HasTypeArguments = true;
3862 new_mg.IsBase = IsBase;
3866 if (first != null) {
3867 Report.SymbolRelatedToPreviousError (first);
3869 305, loc, "Using the generic method `{0}' requires `{1}' type arguments",
3870 TypeManager.CSharpSignature (first), first_count.ToString ());
3873 308, loc, "The non-generic method `{0}' " +
3874 "cannot be used with type arguments", Name);
3878 throw new NotImplementedException ();
3884 /// Fully resolved expression that evaluates to a Field
3886 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariable {
3887 public readonly FieldInfo FieldInfo;
3888 VariableInfo variable_info;
3890 LocalTemporary temp;
3892 bool in_initializer;
3894 public FieldExpr (FieldInfo fi, Location l, bool in_initializer):
3897 this.in_initializer = in_initializer;
3900 public FieldExpr (FieldInfo fi, Location l)
3903 eclass = ExprClass.Variable;
3904 type = TypeManager.TypeToCoreType (fi.FieldType);
3908 public override string Name {
3910 return FieldInfo.Name;
3914 public override bool IsInstance {
3916 return !FieldInfo.IsStatic;
3920 public override bool IsStatic {
3922 return FieldInfo.IsStatic;
3926 public override Type DeclaringType {
3928 return FieldInfo.DeclaringType;
3932 public override string GetSignatureForError ()
3934 return TypeManager.GetFullNameSignature (FieldInfo);
3937 public VariableInfo VariableInfo {
3939 return variable_info;
3943 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3944 SimpleName original)
3946 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
3948 Type t = fi.FieldType;
3950 if (fi.IsLiteral || (fi.IsInitOnly && t == TypeManager.decimal_type)) {
3951 IConstant ic = TypeManager.GetConstant (fi);
3954 ic = new ExternalConstant (fi);
3956 ic = ExternalConstant.CreateDecimal (fi);
3958 return base.ResolveMemberAccess (ec, left, loc, original);
3961 TypeManager.RegisterConstant (fi, ic);
3964 bool left_is_type = left is TypeExpr;
3965 if (!left_is_type && (original == null || !original.IdenticalNameAndTypeName (ec, left, loc))) {
3966 Report.SymbolRelatedToPreviousError (FieldInfo);
3967 error176 (loc, TypeManager.GetFullNameSignature (FieldInfo));
3971 if (ic.ResolveValue ()) {
3972 if (!ec.IsInObsoleteScope)
3973 ic.CheckObsoleteness (loc);
3976 return ic.CreateConstantReference (loc);
3979 if (t.IsPointer && !ec.InUnsafe) {
3984 return base.ResolveMemberAccess (ec, left, loc, original);
3987 override public Expression DoResolve (EmitContext ec)
3989 return DoResolve (ec, false, false);
3992 Expression DoResolve (EmitContext ec, bool lvalue_instance, bool out_access)
3994 if (!FieldInfo.IsStatic){
3995 if (InstanceExpression == null){
3997 // This can happen when referencing an instance field using
3998 // a fully qualified type expression: TypeName.InstanceField = xxx
4000 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4004 // Resolve the field's instance expression while flow analysis is turned
4005 // off: when accessing a field "a.b", we must check whether the field
4006 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4008 if (lvalue_instance) {
4009 using (ec.With (EmitContext.Flags.DoFlowAnalysis, false)) {
4010 Expression right_side =
4011 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4012 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side, loc);
4015 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
4016 InstanceExpression = InstanceExpression.Resolve (ec, rf);
4019 if (InstanceExpression == null)
4022 InstanceExpression.CheckMarshalByRefAccess ();
4025 if (!in_initializer && !ec.IsFieldInitializer) {
4026 ObsoleteAttribute oa;
4027 FieldBase f = TypeManager.GetField (FieldInfo);
4029 if (!ec.IsInObsoleteScope)
4030 f.CheckObsoleteness (loc);
4032 // To be sure that type is external because we do not register generated fields
4033 } else if (!(FieldInfo.DeclaringType is TypeBuilder)) {
4034 oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
4036 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
4040 AnonymousContainer am = ec.CurrentAnonymousMethod;
4042 if (!FieldInfo.IsStatic){
4043 if (!am.IsIterator && (ec.TypeContainer is Struct)){
4044 Report.Error (1673, loc,
4045 "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",
4052 // If the instance expression is a local variable or parameter.
4053 IVariable var = InstanceExpression as IVariable;
4054 if ((var == null) || (var.VariableInfo == null))
4057 VariableInfo vi = var.VariableInfo;
4058 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
4061 variable_info = vi.GetSubStruct (FieldInfo.Name);
4065 static readonly int [] codes = {
4066 191, // instance, write access
4067 192, // instance, out access
4068 198, // static, write access
4069 199, // static, out access
4070 1648, // member of value instance, write access
4071 1649, // member of value instance, out access
4072 1650, // member of value static, write access
4073 1651 // member of value static, out access
4076 static readonly string [] msgs = {
4077 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4078 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4079 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4080 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4081 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4082 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4083 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4084 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4087 // The return value is always null. Returning a value simplifies calling code.
4088 Expression Report_AssignToReadonly (Expression right_side)
4091 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4095 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4097 Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4102 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4104 IVariable var = InstanceExpression as IVariable;
4105 if ((var != null) && (var.VariableInfo != null))
4106 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
4108 bool lvalue_instance = !FieldInfo.IsStatic && FieldInfo.DeclaringType.IsValueType;
4109 bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
4111 Expression e = DoResolve (ec, lvalue_instance, out_access);
4116 FieldBase fb = TypeManager.GetField (FieldInfo);
4120 if (FieldInfo.IsInitOnly) {
4121 // InitOnly fields can only be assigned in constructors or initializers
4122 if (!ec.IsFieldInitializer && !ec.IsConstructor)
4123 return Report_AssignToReadonly (right_side);
4125 if (ec.IsConstructor) {
4126 Type ctype = ec.TypeContainer.CurrentType;
4128 ctype = ec.ContainerType;
4130 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4131 if (!TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
4132 return Report_AssignToReadonly (right_side);
4133 // static InitOnly fields cannot be assigned-to in an instance constructor
4134 if (IsStatic && !ec.IsStatic)
4135 return Report_AssignToReadonly (right_side);
4136 // instance constructors can't modify InitOnly fields of other instances of the same type
4137 if (!IsStatic && !(InstanceExpression is This))
4138 return Report_AssignToReadonly (right_side);
4142 if (right_side == EmptyExpression.OutAccess &&
4143 !IsStatic && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
4144 Report.SymbolRelatedToPreviousError (DeclaringType);
4145 Report.Warning (197, 1, loc,
4146 "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",
4147 GetSignatureForError ());
4153 public override void CheckMarshalByRefAccess ()
4155 if (!IsStatic && Type.IsValueType && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
4156 Report.SymbolRelatedToPreviousError (DeclaringType);
4157 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",
4158 GetSignatureForError ());
4162 public bool VerifyFixed ()
4164 IVariable variable = InstanceExpression as IVariable;
4165 // A variable of the form V.I is fixed when V is a fixed variable of a struct type.
4166 // We defer the InstanceExpression check after the variable check to avoid a
4167 // separate null check on InstanceExpression.
4168 return variable != null && InstanceExpression.Type.IsValueType && variable.VerifyFixed ();
4171 public override int GetHashCode ()
4173 return FieldInfo.GetHashCode ();
4176 public override bool Equals (object obj)
4178 FieldExpr fe = obj as FieldExpr;
4182 if (FieldInfo != fe.FieldInfo)
4185 if (InstanceExpression == null || fe.InstanceExpression == null)
4188 return InstanceExpression.Equals (fe.InstanceExpression);
4191 public void Emit (EmitContext ec, bool leave_copy)
4193 ILGenerator ig = ec.ig;
4194 bool is_volatile = false;
4196 FieldBase f = TypeManager.GetField (FieldInfo);
4198 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4201 f.SetMemberIsUsed ();
4204 if (FieldInfo.IsStatic){
4206 ig.Emit (OpCodes.Volatile);
4208 ig.Emit (OpCodes.Ldsfld, FieldInfo);
4211 EmitInstance (ec, false);
4214 ig.Emit (OpCodes.Volatile);
4216 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
4219 ig.Emit (OpCodes.Ldflda, FieldInfo);
4220 ig.Emit (OpCodes.Ldflda, ff.Element);
4223 ig.Emit (OpCodes.Ldfld, FieldInfo);
4228 ec.ig.Emit (OpCodes.Dup);
4229 if (!FieldInfo.IsStatic) {
4230 temp = new LocalTemporary (this.Type);
4236 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4238 FieldAttributes fa = FieldInfo.Attributes;
4239 bool is_static = (fa & FieldAttributes.Static) != 0;
4240 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
4241 ILGenerator ig = ec.ig;
4242 prepared = prepare_for_load;
4244 if (is_readonly && !ec.IsConstructor){
4245 Report_AssignToReadonly (source);
4249 EmitInstance (ec, prepare_for_load);
4253 ec.ig.Emit (OpCodes.Dup);
4254 if (!FieldInfo.IsStatic) {
4255 temp = new LocalTemporary (this.Type);
4260 FieldBase f = TypeManager.GetField (FieldInfo);
4262 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4263 ig.Emit (OpCodes.Volatile);
4269 ig.Emit (OpCodes.Stsfld, FieldInfo);
4271 ig.Emit (OpCodes.Stfld, FieldInfo);
4279 public override void Emit (EmitContext ec)
4284 public void AddressOf (EmitContext ec, AddressOp mode)
4286 ILGenerator ig = ec.ig;
4288 FieldBase f = TypeManager.GetField (FieldInfo);
4290 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
4291 Report.Warning (420, 1, loc, "`{0}': A volatile fields cannot be passed using a ref or out parameter",
4292 f.GetSignatureForError ());
4296 if ((mode & AddressOp.Store) != 0)
4298 if ((mode & AddressOp.Load) != 0)
4299 f.SetMemberIsUsed ();
4303 // Handle initonly fields specially: make a copy and then
4304 // get the address of the copy.
4307 if (FieldInfo.IsInitOnly){
4309 if (ec.IsConstructor){
4310 if (FieldInfo.IsStatic){
4322 local = ig.DeclareLocal (type);
4323 ig.Emit (OpCodes.Stloc, local);
4324 ig.Emit (OpCodes.Ldloca, local);
4329 if (FieldInfo.IsStatic){
4330 ig.Emit (OpCodes.Ldsflda, FieldInfo);
4333 EmitInstance (ec, false);
4334 ig.Emit (OpCodes.Ldflda, FieldInfo);
4340 // A FieldExpr whose address can not be taken
4342 public class FieldExprNoAddress : FieldExpr, IMemoryLocation {
4343 public FieldExprNoAddress (FieldInfo fi, Location loc) : base (fi, loc)
4347 public new void AddressOf (EmitContext ec, AddressOp mode)
4349 Report.Error (-215, "Report this: Taking the address of a remapped parameter not supported");
4354 /// Expression that evaluates to a Property. The Assign class
4355 /// might set the `Value' expression if we are in an assignment.
4357 /// This is not an LValue because we need to re-write the expression, we
4358 /// can not take data from the stack and store it.
4360 public class PropertyExpr : MemberExpr, IAssignMethod {
4361 public readonly PropertyInfo PropertyInfo;
4364 // This is set externally by the `BaseAccess' class
4367 MethodInfo getter, setter;
4372 LocalTemporary temp;
4375 public PropertyExpr (Type containerType, PropertyInfo pi, Location l)
4378 eclass = ExprClass.PropertyAccess;
4382 type = TypeManager.TypeToCoreType (pi.PropertyType);
4384 ResolveAccessors (containerType);
4387 public override string Name {
4389 return PropertyInfo.Name;
4393 public override bool IsInstance {
4399 public override bool IsStatic {
4405 public override Type DeclaringType {
4407 return PropertyInfo.DeclaringType;
4411 public override string GetSignatureForError ()
4413 return TypeManager.GetFullNameSignature (PropertyInfo);
4416 void FindAccessors (Type invocation_type)
4418 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
4419 BindingFlags.Static | BindingFlags.Instance |
4420 BindingFlags.DeclaredOnly;
4422 Type current = PropertyInfo.DeclaringType;
4423 for (; current != null; current = current.BaseType) {
4424 MemberInfo[] group = TypeManager.MemberLookup (
4425 invocation_type, invocation_type, current,
4426 MemberTypes.Property, flags, PropertyInfo.Name, null);
4431 if (group.Length != 1)
4432 // Oooops, can this ever happen ?
4435 PropertyInfo pi = (PropertyInfo) group [0];
4438 getter = pi.GetGetMethod (true);
4441 setter = pi.GetSetMethod (true);
4443 MethodInfo accessor = getter != null ? getter : setter;
4445 if (!accessor.IsVirtual)
4451 // We also perform the permission checking here, as the PropertyInfo does not
4452 // hold the information for the accessibility of its setter/getter
4454 // TODO: Refactor to use some kind of cache together with GetPropertyFromAccessor
4455 void ResolveAccessors (Type containerType)
4457 FindAccessors (containerType);
4459 if (getter != null) {
4460 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
4461 IMethodData md = TypeManager.GetMethod (the_getter);
4463 md.SetMemberIsUsed ();
4465 is_static = getter.IsStatic;
4468 if (setter != null) {
4469 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
4470 IMethodData md = TypeManager.GetMethod (the_setter);
4472 md.SetMemberIsUsed ();
4474 is_static = setter.IsStatic;
4478 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
4481 InstanceExpression = null;
4485 if (InstanceExpression == null) {
4486 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4490 InstanceExpression = InstanceExpression.DoResolve (ec);
4491 if (lvalue_instance && InstanceExpression != null)
4492 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
4494 if (InstanceExpression == null)
4497 InstanceExpression.CheckMarshalByRefAccess ();
4499 if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) &&
4500 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
4501 !TypeManager.IsNestedChildOf (ec.ContainerType, InstanceExpression.Type) &&
4502 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.ContainerType)) {
4503 Report.SymbolRelatedToPreviousError (PropertyInfo);
4504 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
4511 void Error_PropertyNotFound (MethodInfo mi, bool getter)
4513 // TODO: correctly we should compare arguments but it will lead to bigger changes
4514 if (mi is MethodBuilder) {
4515 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
4519 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
4521 ParameterData iparams = TypeManager.GetParameterData (mi);
4522 sig.Append (getter ? "get_" : "set_");
4524 sig.Append (iparams.GetSignatureForError ());
4526 Report.SymbolRelatedToPreviousError (mi);
4527 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
4528 Name, sig.ToString ());
4531 override public Expression DoResolve (EmitContext ec)
4536 if (getter != null){
4537 if (TypeManager.GetParameterData (getter).Count != 0){
4538 Error_PropertyNotFound (getter, true);
4543 if (getter == null){
4545 // The following condition happens if the PropertyExpr was
4546 // created, but is invalid (ie, the property is inaccessible),
4547 // and we did not want to embed the knowledge about this in
4548 // the caller routine. This only avoids double error reporting.
4553 if (InstanceExpression != EmptyExpression.Null) {
4554 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
4555 TypeManager.GetFullNameSignature (PropertyInfo));
4560 bool must_do_cs1540_check = false;
4561 if (getter != null &&
4562 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
4563 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
4564 if (pm != null && pm.HasCustomAccessModifier) {
4565 Report.SymbolRelatedToPreviousError (pm);
4566 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
4567 TypeManager.CSharpSignature (getter));
4570 Report.SymbolRelatedToPreviousError (getter);
4571 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
4576 if (!InstanceResolve (ec, false, must_do_cs1540_check))
4580 // Only base will allow this invocation to happen.
4582 if (IsBase && getter.IsAbstract) {
4583 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
4587 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
4597 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4599 if (right_side == EmptyExpression.OutAccess) {
4600 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
4601 GetSignatureForError ());
4605 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
4606 Report.Error (1612, loc, "Cannot modify the return value of `{0}' because it is not a variable",
4607 GetSignatureForError ());
4611 if (setter == null){
4613 // The following condition happens if the PropertyExpr was
4614 // created, but is invalid (ie, the property is inaccessible),
4615 // and we did not want to embed the knowledge about this in
4616 // the caller routine. This only avoids double error reporting.
4620 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
4621 GetSignatureForError ());
4625 if (TypeManager.GetParameterData (setter).Count != 1){
4626 Error_PropertyNotFound (setter, false);
4630 bool must_do_cs1540_check;
4631 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
4632 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
4633 if (pm != null && pm.HasCustomAccessModifier) {
4634 Report.SymbolRelatedToPreviousError (pm);
4635 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
4636 TypeManager.CSharpSignature (setter));
4639 Report.SymbolRelatedToPreviousError (setter);
4640 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
4645 if (!InstanceResolve (ec, PropertyInfo.DeclaringType.IsValueType, must_do_cs1540_check))
4649 // Only base will allow this invocation to happen.
4651 if (IsBase && setter.IsAbstract){
4652 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
4659 public override void Emit (EmitContext ec)
4664 public void Emit (EmitContext ec, bool leave_copy)
4667 // Special case: length of single dimension array property is turned into ldlen
4669 if ((getter == TypeManager.system_int_array_get_length) ||
4670 (getter == TypeManager.int_array_get_length)){
4671 Type iet = InstanceExpression.Type;
4674 // System.Array.Length can be called, but the Type does not
4675 // support invoking GetArrayRank, so test for that case first
4677 if (iet != TypeManager.array_type && (iet.GetArrayRank () == 1)) {
4679 EmitInstance (ec, false);
4680 ec.ig.Emit (OpCodes.Ldlen);
4681 ec.ig.Emit (OpCodes.Conv_I4);
4686 Invocation.EmitCall (ec, IsBase, IsStatic, InstanceExpression, getter, null, loc, prepared, false);
4689 ec.ig.Emit (OpCodes.Dup);
4691 temp = new LocalTemporary (this.Type);
4698 // Implements the IAssignMethod interface for assignments
4700 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4702 Expression my_source = source;
4704 prepared = prepare_for_load;
4709 ec.ig.Emit (OpCodes.Dup);
4711 temp = new LocalTemporary (this.Type);
4715 } else if (leave_copy) {
4718 temp = new LocalTemporary (this.Type);
4724 ArrayList args = new ArrayList (1);
4725 args.Add (new Argument (my_source, Argument.AType.Expression));
4727 Invocation.EmitCall (ec, IsBase, IsStatic, InstanceExpression, setter, args, loc, false, prepared);
4737 /// Fully resolved expression that evaluates to an Event
4739 public class EventExpr : MemberExpr {
4740 public readonly EventInfo EventInfo;
4743 MethodInfo add_accessor, remove_accessor;
4745 public EventExpr (EventInfo ei, Location loc)
4749 eclass = ExprClass.EventAccess;
4751 add_accessor = TypeManager.GetAddMethod (ei);
4752 remove_accessor = TypeManager.GetRemoveMethod (ei);
4753 if (add_accessor.IsStatic || remove_accessor.IsStatic)
4756 if (EventInfo is MyEventBuilder){
4757 MyEventBuilder eb = (MyEventBuilder) EventInfo;
4758 type = eb.EventType;
4761 type = EventInfo.EventHandlerType;
4764 public override string Name {
4766 return EventInfo.Name;
4770 public override bool IsInstance {
4776 public override bool IsStatic {
4782 public override Type DeclaringType {
4784 return EventInfo.DeclaringType;
4788 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
4789 SimpleName original)
4792 // If the event is local to this class, we transform ourselves into a FieldExpr
4795 if (EventInfo.DeclaringType == ec.ContainerType ||
4796 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
4797 EventField mi = TypeManager.GetEventField (EventInfo);
4800 if (!ec.IsInObsoleteScope)
4801 mi.CheckObsoleteness (loc);
4803 FieldExpr ml = new FieldExpr (mi.FieldBuilder, loc);
4805 InstanceExpression = null;
4807 return ml.ResolveMemberAccess (ec, left, loc, original);
4811 return base.ResolveMemberAccess (ec, left, loc, original);
4815 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
4818 InstanceExpression = null;
4822 if (InstanceExpression == null) {
4823 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4827 InstanceExpression = InstanceExpression.DoResolve (ec);
4828 if (InstanceExpression == null)
4832 // This is using the same mechanism as the CS1540 check in PropertyExpr.
4833 // However, in the Event case, we reported a CS0122 instead.
4835 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
4836 InstanceExpression.Type != ec.ContainerType &&
4837 ec.ContainerType.IsSubclassOf (InstanceExpression.Type)) {
4838 Report.SymbolRelatedToPreviousError (EventInfo);
4839 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
4846 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
4848 return DoResolve (ec);
4851 public override Expression DoResolve (EmitContext ec)
4853 bool must_do_cs1540_check;
4854 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
4855 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
4856 Report.SymbolRelatedToPreviousError (EventInfo);
4857 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
4861 if (!InstanceResolve (ec, must_do_cs1540_check))
4867 public override void Emit (EmitContext ec)
4869 if (InstanceExpression is This)
4870 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of += or -=", GetSignatureForError ());
4872 Report.Error (70, loc, "The event `{0}' can only appear on the left hand side of += or -= "+
4873 "(except on the defining type)", Name);
4876 public override string GetSignatureForError ()
4878 return TypeManager.CSharpSignature (EventInfo);
4881 public void EmitAddOrRemove (EmitContext ec, Expression source)
4883 BinaryDelegate source_del = source as BinaryDelegate;
4884 if (source_del == null) {
4888 Expression handler = source_del.Right;
4890 Argument arg = new Argument (handler, Argument.AType.Expression);
4891 ArrayList args = new ArrayList ();
4895 if (source_del.IsAddition)
4896 Invocation.EmitCall (
4897 ec, false, IsStatic, InstanceExpression, add_accessor, args, loc);
4899 Invocation.EmitCall (
4900 ec, false, IsStatic, InstanceExpression, remove_accessor, args, loc);
4904 public class TemporaryVariable : Expression, IMemoryLocation
4909 public TemporaryVariable (Type type, Location loc)
4913 eclass = ExprClass.Value;
4916 public override Expression DoResolve (EmitContext ec)
4921 TypeExpr te = new TypeExpression (type, loc);
4922 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
4923 if (!li.Resolve (ec))
4926 if (ec.MustCaptureVariable (li)) {
4927 ScopeInfo scope = li.Block.CreateScopeInfo ();
4928 var = scope.AddLocal (li);
4935 public Variable Variable {
4936 get { return var != null ? var : li.Variable; }
4939 public override void Emit (EmitContext ec)
4941 Variable.EmitInstance (ec);
4945 public void EmitLoadAddress (EmitContext ec)
4947 Variable.EmitInstance (ec);
4948 Variable.EmitAddressOf (ec);
4951 public void Store (EmitContext ec, Expression right_side)
4953 Variable.EmitInstance (ec);
4954 right_side.Emit (ec);
4955 Variable.EmitAssign (ec);
4958 public void EmitThis (EmitContext ec)
4960 Variable.EmitInstance (ec);
4963 public void EmitStore (EmitContext ec)
4965 Variable.EmitAssign (ec);
4968 public void AddressOf (EmitContext ec, AddressOp mode)
4970 EmitLoadAddress (ec);
4974 public sealed class VarExpr : Expression
4976 public bool Handled;
4977 public VarExpr (Location loc)
4982 public override Expression DoResolve (EmitContext ec)
4987 public override void Emit (EmitContext ec)