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)
2375 throw new InternalErrorException ("The resolve phase was not executed");
2378 public override string ToString ()
2383 public override string GetSignatureForError ()
2388 protected override void CloneTo (CloneContext clonectx, Expression target)
2390 // CloneTo: Nothing, we do not keep any state on this expression
2395 /// Represents a namespace or a type. The name of the class was inspired by
2396 /// section 10.8.1 (Fully Qualified Names).
2398 public abstract class FullNamedExpression : Expression {
2399 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2404 public abstract string FullName {
2410 /// Expression that evaluates to a type
2412 public abstract class TypeExpr : FullNamedExpression {
2413 override public FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2415 TypeExpr t = DoResolveAsTypeStep (ec);
2419 eclass = ExprClass.Type;
2423 override public Expression DoResolve (EmitContext ec)
2425 return ResolveAsTypeTerminal (ec, false);
2428 override public void Emit (EmitContext ec)
2430 throw new Exception ("Should never be called");
2433 public virtual bool CheckAccessLevel (DeclSpace ds)
2435 return ds.CheckAccessLevel (Type);
2438 public virtual bool AsAccessible (DeclSpace ds, int flags)
2440 return ds.AsAccessible (Type, flags);
2443 public virtual bool IsClass {
2444 get { return Type.IsClass; }
2447 public virtual bool IsValueType {
2448 get { return Type.IsValueType; }
2451 public virtual bool IsInterface {
2452 get { return Type.IsInterface; }
2455 public virtual bool IsSealed {
2456 get { return Type.IsSealed; }
2459 public virtual bool CanInheritFrom ()
2461 if (Type == TypeManager.enum_type ||
2462 (Type == TypeManager.value_type && RootContext.StdLib) ||
2463 Type == TypeManager.multicast_delegate_type ||
2464 Type == TypeManager.delegate_type ||
2465 Type == TypeManager.array_type)
2471 protected abstract TypeExpr DoResolveAsTypeStep (IResolveContext ec);
2473 public abstract string Name {
2477 public override bool Equals (object obj)
2479 TypeExpr tobj = obj as TypeExpr;
2483 return Type == tobj.Type;
2486 public override int GetHashCode ()
2488 return Type.GetHashCode ();
2491 public override string ToString ()
2498 /// Fully resolved Expression that already evaluated to a type
2500 public class TypeExpression : TypeExpr {
2501 public TypeExpression (Type t, Location l)
2504 eclass = ExprClass.Type;
2508 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2513 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2518 public override string Name {
2519 get { return Type.ToString (); }
2522 public override string FullName {
2523 get { return Type.FullName; }
2528 /// Used to create types from a fully qualified name. These are just used
2529 /// by the parser to setup the core types. A TypeLookupExpression is always
2530 /// classified as a type.
2532 public sealed class TypeLookupExpression : TypeExpr {
2533 readonly string name;
2535 public TypeLookupExpression (string name)
2538 eclass = ExprClass.Type;
2541 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2543 // It's null for corlib compilation only
2545 return DoResolveAsTypeStep (ec);
2550 private class UnexpectedType
2554 // This performes recursive type lookup, providing support for generic types.
2555 // For example, given the type:
2557 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]]
2559 // The types will be checked in the following order:
2562 // System.Collections |
2563 // System.Collections.Generic |
2565 // System | recursive call 1 |
2566 // System.Int32 _| | main method call
2568 // System | recursive call 2 |
2569 // System.String _| |
2571 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]] _|
2573 private Type TypeLookup (IResolveContext ec, string name)
2578 FullNamedExpression resolved = null;
2580 Type recursive_type = null;
2581 while (index < name.Length) {
2582 if (name[index] == '[') {
2587 if (name[index] == '[')
2589 else if (name[index] == ']')
2591 } while (braces > 0);
2592 recursive_type = TypeLookup (ec, name.Substring (open + 1, index - open - 1));
2593 if (recursive_type == null || (recursive_type == typeof(UnexpectedType)))
2594 return recursive_type;
2597 if (name[index] == ',')
2599 else if ((name[index] == '.' && !done) || (index == name.Length && name[0] != '[')) {
2600 string substring = name.Substring(dot, index - dot);
2602 if (resolved == null)
2603 resolved = RootNamespace.Global.Lookup (ec.DeclContainer, substring, Location.Null);
2604 else if (resolved is Namespace)
2605 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
2606 else if (type != null)
2607 type = TypeManager.GetNestedType (type, substring);
2611 if (resolved == null)
2613 else if (type == null && resolved is TypeExpr)
2614 type = resolved.Type;
2621 if (name[0] != '[') {
2622 string substring = name.Substring(dot, index - dot);
2625 return TypeManager.GetNestedType (type, substring);
2626 else if (resolved != null) {
2627 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
2628 if (resolved is TypeExpr)
2629 return resolved.Type;
2631 resolved.Error_UnexpectedKind (ec.DeclContainer, "type", loc);
2632 return typeof (UnexpectedType);
2639 return recursive_type;
2642 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2644 Type t = TypeLookup (ec, name);
2645 if (t == null || !ec.DeclContainer.CheckAccessLevel (t)) {
2646 NamespaceEntry.Error_NamespaceNotFound (loc, name);
2649 else if (t == typeof(UnexpectedType))
2655 public override string Name {
2656 get { return name; }
2659 public override string FullName {
2660 get { return name; }
2663 protected override void CloneTo (CloneContext clonectx, Expression target)
2665 // CloneTo: Nothing, we do not keep any state on this expression
2670 /// Represents an "unbound generic type", ie. typeof (Foo<>).
2673 public class UnboundTypeExpression : TypeExpr
2677 public UnboundTypeExpression (MemberName name, Location l)
2683 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2686 if (name.Left != null) {
2687 Expression lexpr = name.Left.GetTypeExpression ();
2688 expr = new MemberAccess (lexpr, name.Basename);
2690 expr = new SimpleName (name.Basename, loc);
2693 FullNamedExpression fne = expr.ResolveAsTypeStep (ec, false);
2698 return new TypeExpression (type, loc);
2701 public override string Name {
2702 get { return name.FullName; }
2705 public override string FullName {
2706 get { return name.FullName; }
2710 public class TypeAliasExpression : TypeExpr {
2711 FullNamedExpression alias;
2716 public TypeAliasExpression (FullNamedExpression alias, TypeArguments args, Location l)
2722 eclass = ExprClass.Type;
2724 name = alias.FullName + "<" + args.ToString () + ">";
2726 name = alias.FullName;
2729 public override string Name {
2730 get { return alias.FullName; }
2733 public override string FullName {
2734 get { return name; }
2737 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2739 texpr = alias.ResolveAsTypeTerminal (ec, false);
2743 Type type = texpr.Type;
2744 int num_args = TypeManager.GetNumberOfTypeArguments (type);
2747 if (num_args == 0) {
2748 Report.Error (308, loc,
2749 "The non-generic type `{0}' cannot " +
2750 "be used with type arguments.",
2751 TypeManager.CSharpName (type));
2755 ConstructedType ctype = new ConstructedType (type, args, loc);
2756 return ctype.ResolveAsTypeTerminal (ec, false);
2757 } else if (num_args > 0) {
2758 Report.Error (305, loc,
2759 "Using the generic type `{0}' " +
2760 "requires {1} type arguments",
2761 TypeManager.CSharpName (type), num_args.ToString ());
2768 public override bool CheckAccessLevel (DeclSpace ds)
2770 return texpr.CheckAccessLevel (ds);
2773 public override bool AsAccessible (DeclSpace ds, int flags)
2775 return texpr.AsAccessible (ds, flags);
2778 public override bool IsClass {
2779 get { return texpr.IsClass; }
2782 public override bool IsValueType {
2783 get { return texpr.IsValueType; }
2786 public override bool IsInterface {
2787 get { return texpr.IsInterface; }
2790 public override bool IsSealed {
2791 get { return texpr.IsSealed; }
2796 /// This class denotes an expression which evaluates to a member
2797 /// of a struct or a class.
2799 public abstract class MemberExpr : Expression
2802 /// The name of this member.
2804 public abstract string Name {
2809 /// Whether this is an instance member.
2811 public abstract bool IsInstance {
2816 /// Whether this is a static member.
2818 public abstract bool IsStatic {
2823 /// The type which declares this member.
2825 public abstract Type DeclaringType {
2830 /// The instance expression associated with this member, if it's a
2831 /// non-static member.
2833 public Expression InstanceExpression;
2835 public static void error176 (Location loc, string name)
2837 Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
2838 "with an instance reference, qualify it with a type name instead", name);
2841 // TODO: possible optimalization
2842 // Cache resolved constant result in FieldBuilder <-> expression map
2843 public virtual Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
2844 SimpleName original)
2848 // original == null || original.Resolve (...) ==> left
2851 if (left is TypeExpr) {
2852 left = left.ResolveAsTypeTerminal (ec, true);
2857 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
2865 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
2868 error176 (loc, GetSignatureForError ());
2872 InstanceExpression = left;
2877 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
2882 if (InstanceExpression == EmptyExpression.Null) {
2883 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
2887 if (InstanceExpression.Type.IsValueType) {
2888 if (InstanceExpression is IMemoryLocation) {
2889 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
2891 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
2892 InstanceExpression.Emit (ec);
2894 t.AddressOf (ec, AddressOp.Store);
2897 InstanceExpression.Emit (ec);
2899 if (prepare_for_load)
2900 ec.ig.Emit (OpCodes.Dup);
2905 /// Represents group of extension methods
2907 public class ExtensionMethodGroupExpr : MethodGroupExpr
2909 NamespaceEntry namespaceEntry;
2911 public ExtensionMethodGroupExpr (ArrayList list, NamespaceEntry n, Type extensionType, Location l)
2914 this.namespaceEntry = n;
2915 this.type = extensionType;
2918 public override bool IsBase {
2919 get { return true; }
2922 public override bool IsStatic {
2923 get { return true; }
2926 public bool IsTopLevel {
2927 get { return namespaceEntry == null; }
2930 public override MethodBase OverloadExtensionResolve (EmitContext ec, ref ArrayList arguments, ref MethodGroupExpr mg,
2931 Expression expr, Location loc)
2933 if (arguments == null)
2934 arguments = new ArrayList (1);
2936 Expression extension_argument = ((MemberAccess)expr).Expr;
2937 if ((extension_argument.eclass & (ExprClass.Value | ExprClass.Variable)) == 0)
2940 Argument a = new Argument (extension_argument);
2941 a.Resolve (ec, loc);
2942 arguments.Insert (0, a);
2946 MethodBase method = mg.OverloadResolve (ec, arguments, true, loc);
2950 ExtensionMethodGroupExpr e = namespaceEntry.LookupExtensionMethod (type, null, Name);
2952 return mg.OverloadResolve (ec, arguments, false, loc);
2955 namespaceEntry = e.namespaceEntry;
2961 /// MethodGroup Expression.
2963 /// This is a fully resolved expression that evaluates to a type
2965 public class MethodGroupExpr : MemberExpr {
2966 public MethodBase [] Methods;
2967 bool has_type_arguments = false;
2968 bool identical_type_name = false;
2971 public MethodGroupExpr (MemberInfo [] mi, Location l)
2973 Methods = new MethodBase [mi.Length];
2974 mi.CopyTo (Methods, 0);
2975 eclass = ExprClass.MethodGroup;
2977 // Set the type to something that will never be useful, which will
2978 // trigger the proper conversions.
2979 type = typeof (MethodGroupExpr);
2983 public MethodGroupExpr (ArrayList list, Location l)
2986 Methods = (MethodBase[])list.ToArray (typeof (MethodBase));
2988 foreach (MemberInfo m in list){
2989 if (!(m is MethodBase)){
2990 Console.WriteLine ("Name " + m.Name);
2991 Console.WriteLine ("Found a: " + m.GetType ().FullName);
2998 eclass = ExprClass.MethodGroup;
2999 type = TypeManager.object_type;
3002 public override Type DeclaringType {
3005 // We assume that the top-level type is in the end
3007 return Methods [Methods.Length - 1].DeclaringType;
3008 //return Methods [0].DeclaringType;
3012 public bool HasTypeArguments {
3014 return has_type_arguments;
3018 has_type_arguments = value;
3022 public bool IdenticalTypeName {
3024 return identical_type_name;
3028 identical_type_name = value;
3032 public virtual bool IsBase {
3041 public override string GetSignatureForError ()
3043 return TypeManager.CSharpSignature (Methods [0]);
3046 public override string Name {
3048 return Methods [0].Name;
3052 public override bool IsInstance {
3054 foreach (MethodBase mb in Methods)
3062 public override bool IsStatic {
3064 foreach (MethodBase mb in Methods)
3073 /// Determines "better conversion" as specified in 14.4.2.3
3075 /// Returns : p if a->p is better,
3076 /// q if a->q is better,
3077 /// null if neither is better
3079 static Type BetterConversion (EmitContext ec, Argument a, Type p, Type q)
3081 Type argument_type = TypeManager.TypeToCoreType (a.Type);
3082 Expression argument_expr = a.Expr;
3084 if (argument_type == null)
3085 throw new Exception ("Expression of type " + a.Expr +
3086 " does not resolve its type");
3088 if (p == null || q == null)
3089 throw new InternalErrorException ("BetterConversion Got a null conversion");
3094 if (argument_expr is NullLiteral)
3097 // If the argument is null and one of the types to compare is 'object' and
3098 // the other is a reference type, we prefer the other.
3100 // This follows from the usual rules:
3101 // * There is an implicit conversion from 'null' to type 'object'
3102 // * There is an implicit conversion from 'null' to any reference type
3103 // * There is an implicit conversion from any reference type to type 'object'
3104 // * There is no implicit conversion from type 'object' to other reference types
3105 // => Conversion of 'null' to a reference type is better than conversion to 'object'
3107 // FIXME: This probably isn't necessary, since the type of a NullLiteral is the
3108 // null type. I think it used to be 'object' and thus needed a special
3109 // case to avoid the immediately following two checks.
3111 if (!p.IsValueType && q == TypeManager.object_type)
3113 if (!q.IsValueType && p == TypeManager.object_type)
3117 if (argument_type == p)
3120 if (argument_type == q)
3123 Expression p_tmp = new EmptyExpression (p);
3124 Expression q_tmp = new EmptyExpression (q);
3126 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3127 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3129 if (p_to_q && !q_to_p)
3132 if (q_to_p && !p_to_q)
3135 if (p == TypeManager.sbyte_type)
3136 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3137 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3139 if (q == TypeManager.sbyte_type)
3140 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3141 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3144 if (p == TypeManager.short_type)
3145 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3146 q == TypeManager.uint64_type)
3148 if (q == TypeManager.short_type)
3149 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3150 p == TypeManager.uint64_type)
3153 if (p == TypeManager.int32_type)
3154 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3156 if (q == TypeManager.int32_type)
3157 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3160 if (p == TypeManager.int64_type)
3161 if (q == TypeManager.uint64_type)
3163 if (q == TypeManager.int64_type)
3164 if (p == TypeManager.uint64_type)
3171 /// Determines "Better function" between candidate
3172 /// and the current best match
3175 /// Returns a boolean indicating :
3176 /// false if candidate ain't better
3177 /// true if candidate is better than the current best match
3179 static bool BetterFunction (EmitContext ec, ArrayList args, int argument_count,
3180 MethodBase candidate, bool candidate_params,
3181 MethodBase best, bool best_params)
3183 ParameterData candidate_pd = TypeManager.GetParameterData (candidate);
3184 ParameterData best_pd = TypeManager.GetParameterData (best);
3186 bool better_at_least_one = false;
3188 for (int j = 0, c_idx = 0, b_idx = 0; j < argument_count; ++j, ++c_idx, ++b_idx)
3190 Argument a = (Argument) args [j];
3192 Type ct = TypeManager.TypeToCoreType (candidate_pd.ParameterType (c_idx));
3193 Type bt = TypeManager.TypeToCoreType (best_pd.ParameterType (b_idx));
3195 if (candidate_params && candidate_pd.ParameterModifier (c_idx) == Parameter.Modifier.PARAMS)
3197 ct = TypeManager.GetElementType (ct);
3201 if (best_params && best_pd.ParameterModifier (b_idx) == Parameter.Modifier.PARAMS)
3203 bt = TypeManager.GetElementType (bt);
3211 Type better = BetterConversion (ec, a, ct, bt);
3213 // for each argument, the conversion to 'ct' should be no worse than
3214 // the conversion to 'bt'.
3218 // for at least one argument, the conversion to 'ct' should be better than
3219 // the conversion to 'bt'.
3221 better_at_least_one = true;
3224 if (better_at_least_one)
3228 // This handles the case
3230 // Add (float f1, float f2, float f3);
3231 // Add (params decimal [] foo);
3233 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3234 // first candidate would've chosen as better.
3240 // The two methods have equal parameter types. Now apply tie-breaking rules
3242 if (TypeManager.IsGenericMethod (best) && !TypeManager.IsGenericMethod (candidate))
3244 if (!TypeManager.IsGenericMethod (best) && TypeManager.IsGenericMethod (candidate))
3248 // This handles the following cases:
3250 // Trim () is better than Trim (params char[] chars)
3251 // Concat (string s1, string s2, string s3) is better than
3252 // Concat (string s1, params string [] srest)
3253 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3255 if (!candidate_params && best_params)
3257 if (candidate_params && !best_params)
3260 int candidate_param_count = candidate_pd.Count;
3261 int best_param_count = best_pd.Count;
3263 if (candidate_param_count != best_param_count)
3264 // can only happen if (candidate_params && best_params)
3265 return candidate_param_count > best_param_count;
3268 // now, both methods have the same number of parameters, and the parameters have the same types
3269 // Pick the "more specific" signature
3272 MethodBase orig_candidate = TypeManager.DropGenericMethodArguments (candidate);
3273 MethodBase orig_best = TypeManager.DropGenericMethodArguments (best);
3275 ParameterData orig_candidate_pd = TypeManager.GetParameterData (orig_candidate);
3276 ParameterData orig_best_pd = TypeManager.GetParameterData (orig_best);
3278 bool specific_at_least_once = false;
3279 for (int j = 0; j < candidate_param_count; ++j)
3281 Type ct = TypeManager.TypeToCoreType (orig_candidate_pd.ParameterType (j));
3282 Type bt = TypeManager.TypeToCoreType (orig_best_pd.ParameterType (j));
3285 Type specific = MoreSpecific (ct, bt);
3289 specific_at_least_once = true;
3292 if (specific_at_least_once)
3295 // FIXME: handle lifted operators
3301 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3302 SimpleName original)
3304 if (!(left is TypeExpr) &&
3305 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3306 IdenticalTypeName = true;
3308 return base.ResolveMemberAccess (ec, left, loc, original);
3311 override public Expression DoResolve (EmitContext ec)
3314 InstanceExpression = null;
3316 if (InstanceExpression != null) {
3317 InstanceExpression = InstanceExpression.DoResolve (ec);
3318 if (InstanceExpression == null)
3325 public void ReportUsageError ()
3327 Report.Error (654, loc, "Method `" + DeclaringType + "." +
3328 Name + "()' is referenced without parentheses");
3331 override public void Emit (EmitContext ec)
3333 ReportUsageError ();
3336 public static bool IsAncestralType (Type first_type, Type second_type)
3338 return first_type != second_type &&
3339 (TypeManager.IsSubclassOf (second_type, first_type) ||
3340 TypeManager.ImplementsInterface (second_type, first_type));
3343 public static bool IsOverride (MethodBase cand_method, MethodBase base_method)
3345 if (!IsAncestralType (base_method.DeclaringType, cand_method.DeclaringType))
3348 ParameterData cand_pd = TypeManager.GetParameterData (cand_method);
3349 ParameterData base_pd = TypeManager.GetParameterData (base_method);
3351 if (cand_pd.Count != base_pd.Count)
3354 for (int j = 0; j < cand_pd.Count; ++j)
3356 Parameter.Modifier cm = cand_pd.ParameterModifier (j);
3357 Parameter.Modifier bm = base_pd.ParameterModifier (j);
3358 Type ct = TypeManager.TypeToCoreType (cand_pd.ParameterType (j));
3359 Type bt = TypeManager.TypeToCoreType (base_pd.ParameterType (j));
3361 if (cm != bm || ct != bt)
3368 static Type MoreSpecific (Type p, Type q)
3370 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
3372 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
3375 if (TypeManager.HasElementType (p))
3377 Type pe = TypeManager.GetElementType (p);
3378 Type qe = TypeManager.GetElementType (q);
3379 Type specific = MoreSpecific (pe, qe);
3385 else if (TypeManager.IsGenericType (p))
3387 Type[] pargs = TypeManager.GetTypeArguments (p);
3388 Type[] qargs = TypeManager.GetTypeArguments (q);
3390 bool p_specific_at_least_once = false;
3391 bool q_specific_at_least_once = false;
3393 for (int i = 0; i < pargs.Length; i++)
3395 Type specific = MoreSpecific (pargs [i], qargs [i]);
3396 if (specific == pargs [i])
3397 p_specific_at_least_once = true;
3398 if (specific == qargs [i])
3399 q_specific_at_least_once = true;
3402 if (p_specific_at_least_once && !q_specific_at_least_once)
3404 if (!p_specific_at_least_once && q_specific_at_least_once)
3411 public virtual MethodBase OverloadExtensionResolve (EmitContext ec, ref ArrayList arguments, ref MethodGroupExpr mg,
3412 Expression expr, Location loc)
3414 MethodBase method = OverloadResolve (ec, arguments, true, loc);
3415 if (method != null) {
3420 MemberAccess mexpr = expr as MemberAccess;
3421 if (mexpr != null) {
3422 ExtensionMethodGroupExpr emg = ec.DeclContainer.LookupExtensionMethod (mexpr.Expr.Type, Name);
3424 return OverloadExtensionResolve (ec, ref arguments, ref mg, expr, loc);
3428 return OverloadResolve (ec, arguments, false, loc);
3432 /// Find the Applicable Function Members (7.4.2.1)
3434 /// me: Method Group expression with the members to select.
3435 /// it might contain constructors or methods (or anything
3436 /// that maps to a method).
3438 /// Arguments: ArrayList containing resolved Argument objects.
3440 /// loc: The location if we want an error to be reported, or a Null
3441 /// location for "probing" purposes.
3443 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3444 /// that is the best match of me on Arguments.
3447 public virtual MethodBase OverloadResolve (EmitContext ec, ArrayList Arguments,
3448 bool may_fail, Location loc)
3450 MethodBase method = null;
3451 bool method_params = false;
3452 Type applicable_type = null;
3454 ArrayList candidates = new ArrayList (2);
3455 ArrayList candidate_overrides = null;
3458 // Used to keep a map between the candidate
3459 // and whether it is being considered in its
3460 // normal or expanded form
3462 // false is normal form, true is expanded form
3464 Hashtable candidate_to_form = null;
3466 if (Arguments != null)
3467 arg_count = Arguments.Count;
3469 if (RootContext.Version == LanguageVersion.ISO_1 && Name == "Invoke" && TypeManager.IsDelegateType (DeclaringType)) {
3471 Report.Error (1533, loc, "Invoke cannot be called directly on a delegate");
3475 int nmethods = Methods.Length;
3479 // Methods marked 'override' don't take part in 'applicable_type'
3480 // computation, nor in the actual overload resolution.
3481 // However, they still need to be emitted instead of a base virtual method.
3482 // So, we salt them away into the 'candidate_overrides' array.
3484 // In case of reflected methods, we replace each overriding method with
3485 // its corresponding base virtual method. This is to improve compatibility
3486 // with non-C# libraries which change the visibility of overrides (#75636)
3489 for (int i = 0; i < Methods.Length; ++i) {
3490 MethodBase m = Methods [i];
3492 Type [] gen_args = null;
3493 if (m.IsGenericMethod && !m.IsGenericMethodDefinition)
3494 gen_args = m.GetGenericArguments ();
3496 if (TypeManager.IsOverride (m)) {
3497 if (candidate_overrides == null)
3498 candidate_overrides = new ArrayList ();
3499 candidate_overrides.Add (m);
3500 m = TypeManager.TryGetBaseDefinition (m);
3502 if (m != null && gen_args != null) {
3503 if (!m.IsGenericMethodDefinition)
3504 throw new InternalErrorException ("GetBaseDefinition didn't return a GenericMethodDefinition");
3505 m = ((MethodInfo) m).MakeGenericMethod (gen_args);
3515 int applicable_errors = Report.Errors;
3518 // First we construct the set of applicable methods
3520 bool is_sorted = true;
3521 for (int i = 0; i < nmethods; i++) {
3522 Type decl_type = Methods [i].DeclaringType;
3525 // If we have already found an applicable method
3526 // we eliminate all base types (Section 14.5.5.1)
3528 if (applicable_type != null && IsAncestralType (decl_type, applicable_type))
3532 // Check if candidate is applicable (section 14.4.2.1)
3533 // Is candidate applicable in normal form?
3535 bool is_applicable = Invocation.IsApplicable (ec, this, Arguments, arg_count, ref Methods [i]);
3537 if (!is_applicable && Invocation.IsParamsMethodApplicable (ec, this, Arguments, arg_count, ref Methods [i])) {
3538 MethodBase candidate = Methods [i];
3539 if (candidate_to_form == null)
3540 candidate_to_form = new PtrHashtable ();
3541 candidate_to_form [candidate] = candidate;
3542 // Candidate is applicable in expanded form
3543 is_applicable = true;
3549 candidates.Add (Methods [i]);
3551 if (applicable_type == null)
3552 applicable_type = decl_type;
3553 else if (applicable_type != decl_type) {
3555 if (IsAncestralType (applicable_type, decl_type))
3556 applicable_type = decl_type;
3560 if (applicable_errors != Report.Errors)
3563 int candidate_top = candidates.Count;
3565 if (applicable_type == null) {
3567 // Okay so we have failed to find anything so we
3568 // return by providing info about the closest match
3570 int errors = Report.Errors;
3571 for (int i = 0; i < nmethods; ++i) {
3572 MethodBase c = Methods [i];
3573 ParameterData pd = TypeManager.GetParameterData (c);
3575 if (pd.Count != arg_count)
3579 if (!TypeManager.InferTypeArguments (ec, Arguments, ref c))
3581 if (TypeManager.IsGenericMethodDefinition (c))
3585 Invocation.VerifyArgumentsCompat (ec, Arguments, arg_count,
3586 c, false, null, may_fail, loc);
3588 if (!may_fail && errors == Report.Errors){
3590 throw new InternalErrorException (
3591 "VerifyArgumentsCompat and IsApplicable do not agree; " +
3592 "likely reason: ImplicitConversion and ImplicitConversionExists have gone out of sync");
3598 if (!may_fail && errors == Report.Errors) {
3599 string report_name = Name;
3600 if (report_name == ".ctor")
3601 report_name = TypeManager.CSharpName (DeclaringType);
3607 for (int i = 0; i < Methods.Length; ++i) {
3608 MethodBase c = Methods [i];
3609 ParameterData pd = TypeManager.GetParameterData (c);
3611 if (pd.Count != arg_count)
3614 if (TypeManager.InferTypeArguments (ec, Arguments, ref c))
3618 411, loc, "The type arguments for " +
3619 "method `{0}' cannot be inferred from " +
3620 "the usage. Try specifying the type " +
3621 "arguments explicitly.", report_name);
3626 Invocation.Error_WrongNumArguments (loc, report_name, arg_count);
3634 // At this point, applicable_type is _one_ of the most derived types
3635 // in the set of types containing the methods in this MethodGroup.
3636 // Filter the candidates so that they only contain methods from the
3637 // most derived types.
3640 int finalized = 0; // Number of finalized candidates
3643 // Invariant: applicable_type is a most derived type
3645 // We'll try to complete Section 14.5.5.1 for 'applicable_type' by
3646 // eliminating all it's base types. At the same time, we'll also move
3647 // every unrelated type to the end of the array, and pick the next
3648 // 'applicable_type'.
3650 Type next_applicable_type = null;
3651 int j = finalized; // where to put the next finalized candidate
3652 int k = finalized; // where to put the next undiscarded candidate
3653 for (int i = finalized; i < candidate_top; ++i) {
3654 MethodBase candidate = (MethodBase) candidates [i];
3655 Type decl_type = candidate.DeclaringType;
3657 if (decl_type == applicable_type) {
3658 candidates [k++] = candidates [j];
3659 candidates [j++] = candidates [i];
3663 if (IsAncestralType (decl_type, applicable_type))
3666 if (next_applicable_type != null &&
3667 IsAncestralType (decl_type, next_applicable_type))
3670 candidates [k++] = candidates [i];
3672 if (next_applicable_type == null ||
3673 IsAncestralType (next_applicable_type, decl_type))
3674 next_applicable_type = decl_type;
3677 applicable_type = next_applicable_type;
3680 } while (applicable_type != null);
3684 // Now we actually find the best method
3687 method = (MethodBase) candidates [0];
3688 method_params = candidate_to_form != null && candidate_to_form.Contains (method);
3689 for (int ix = 1; ix < candidate_top; ix++) {
3690 MethodBase candidate = (MethodBase) candidates [ix];
3692 if (candidate == method)
3695 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
3697 if (BetterFunction (ec, Arguments, arg_count,
3698 candidate, cand_params,
3699 method, method_params)) {
3701 method_params = cand_params;
3705 // Now check that there are no ambiguities i.e the selected method
3706 // should be better than all the others
3708 MethodBase ambiguous = null;
3709 for (int ix = 0; ix < candidate_top; ix++) {
3710 MethodBase candidate = (MethodBase) candidates [ix];
3712 if (candidate == method)
3715 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
3716 if (!BetterFunction (ec, Arguments, arg_count,
3717 method, method_params,
3718 candidate, cand_params))
3721 Report.SymbolRelatedToPreviousError (candidate);
3722 ambiguous = candidate;
3726 if (ambiguous != null) {
3727 Report.SymbolRelatedToPreviousError (method);
3728 Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
3729 TypeManager.CSharpSignature (ambiguous), TypeManager.CSharpSignature (method));
3734 // If the method is a virtual function, pick an override closer to the LHS type.
3736 if (!IsBase && method.IsVirtual) {
3737 if (TypeManager.IsOverride (method))
3738 throw new InternalErrorException (
3739 "Should not happen. An 'override' method took part in overload resolution: " + method);
3741 if (candidate_overrides != null)
3742 foreach (MethodBase candidate in candidate_overrides) {
3743 if (IsOverride (candidate, method))
3749 // And now check if the arguments are all
3750 // compatible, perform conversions if
3751 // necessary etc. and return if everything is
3754 if (!Invocation.VerifyArgumentsCompat (ec, Arguments, arg_count, method,
3755 method_params, null, may_fail, loc))
3761 MethodBase the_method = TypeManager.DropGenericMethodArguments (method);
3763 if (the_method.IsGenericMethodDefinition &&
3764 !ConstraintChecker.CheckConstraints (ec, the_method, method, loc))
3768 IMethodData data = TypeManager.GetMethod (the_method);
3770 data.SetMemberIsUsed ();
3776 bool RemoveMethods (bool keep_static)
3778 ArrayList smethods = new ArrayList ();
3780 foreach (MethodBase mb in Methods){
3781 if (mb.IsStatic == keep_static)
3785 if (smethods.Count == 0)
3788 Methods = new MethodBase [smethods.Count];
3789 smethods.CopyTo (Methods, 0);
3795 /// Removes any instance methods from the MethodGroup, returns
3796 /// false if the resulting set is empty.
3798 public bool RemoveInstanceMethods ()
3800 return RemoveMethods (true);
3804 /// Removes any static methods from the MethodGroup, returns
3805 /// false if the resulting set is empty.
3807 public bool RemoveStaticMethods ()
3809 return RemoveMethods (false);
3812 public Expression ResolveGeneric (EmitContext ec, TypeArguments args)
3815 if (!args.Resolve (ec))
3818 Type[] atypes = args.Arguments;
3820 int first_count = 0;
3821 MethodInfo first = null;
3823 ArrayList list = new ArrayList ();
3824 foreach (MethodBase mb in Methods) {
3825 MethodInfo mi = mb as MethodInfo;
3826 if ((mi == null) || !mb.IsGenericMethod)
3829 Type[] gen_params = mb.GetGenericArguments ();
3831 if (first == null) {
3833 first_count = gen_params.Length;
3836 if (gen_params.Length != atypes.Length)
3839 mi = mi.MakeGenericMethod (atypes);
3843 // MS implementation throws NotSupportedException for GetParameters
3844 // on unbaked generic method
3845 Parameters p = ((Parameters)TypeManager.GetParameterData (mi)).Clone ();
3846 p.InflateTypes (gen_params, atypes);
3847 TypeManager.RegisterMethod (mi, p);
3851 if (list.Count > 0) {
3852 MethodGroupExpr new_mg = new MethodGroupExpr (list, Location);
3853 new_mg.InstanceExpression = InstanceExpression;
3854 new_mg.HasTypeArguments = true;
3855 new_mg.IsBase = IsBase;
3859 if (first != null) {
3860 Report.SymbolRelatedToPreviousError (first);
3862 305, loc, "Using the generic method `{0}' requires `{1}' type arguments",
3863 TypeManager.CSharpSignature (first), first_count.ToString ());
3866 308, loc, "The non-generic method `{0}' " +
3867 "cannot be used with type arguments", Name);
3871 throw new NotImplementedException ();
3877 /// Fully resolved expression that evaluates to a Field
3879 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariable {
3880 public readonly FieldInfo FieldInfo;
3881 VariableInfo variable_info;
3883 LocalTemporary temp;
3885 bool in_initializer;
3887 public FieldExpr (FieldInfo fi, Location l, bool in_initializer):
3890 this.in_initializer = in_initializer;
3893 public FieldExpr (FieldInfo fi, Location l)
3896 eclass = ExprClass.Variable;
3897 type = TypeManager.TypeToCoreType (fi.FieldType);
3901 public override string Name {
3903 return FieldInfo.Name;
3907 public override bool IsInstance {
3909 return !FieldInfo.IsStatic;
3913 public override bool IsStatic {
3915 return FieldInfo.IsStatic;
3919 public override Type DeclaringType {
3921 return FieldInfo.DeclaringType;
3925 public override string GetSignatureForError ()
3927 return TypeManager.GetFullNameSignature (FieldInfo);
3930 public VariableInfo VariableInfo {
3932 return variable_info;
3936 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3937 SimpleName original)
3939 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
3941 Type t = fi.FieldType;
3943 if (fi.IsLiteral || (fi.IsInitOnly && t == TypeManager.decimal_type)) {
3944 IConstant ic = TypeManager.GetConstant (fi);
3947 ic = new ExternalConstant (fi);
3949 ic = ExternalConstant.CreateDecimal (fi);
3951 return base.ResolveMemberAccess (ec, left, loc, original);
3954 TypeManager.RegisterConstant (fi, ic);
3957 bool left_is_type = left is TypeExpr;
3958 if (!left_is_type && (original == null || !original.IdenticalNameAndTypeName (ec, left, loc))) {
3959 Report.SymbolRelatedToPreviousError (FieldInfo);
3960 error176 (loc, TypeManager.GetFullNameSignature (FieldInfo));
3964 if (ic.ResolveValue ()) {
3965 if (!ec.IsInObsoleteScope)
3966 ic.CheckObsoleteness (loc);
3969 return ic.CreateConstantReference (loc);
3972 if (t.IsPointer && !ec.InUnsafe) {
3977 return base.ResolveMemberAccess (ec, left, loc, original);
3980 override public Expression DoResolve (EmitContext ec)
3982 return DoResolve (ec, false, false);
3985 Expression DoResolve (EmitContext ec, bool lvalue_instance, bool out_access)
3987 if (!FieldInfo.IsStatic){
3988 if (InstanceExpression == null){
3990 // This can happen when referencing an instance field using
3991 // a fully qualified type expression: TypeName.InstanceField = xxx
3993 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3997 // Resolve the field's instance expression while flow analysis is turned
3998 // off: when accessing a field "a.b", we must check whether the field
3999 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4001 if (lvalue_instance) {
4002 using (ec.With (EmitContext.Flags.DoFlowAnalysis, false)) {
4003 Expression right_side =
4004 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4005 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side, loc);
4008 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
4009 InstanceExpression = InstanceExpression.Resolve (ec, rf);
4012 if (InstanceExpression == null)
4015 InstanceExpression.CheckMarshalByRefAccess ();
4018 if (!in_initializer && !ec.IsFieldInitializer) {
4019 ObsoleteAttribute oa;
4020 FieldBase f = TypeManager.GetField (FieldInfo);
4022 if (!ec.IsInObsoleteScope)
4023 f.CheckObsoleteness (loc);
4025 // To be sure that type is external because we do not register generated fields
4026 } else if (!(FieldInfo.DeclaringType is TypeBuilder)) {
4027 oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
4029 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
4033 AnonymousContainer am = ec.CurrentAnonymousMethod;
4035 if (!FieldInfo.IsStatic){
4036 if (!am.IsIterator && (ec.TypeContainer is Struct)){
4037 Report.Error (1673, loc,
4038 "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",
4045 // If the instance expression is a local variable or parameter.
4046 IVariable var = InstanceExpression as IVariable;
4047 if ((var == null) || (var.VariableInfo == null))
4050 VariableInfo vi = var.VariableInfo;
4051 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
4054 variable_info = vi.GetSubStruct (FieldInfo.Name);
4058 static readonly int [] codes = {
4059 191, // instance, write access
4060 192, // instance, out access
4061 198, // static, write access
4062 199, // static, out access
4063 1648, // member of value instance, write access
4064 1649, // member of value instance, out access
4065 1650, // member of value static, write access
4066 1651 // member of value static, out access
4069 static readonly string [] msgs = {
4070 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4071 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4072 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4073 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4074 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4075 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4076 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4077 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4080 // The return value is always null. Returning a value simplifies calling code.
4081 Expression Report_AssignToReadonly (Expression right_side)
4084 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4088 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4090 Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4095 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4097 IVariable var = InstanceExpression as IVariable;
4098 if ((var != null) && (var.VariableInfo != null))
4099 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
4101 bool lvalue_instance = !FieldInfo.IsStatic && FieldInfo.DeclaringType.IsValueType;
4102 bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
4104 Expression e = DoResolve (ec, lvalue_instance, out_access);
4109 FieldBase fb = TypeManager.GetField (FieldInfo);
4113 if (FieldInfo.IsInitOnly) {
4114 // InitOnly fields can only be assigned in constructors or initializers
4115 if (!ec.IsFieldInitializer && !ec.IsConstructor)
4116 return Report_AssignToReadonly (right_side);
4118 if (ec.IsConstructor) {
4119 Type ctype = ec.TypeContainer.CurrentType;
4121 ctype = ec.ContainerType;
4123 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4124 if (!TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
4125 return Report_AssignToReadonly (right_side);
4126 // static InitOnly fields cannot be assigned-to in an instance constructor
4127 if (IsStatic && !ec.IsStatic)
4128 return Report_AssignToReadonly (right_side);
4129 // instance constructors can't modify InitOnly fields of other instances of the same type
4130 if (!IsStatic && !(InstanceExpression is This))
4131 return Report_AssignToReadonly (right_side);
4135 if (right_side == EmptyExpression.OutAccess &&
4136 !IsStatic && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
4137 Report.SymbolRelatedToPreviousError (DeclaringType);
4138 Report.Warning (197, 1, loc,
4139 "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",
4140 GetSignatureForError ());
4146 public override void CheckMarshalByRefAccess ()
4148 if (!IsStatic && Type.IsValueType && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
4149 Report.SymbolRelatedToPreviousError (DeclaringType);
4150 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",
4151 GetSignatureForError ());
4155 public bool VerifyFixed ()
4157 IVariable variable = InstanceExpression as IVariable;
4158 // A variable of the form V.I is fixed when V is a fixed variable of a struct type.
4159 // We defer the InstanceExpression check after the variable check to avoid a
4160 // separate null check on InstanceExpression.
4161 return variable != null && InstanceExpression.Type.IsValueType && variable.VerifyFixed ();
4164 public override int GetHashCode ()
4166 return FieldInfo.GetHashCode ();
4169 public override bool Equals (object obj)
4171 FieldExpr fe = obj as FieldExpr;
4175 if (FieldInfo != fe.FieldInfo)
4178 if (InstanceExpression == null || fe.InstanceExpression == null)
4181 return InstanceExpression.Equals (fe.InstanceExpression);
4184 public void Emit (EmitContext ec, bool leave_copy)
4186 ILGenerator ig = ec.ig;
4187 bool is_volatile = false;
4189 FieldBase f = TypeManager.GetField (FieldInfo);
4191 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4194 f.SetMemberIsUsed ();
4197 if (FieldInfo.IsStatic){
4199 ig.Emit (OpCodes.Volatile);
4201 ig.Emit (OpCodes.Ldsfld, FieldInfo);
4204 EmitInstance (ec, false);
4207 ig.Emit (OpCodes.Volatile);
4209 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
4212 ig.Emit (OpCodes.Ldflda, FieldInfo);
4213 ig.Emit (OpCodes.Ldflda, ff.Element);
4216 ig.Emit (OpCodes.Ldfld, FieldInfo);
4221 ec.ig.Emit (OpCodes.Dup);
4222 if (!FieldInfo.IsStatic) {
4223 temp = new LocalTemporary (this.Type);
4229 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4231 FieldAttributes fa = FieldInfo.Attributes;
4232 bool is_static = (fa & FieldAttributes.Static) != 0;
4233 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
4234 ILGenerator ig = ec.ig;
4235 prepared = prepare_for_load;
4237 if (is_readonly && !ec.IsConstructor){
4238 Report_AssignToReadonly (source);
4242 EmitInstance (ec, prepare_for_load);
4246 ec.ig.Emit (OpCodes.Dup);
4247 if (!FieldInfo.IsStatic) {
4248 temp = new LocalTemporary (this.Type);
4253 FieldBase f = TypeManager.GetField (FieldInfo);
4255 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4256 ig.Emit (OpCodes.Volatile);
4262 ig.Emit (OpCodes.Stsfld, FieldInfo);
4264 ig.Emit (OpCodes.Stfld, FieldInfo);
4272 public override void Emit (EmitContext ec)
4277 public void AddressOf (EmitContext ec, AddressOp mode)
4279 ILGenerator ig = ec.ig;
4281 FieldBase f = TypeManager.GetField (FieldInfo);
4283 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
4284 Report.Warning (420, 1, loc, "`{0}': A volatile fields cannot be passed using a ref or out parameter",
4285 f.GetSignatureForError ());
4289 if ((mode & AddressOp.Store) != 0)
4291 if ((mode & AddressOp.Load) != 0)
4292 f.SetMemberIsUsed ();
4296 // Handle initonly fields specially: make a copy and then
4297 // get the address of the copy.
4300 if (FieldInfo.IsInitOnly){
4302 if (ec.IsConstructor){
4303 if (FieldInfo.IsStatic){
4315 local = ig.DeclareLocal (type);
4316 ig.Emit (OpCodes.Stloc, local);
4317 ig.Emit (OpCodes.Ldloca, local);
4322 if (FieldInfo.IsStatic){
4323 ig.Emit (OpCodes.Ldsflda, FieldInfo);
4326 EmitInstance (ec, false);
4327 ig.Emit (OpCodes.Ldflda, FieldInfo);
4333 // A FieldExpr whose address can not be taken
4335 public class FieldExprNoAddress : FieldExpr, IMemoryLocation {
4336 public FieldExprNoAddress (FieldInfo fi, Location loc) : base (fi, loc)
4340 public new void AddressOf (EmitContext ec, AddressOp mode)
4342 Report.Error (-215, "Report this: Taking the address of a remapped parameter not supported");
4347 /// Expression that evaluates to a Property. The Assign class
4348 /// might set the `Value' expression if we are in an assignment.
4350 /// This is not an LValue because we need to re-write the expression, we
4351 /// can not take data from the stack and store it.
4353 public class PropertyExpr : MemberExpr, IAssignMethod {
4354 public readonly PropertyInfo PropertyInfo;
4357 // This is set externally by the `BaseAccess' class
4360 MethodInfo getter, setter;
4365 LocalTemporary temp;
4368 public PropertyExpr (Type containerType, PropertyInfo pi, Location l)
4371 eclass = ExprClass.PropertyAccess;
4375 type = TypeManager.TypeToCoreType (pi.PropertyType);
4377 ResolveAccessors (containerType);
4380 public override string Name {
4382 return PropertyInfo.Name;
4386 public override bool IsInstance {
4392 public override bool IsStatic {
4398 public override Type DeclaringType {
4400 return PropertyInfo.DeclaringType;
4404 public override string GetSignatureForError ()
4406 return TypeManager.GetFullNameSignature (PropertyInfo);
4409 void FindAccessors (Type invocation_type)
4411 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
4412 BindingFlags.Static | BindingFlags.Instance |
4413 BindingFlags.DeclaredOnly;
4415 Type current = PropertyInfo.DeclaringType;
4416 for (; current != null; current = current.BaseType) {
4417 MemberInfo[] group = TypeManager.MemberLookup (
4418 invocation_type, invocation_type, current,
4419 MemberTypes.Property, flags, PropertyInfo.Name, null);
4424 if (group.Length != 1)
4425 // Oooops, can this ever happen ?
4428 PropertyInfo pi = (PropertyInfo) group [0];
4431 getter = pi.GetGetMethod (true);
4434 setter = pi.GetSetMethod (true);
4436 MethodInfo accessor = getter != null ? getter : setter;
4438 if (!accessor.IsVirtual)
4444 // We also perform the permission checking here, as the PropertyInfo does not
4445 // hold the information for the accessibility of its setter/getter
4447 // TODO: Refactor to use some kind of cache together with GetPropertyFromAccessor
4448 void ResolveAccessors (Type containerType)
4450 FindAccessors (containerType);
4452 if (getter != null) {
4453 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
4454 IMethodData md = TypeManager.GetMethod (the_getter);
4456 md.SetMemberIsUsed ();
4458 is_static = getter.IsStatic;
4461 if (setter != null) {
4462 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
4463 IMethodData md = TypeManager.GetMethod (the_setter);
4465 md.SetMemberIsUsed ();
4467 is_static = setter.IsStatic;
4471 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
4474 InstanceExpression = null;
4478 if (InstanceExpression == null) {
4479 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4483 InstanceExpression = InstanceExpression.DoResolve (ec);
4484 if (lvalue_instance && InstanceExpression != null)
4485 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
4487 if (InstanceExpression == null)
4490 InstanceExpression.CheckMarshalByRefAccess ();
4492 if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) &&
4493 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
4494 !TypeManager.IsNestedChildOf (ec.ContainerType, InstanceExpression.Type) &&
4495 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.ContainerType)) {
4496 Report.SymbolRelatedToPreviousError (PropertyInfo);
4497 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
4504 void Error_PropertyNotFound (MethodInfo mi, bool getter)
4506 // TODO: correctly we should compare arguments but it will lead to bigger changes
4507 if (mi is MethodBuilder) {
4508 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
4512 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
4514 ParameterData iparams = TypeManager.GetParameterData (mi);
4515 sig.Append (getter ? "get_" : "set_");
4517 sig.Append (iparams.GetSignatureForError ());
4519 Report.SymbolRelatedToPreviousError (mi);
4520 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
4521 Name, sig.ToString ());
4524 override public Expression DoResolve (EmitContext ec)
4529 if (getter != null){
4530 if (TypeManager.GetParameterData (getter).Count != 0){
4531 Error_PropertyNotFound (getter, true);
4536 if (getter == null){
4538 // The following condition happens if the PropertyExpr was
4539 // created, but is invalid (ie, the property is inaccessible),
4540 // and we did not want to embed the knowledge about this in
4541 // the caller routine. This only avoids double error reporting.
4546 if (InstanceExpression != EmptyExpression.Null) {
4547 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
4548 TypeManager.GetFullNameSignature (PropertyInfo));
4553 bool must_do_cs1540_check = false;
4554 if (getter != null &&
4555 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
4556 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
4557 if (pm != null && pm.HasCustomAccessModifier) {
4558 Report.SymbolRelatedToPreviousError (pm);
4559 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
4560 TypeManager.CSharpSignature (getter));
4563 Report.SymbolRelatedToPreviousError (getter);
4564 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
4569 if (!InstanceResolve (ec, false, must_do_cs1540_check))
4573 // Only base will allow this invocation to happen.
4575 if (IsBase && getter.IsAbstract) {
4576 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
4580 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
4590 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4592 if (right_side == EmptyExpression.OutAccess) {
4593 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
4594 GetSignatureForError ());
4598 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
4599 Report.Error (1612, loc, "Cannot modify the return value of `{0}' because it is not a variable",
4600 GetSignatureForError ());
4604 if (setter == null){
4606 // The following condition happens if the PropertyExpr was
4607 // created, but is invalid (ie, the property is inaccessible),
4608 // and we did not want to embed the knowledge about this in
4609 // the caller routine. This only avoids double error reporting.
4613 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
4614 GetSignatureForError ());
4618 if (TypeManager.GetParameterData (setter).Count != 1){
4619 Error_PropertyNotFound (setter, false);
4623 bool must_do_cs1540_check;
4624 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
4625 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
4626 if (pm != null && pm.HasCustomAccessModifier) {
4627 Report.SymbolRelatedToPreviousError (pm);
4628 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
4629 TypeManager.CSharpSignature (setter));
4632 Report.SymbolRelatedToPreviousError (setter);
4633 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
4638 if (!InstanceResolve (ec, PropertyInfo.DeclaringType.IsValueType, must_do_cs1540_check))
4642 // Only base will allow this invocation to happen.
4644 if (IsBase && setter.IsAbstract){
4645 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
4652 public override void Emit (EmitContext ec)
4657 public void Emit (EmitContext ec, bool leave_copy)
4660 // Special case: length of single dimension array property is turned into ldlen
4662 if ((getter == TypeManager.system_int_array_get_length) ||
4663 (getter == TypeManager.int_array_get_length)){
4664 Type iet = InstanceExpression.Type;
4667 // System.Array.Length can be called, but the Type does not
4668 // support invoking GetArrayRank, so test for that case first
4670 if (iet != TypeManager.array_type && (iet.GetArrayRank () == 1)) {
4672 EmitInstance (ec, false);
4673 ec.ig.Emit (OpCodes.Ldlen);
4674 ec.ig.Emit (OpCodes.Conv_I4);
4679 Invocation.EmitCall (ec, IsBase, IsStatic, InstanceExpression, getter, null, loc, prepared, false);
4682 ec.ig.Emit (OpCodes.Dup);
4684 temp = new LocalTemporary (this.Type);
4691 // Implements the IAssignMethod interface for assignments
4693 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4695 Expression my_source = source;
4697 prepared = prepare_for_load;
4702 ec.ig.Emit (OpCodes.Dup);
4704 temp = new LocalTemporary (this.Type);
4708 } else if (leave_copy) {
4711 temp = new LocalTemporary (this.Type);
4717 ArrayList args = new ArrayList (1);
4718 args.Add (new Argument (my_source, Argument.AType.Expression));
4720 Invocation.EmitCall (ec, IsBase, IsStatic, InstanceExpression, setter, args, loc, false, prepared);
4730 /// Fully resolved expression that evaluates to an Event
4732 public class EventExpr : MemberExpr {
4733 public readonly EventInfo EventInfo;
4736 MethodInfo add_accessor, remove_accessor;
4738 public EventExpr (EventInfo ei, Location loc)
4742 eclass = ExprClass.EventAccess;
4744 add_accessor = TypeManager.GetAddMethod (ei);
4745 remove_accessor = TypeManager.GetRemoveMethod (ei);
4746 if (add_accessor.IsStatic || remove_accessor.IsStatic)
4749 if (EventInfo is MyEventBuilder){
4750 MyEventBuilder eb = (MyEventBuilder) EventInfo;
4751 type = eb.EventType;
4754 type = EventInfo.EventHandlerType;
4757 public override string Name {
4759 return EventInfo.Name;
4763 public override bool IsInstance {
4769 public override bool IsStatic {
4775 public override Type DeclaringType {
4777 return EventInfo.DeclaringType;
4781 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
4782 SimpleName original)
4785 // If the event is local to this class, we transform ourselves into a FieldExpr
4788 if (EventInfo.DeclaringType == ec.ContainerType ||
4789 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
4790 EventField mi = TypeManager.GetEventField (EventInfo);
4793 if (!ec.IsInObsoleteScope)
4794 mi.CheckObsoleteness (loc);
4796 FieldExpr ml = new FieldExpr (mi.FieldBuilder, loc);
4798 InstanceExpression = null;
4800 return ml.ResolveMemberAccess (ec, left, loc, original);
4804 return base.ResolveMemberAccess (ec, left, loc, original);
4808 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
4811 InstanceExpression = null;
4815 if (InstanceExpression == null) {
4816 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4820 InstanceExpression = InstanceExpression.DoResolve (ec);
4821 if (InstanceExpression == null)
4825 // This is using the same mechanism as the CS1540 check in PropertyExpr.
4826 // However, in the Event case, we reported a CS0122 instead.
4828 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
4829 InstanceExpression.Type != ec.ContainerType &&
4830 ec.ContainerType.IsSubclassOf (InstanceExpression.Type)) {
4831 Report.SymbolRelatedToPreviousError (EventInfo);
4832 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
4839 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
4841 return DoResolve (ec);
4844 public override Expression DoResolve (EmitContext ec)
4846 bool must_do_cs1540_check;
4847 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
4848 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
4849 Report.SymbolRelatedToPreviousError (EventInfo);
4850 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
4854 if (!InstanceResolve (ec, must_do_cs1540_check))
4860 public override void Emit (EmitContext ec)
4862 if (InstanceExpression is This)
4863 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of += or -=", GetSignatureForError ());
4865 Report.Error (70, loc, "The event `{0}' can only appear on the left hand side of += or -= "+
4866 "(except on the defining type)", Name);
4869 public override string GetSignatureForError ()
4871 return TypeManager.CSharpSignature (EventInfo);
4874 public void EmitAddOrRemove (EmitContext ec, Expression source)
4876 BinaryDelegate source_del = source as BinaryDelegate;
4877 if (source_del == null) {
4881 Expression handler = source_del.Right;
4883 Argument arg = new Argument (handler, Argument.AType.Expression);
4884 ArrayList args = new ArrayList ();
4888 if (source_del.IsAddition)
4889 Invocation.EmitCall (
4890 ec, false, IsStatic, InstanceExpression, add_accessor, args, loc);
4892 Invocation.EmitCall (
4893 ec, false, IsStatic, InstanceExpression, remove_accessor, args, loc);
4897 public class TemporaryVariable : Expression, IMemoryLocation
4902 public TemporaryVariable (Type type, Location loc)
4906 eclass = ExprClass.Value;
4909 public override Expression DoResolve (EmitContext ec)
4914 TypeExpr te = new TypeExpression (type, loc);
4915 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
4916 if (!li.Resolve (ec))
4919 if (ec.MustCaptureVariable (li)) {
4920 ScopeInfo scope = li.Block.CreateScopeInfo ();
4921 var = scope.AddLocal (li);
4928 public Variable Variable {
4929 get { return var != null ? var : li.Variable; }
4932 public override void Emit (EmitContext ec)
4934 Variable.EmitInstance (ec);
4938 public void EmitLoadAddress (EmitContext ec)
4940 Variable.EmitInstance (ec);
4941 Variable.EmitAddressOf (ec);
4944 public void Store (EmitContext ec, Expression right_side)
4946 Variable.EmitInstance (ec);
4947 right_side.Emit (ec);
4948 Variable.EmitAssign (ec);
4951 public void EmitThis (EmitContext ec)
4953 Variable.EmitInstance (ec);
4956 public void EmitStore (EmitContext ec)
4958 Variable.EmitAssign (ec);
4961 public void AddressOf (EmitContext ec, AddressOp mode)
4963 EmitLoadAddress (ec);
4967 public sealed class VarExpr : Expression
4969 public bool Handled;
4970 public VarExpr (Location loc)
4975 public override Expression DoResolve (EmitContext ec)
4980 public override void Emit (EmitContext ec)