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);
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)
1571 // This is workaround of mono bug. It can be removed when the latest corlib spreads enough
1572 if (TypeManager.IsEnumType (type.UnderlyingSystemType))
1575 if (type.UnderlyingSystemType != Child.Type)
1576 Child = Child.ConvertImplicitly (type.UnderlyingSystemType);
1580 if (!Convert.ImplicitStandardConversionExists (this, type)){
1584 return Child.ConvertImplicitly(type);
1590 /// This kind of cast is used to encapsulate Value Types in objects.
1592 /// The effect of it is to box the value type emitted by the previous
1595 public class BoxedCast : EmptyCast {
1597 public BoxedCast (Expression expr, Type target_type)
1598 : base (expr, target_type)
1600 eclass = ExprClass.Value;
1603 public override Expression DoResolve (EmitContext ec)
1605 // This should never be invoked, we are born in fully
1606 // initialized state.
1611 public override void Emit (EmitContext ec)
1615 ec.ig.Emit (OpCodes.Box, child.Type);
1619 public class UnboxCast : EmptyCast {
1620 public UnboxCast (Expression expr, Type return_type)
1621 : base (expr, return_type)
1625 public override Expression DoResolve (EmitContext ec)
1627 // This should never be invoked, we are born in fully
1628 // initialized state.
1633 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1635 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
1636 Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
1637 return base.DoResolveLValue (ec, right_side);
1640 public override void Emit (EmitContext ec)
1643 ILGenerator ig = ec.ig;
1647 if (t.IsGenericParameter || t.IsGenericType && t.IsValueType)
1648 ig.Emit (OpCodes.Unbox_Any, t);
1652 ig.Emit (OpCodes.Unbox, t);
1654 LoadFromPtr (ig, t);
1660 /// This is used to perform explicit numeric conversions.
1662 /// Explicit numeric conversions might trigger exceptions in a checked
1663 /// context, so they should generate the conv.ovf opcodes instead of
1666 public class ConvCast : EmptyCast {
1667 public enum Mode : byte {
1668 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1670 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1671 U2_I1, U2_U1, U2_I2, U2_CH,
1672 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1673 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1674 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH,
1675 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH,
1676 CH_I1, CH_U1, CH_I2,
1677 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1678 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4
1683 public ConvCast (Expression child, Type return_type, Mode m)
1684 : base (child, return_type)
1689 public override Expression DoResolve (EmitContext ec)
1691 // This should never be invoked, we are born in fully
1692 // initialized state.
1697 public override string ToString ()
1699 return String.Format ("ConvCast ({0}, {1})", mode, child);
1702 public override void Emit (EmitContext ec)
1704 ILGenerator ig = ec.ig;
1710 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1711 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1712 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1713 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1714 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1716 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1717 case Mode.U1_CH: /* nothing */ break;
1719 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1720 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1721 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1722 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1723 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1724 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1726 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1727 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1728 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1729 case Mode.U2_CH: /* nothing */ break;
1731 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1732 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1733 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1734 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1735 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1736 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1737 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1739 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1740 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1741 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1742 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1743 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1744 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1746 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1747 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1748 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1749 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1750 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1751 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1752 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1753 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1755 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1756 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1757 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1758 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1759 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1760 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1761 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1762 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1764 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1765 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1766 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1768 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1769 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1770 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1771 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1772 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1773 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1774 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1775 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1776 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1778 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1779 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1780 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1781 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1782 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1783 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1784 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1785 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1786 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1787 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1791 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
1792 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
1793 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
1794 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
1795 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
1797 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
1798 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
1800 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
1801 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
1802 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
1803 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
1804 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
1805 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
1807 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
1808 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
1809 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
1810 case Mode.U2_CH: /* nothing */ break;
1812 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
1813 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
1814 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
1815 case Mode.I4_U4: /* nothing */ break;
1816 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
1817 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
1818 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
1820 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
1821 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
1822 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
1823 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
1824 case Mode.U4_I4: /* nothing */ break;
1825 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
1827 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
1828 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
1829 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
1830 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
1831 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
1832 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
1833 case Mode.I8_U8: /* nothing */ break;
1834 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
1836 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
1837 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
1838 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
1839 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
1840 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
1841 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
1842 case Mode.U8_I8: /* nothing */ break;
1843 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
1845 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
1846 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
1847 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
1849 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
1850 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
1851 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
1852 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
1853 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
1854 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
1855 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
1856 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
1857 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
1859 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
1860 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
1861 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
1862 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
1863 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
1864 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
1865 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
1866 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
1867 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
1868 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1874 public class OpcodeCast : EmptyCast {
1878 public OpcodeCast (Expression child, Type return_type, OpCode op)
1879 : base (child, return_type)
1883 second_valid = false;
1886 public OpcodeCast (Expression child, Type return_type, OpCode op, OpCode op2)
1887 : base (child, return_type)
1892 second_valid = true;
1895 public override Expression DoResolve (EmitContext ec)
1897 // This should never be invoked, we are born in fully
1898 // initialized state.
1903 public override void Emit (EmitContext ec)
1914 /// This kind of cast is used to encapsulate a child and cast it
1915 /// to the class requested
1917 public class ClassCast : EmptyCast {
1918 public ClassCast (Expression child, Type return_type)
1919 : base (child, return_type)
1924 public override Expression DoResolve (EmitContext ec)
1926 // This should never be invoked, we are born in fully
1927 // initialized state.
1932 public override void Emit (EmitContext ec)
1936 if (TypeManager.IsGenericParameter (child.Type))
1937 ec.ig.Emit (OpCodes.Box, child.Type);
1940 if (type.IsGenericParameter)
1941 ec.ig.Emit (OpCodes.Unbox_Any, type);
1944 ec.ig.Emit (OpCodes.Castclass, type);
1949 /// SimpleName expressions are formed of a single word and only happen at the beginning
1950 /// of a dotted-name.
1952 public class SimpleName : Expression {
1954 public readonly TypeArguments Arguments;
1957 public SimpleName (string name, Location l)
1963 public SimpleName (string name, TypeArguments args, Location l)
1970 public SimpleName (string name, TypeParameter[] type_params, Location l)
1975 Arguments = new TypeArguments (l);
1976 foreach (TypeParameter type_param in type_params)
1977 Arguments.Add (new TypeParameterExpr (type_param, l));
1980 public static string RemoveGenericArity (string name)
1983 StringBuilder sb = null;
1985 int pos = name.IndexOf ('`', start);
1990 sb.Append (name.Substring (start));
1995 sb = new StringBuilder ();
1996 sb.Append (name.Substring (start, pos-start));
1999 while ((pos < name.Length) && Char.IsNumber (name [pos]))
2003 } while (start < name.Length);
2005 return sb.ToString ();
2008 public SimpleName GetMethodGroup ()
2010 return new SimpleName (RemoveGenericArity (Name), Arguments, loc);
2013 public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
2015 if (ec.IsFieldInitializer)
2016 Report.Error (236, l,
2017 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2021 120, l, "`{0}': An object reference is required for the nonstatic field, method or property",
2025 public bool IdenticalNameAndTypeName (EmitContext ec, Expression resolved_to, Location loc)
2027 return resolved_to != null && resolved_to.Type != null &&
2028 resolved_to.Type.Name == Name &&
2029 (ec.DeclContainer.LookupNamespaceOrType (Name, loc, /* ignore_cs0104 = */ true) != null);
2032 public override Expression DoResolve (EmitContext ec)
2034 return SimpleNameResolve (ec, null, false);
2037 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
2039 return SimpleNameResolve (ec, right_side, false);
2043 public Expression DoResolve (EmitContext ec, bool intermediate)
2045 return SimpleNameResolve (ec, null, intermediate);
2048 private bool IsNestedChild (Type t, Type parent)
2053 while (parent != null) {
2054 parent = TypeManager.DropGenericTypeArguments (parent);
2055 if (TypeManager.IsNestedChildOf (t, parent))
2058 parent = parent.BaseType;
2064 FullNamedExpression ResolveNested (IResolveContext ec, Type t)
2066 if (!TypeManager.IsGenericTypeDefinition (t))
2069 DeclSpace ds = ec.DeclContainer;
2070 while (ds != null) {
2071 if (IsNestedChild (t, ds.TypeBuilder))
2080 Type[] gen_params = TypeManager.GetTypeArguments (t);
2082 int arg_count = Arguments != null ? Arguments.Count : 0;
2084 for (; (ds != null) && ds.IsGeneric; ds = ds.Parent) {
2085 if (arg_count + ds.CountTypeParameters == gen_params.Length) {
2086 TypeArguments new_args = new TypeArguments (loc);
2087 foreach (TypeParameter param in ds.TypeParameters)
2088 new_args.Add (new TypeParameterExpr (param, loc));
2090 if (Arguments != null)
2091 new_args.Add (Arguments);
2093 return new ConstructedType (t, new_args, loc);
2100 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2102 FullNamedExpression fne = ec.GenericDeclContainer.LookupGeneric (Name, loc);
2104 return fne.ResolveAsTypeStep (ec, silent);
2106 int errors = Report.Errors;
2107 fne = ec.DeclContainer.LookupNamespaceOrType (Name, loc, /*ignore_cs0104=*/ false);
2110 if (fne.Type == null)
2113 FullNamedExpression nested = ResolveNested (ec, fne.Type);
2115 return nested.ResolveAsTypeStep (ec, false);
2117 if (Arguments != null) {
2118 ConstructedType ct = new ConstructedType (fne, Arguments, loc);
2119 return ct.ResolveAsTypeStep (ec, false);
2125 if (silent || errors != Report.Errors)
2128 MemberCore mc = ec.DeclContainer.GetDefinition (Name);
2130 Error_UnexpectedKind (ec.DeclContainer, "type", GetMemberType (mc), loc);
2134 string ns = ec.DeclContainer.NamespaceEntry.NS.Name;
2135 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2136 foreach (Assembly a in RootNamespace.Global.Assemblies) {
2137 Type type = a.GetType (fullname);
2139 Report.SymbolRelatedToPreviousError (type);
2140 Expression.ErrorIsInaccesible (loc, fullname);
2145 Type t = ec.DeclContainer.LookupAnyGeneric (Name);
2147 Namespace.Error_InvalidNumberOfTypeArguments (t, loc);
2151 NamespaceEntry.Error_NamespaceNotFound (loc, Name);
2155 // TODO: I am still not convinced about this. If someone else will need it
2156 // implement this as virtual property in MemberCore hierarchy
2157 public static string GetMemberType (MemberCore mc)
2163 if (mc is FieldBase)
2165 if (mc is MethodCore)
2167 if (mc is EnumMember)
2175 Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2181 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2185 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2192 /// 7.5.2: Simple Names.
2194 /// Local Variables and Parameters are handled at
2195 /// parse time, so they never occur as SimpleNames.
2197 /// The `intermediate' flag is used by MemberAccess only
2198 /// and it is used to inform us that it is ok for us to
2199 /// avoid the static check, because MemberAccess might end
2200 /// up resolving the Name as a Type name and the access as
2201 /// a static type access.
2203 /// ie: Type Type; .... { Type.GetType (""); }
2205 /// Type is both an instance variable and a Type; Type.GetType
2206 /// is the static method not an instance method of type.
2208 Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2210 Expression e = null;
2213 // Stage 1: Performed by the parser (binding to locals or parameters).
2215 Block current_block = ec.CurrentBlock;
2216 if (current_block != null){
2217 LocalInfo vi = current_block.GetLocalInfo (Name);
2219 if (Arguments != null) {
2220 Report.Error (307, loc,
2221 "The variable `{0}' cannot be used with type arguments",
2226 LocalVariableReference var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2227 if (right_side != null) {
2228 return var.ResolveLValue (ec, right_side, loc);
2230 ResolveFlags rf = ResolveFlags.VariableOrValue;
2232 rf |= ResolveFlags.DisableFlowAnalysis;
2233 return var.Resolve (ec, rf);
2237 ParameterReference pref = current_block.Toplevel.GetParameterReference (Name, loc);
2239 if (Arguments != null) {
2240 Report.Error (307, loc,
2241 "The variable `{0}' cannot be used with type arguments",
2246 if (right_side != null)
2247 return pref.ResolveLValue (ec, right_side, loc);
2249 return pref.Resolve (ec);
2254 // Stage 2: Lookup members
2257 DeclSpace lookup_ds = ec.DeclContainer;
2258 Type almost_matched_type = null;
2259 ArrayList almost_matched = null;
2261 if (lookup_ds.TypeBuilder == null)
2264 e = MemberLookup (ec.ContainerType, lookup_ds.TypeBuilder, Name, loc);
2268 if (almost_matched == null && almostMatchedMembers.Count > 0) {
2269 almost_matched_type = lookup_ds.TypeBuilder;
2270 almost_matched = (ArrayList) almostMatchedMembers.Clone ();
2273 lookup_ds =lookup_ds.Parent;
2274 } while (lookup_ds != null);
2276 if (e == null && ec.ContainerType != null)
2277 e = MemberLookup (ec.ContainerType, ec.ContainerType, Name, loc);
2280 if (almost_matched == null && almostMatchedMembers.Count > 0) {
2281 almost_matched_type = ec.ContainerType;
2282 almost_matched = (ArrayList) almostMatchedMembers.Clone ();
2284 e = ResolveAsTypeStep (ec, true);
2288 if (almost_matched != null)
2289 almostMatchedMembers = almost_matched;
2290 if (almost_matched_type == null)
2291 almost_matched_type = ec.ContainerType;
2292 MemberLookupFailed (ec.ContainerType, null, almost_matched_type, ((SimpleName) this).Name, ec.DeclContainer.Name, true, loc);
2296 if (e is TypeExpr) {
2297 if (Arguments == null)
2300 ConstructedType ct = new ConstructedType (
2301 (FullNamedExpression) e, Arguments, loc);
2302 return ct.ResolveAsTypeStep (ec, false);
2305 if (e is MemberExpr) {
2306 MemberExpr me = (MemberExpr) e;
2309 if (me.IsInstance) {
2310 if (ec.IsStatic || ec.IsFieldInitializer) {
2312 // Note that an MemberExpr can be both IsInstance and IsStatic.
2313 // An unresolved MethodGroupExpr can contain both kinds of methods
2314 // and each predicate is true if the MethodGroupExpr contains
2315 // at least one of that kind of method.
2319 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2320 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2321 return EmptyExpression.Null;
2325 // Pass the buck to MemberAccess and Invocation.
2327 left = EmptyExpression.Null;
2329 left = ec.GetThis (loc);
2332 left = new TypeExpression (ec.ContainerType, loc);
2335 e = me.ResolveMemberAccess (ec, left, loc, null);
2339 me = e as MemberExpr;
2343 if (Arguments != null) {
2344 MethodGroupExpr mg = me as MethodGroupExpr;
2348 return mg.ResolveGeneric (ec, Arguments);
2351 if (!me.IsStatic && (me.InstanceExpression != null) &&
2352 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2353 me.InstanceExpression.Type != me.DeclaringType &&
2354 !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2355 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2356 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2357 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2361 return (right_side != null)
2362 ? me.DoResolveLValue (ec, right_side)
2363 : me.DoResolve (ec);
2369 public override void Emit (EmitContext ec)
2372 // If this is ever reached, then we failed to
2373 // find the name as a namespace
2376 Error (103, "The name `" + Name +
2377 "' does not exist in the class `" +
2378 ec.DeclContainer.Name + "'");
2381 public override string ToString ()
2386 public override string GetSignatureForError ()
2391 protected override void CloneTo (CloneContext clonectx, Expression target)
2393 // CloneTo: Nothing, we do not keep any state on this expression
2398 /// Represents a namespace or a type. The name of the class was inspired by
2399 /// section 10.8.1 (Fully Qualified Names).
2401 public abstract class FullNamedExpression : Expression {
2402 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2407 public abstract string FullName {
2413 /// Expression that evaluates to a type
2415 public abstract class TypeExpr : FullNamedExpression {
2416 override public FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2418 TypeExpr t = DoResolveAsTypeStep (ec);
2422 eclass = ExprClass.Type;
2426 override public Expression DoResolve (EmitContext ec)
2428 return ResolveAsTypeTerminal (ec, false);
2431 override public void Emit (EmitContext ec)
2433 throw new Exception ("Should never be called");
2436 public virtual bool CheckAccessLevel (DeclSpace ds)
2438 return ds.CheckAccessLevel (Type);
2441 public virtual bool AsAccessible (DeclSpace ds, int flags)
2443 return ds.AsAccessible (Type, flags);
2446 public virtual bool IsClass {
2447 get { return Type.IsClass; }
2450 public virtual bool IsValueType {
2451 get { return Type.IsValueType; }
2454 public virtual bool IsInterface {
2455 get { return Type.IsInterface; }
2458 public virtual bool IsSealed {
2459 get { return Type.IsSealed; }
2462 public virtual bool CanInheritFrom ()
2464 if (Type == TypeManager.enum_type ||
2465 (Type == TypeManager.value_type && RootContext.StdLib) ||
2466 Type == TypeManager.multicast_delegate_type ||
2467 Type == TypeManager.delegate_type ||
2468 Type == TypeManager.array_type)
2474 protected abstract TypeExpr DoResolveAsTypeStep (IResolveContext ec);
2476 public abstract string Name {
2480 public override bool Equals (object obj)
2482 TypeExpr tobj = obj as TypeExpr;
2486 return Type == tobj.Type;
2489 public override int GetHashCode ()
2491 return Type.GetHashCode ();
2494 public override string ToString ()
2501 /// Fully resolved Expression that already evaluated to a type
2503 public class TypeExpression : TypeExpr {
2504 public TypeExpression (Type t, Location l)
2507 eclass = ExprClass.Type;
2511 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2516 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2521 public override string Name {
2522 get { return Type.ToString (); }
2525 public override string FullName {
2526 get { return Type.FullName; }
2531 /// Used to create types from a fully qualified name. These are just used
2532 /// by the parser to setup the core types. A TypeLookupExpression is always
2533 /// classified as a type.
2535 public sealed class TypeLookupExpression : TypeExpr {
2536 readonly string name;
2538 public TypeLookupExpression (string name)
2541 eclass = ExprClass.Type;
2544 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2546 // It's null for corlib compilation only
2548 return DoResolveAsTypeStep (ec);
2553 static readonly char [] dot_array = { '.' };
2554 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2556 // If name is of the form `N.I', first lookup `N', then search a member `I' in it.
2558 string lookup_name = name;
2559 int pos = name.IndexOf ('.');
2561 rest = name.Substring (pos + 1);
2562 lookup_name = name.Substring (0, pos);
2565 FullNamedExpression resolved = RootNamespace.Global.Lookup (ec.DeclContainer, lookup_name, Location.Null);
2567 if (resolved != null && rest != null) {
2568 // Now handle the rest of the the name.
2569 string [] elements = rest.Split (dot_array);
2571 int count = elements.Length;
2573 while (i < count && resolved != null && resolved is Namespace) {
2574 Namespace ns = resolved as Namespace;
2575 element = elements [i++];
2576 lookup_name += "." + element;
2577 resolved = ns.Lookup (ec.DeclContainer, element, Location.Null);
2580 if (resolved != null && resolved is TypeExpr) {
2581 Type t = ((TypeExpr) resolved).Type;
2583 if (!ec.DeclContainer.CheckAccessLevel (t)) {
2585 lookup_name = t.FullName;
2592 t = TypeManager.GetNestedType (t, elements [i++]);
2597 if (resolved == null) {
2598 NamespaceEntry.Error_NamespaceNotFound (loc, lookup_name);
2602 if (!(resolved is TypeExpr)) {
2603 resolved.Error_UnexpectedKind (ec.DeclContainer, "type", loc);
2607 type = resolved.Type;
2611 public override string Name {
2612 get { return name; }
2615 public override string FullName {
2616 get { return name; }
2619 protected override void CloneTo (CloneContext clonectx, Expression target)
2621 // CloneTo: Nothing, we do not keep any state on this expression
2626 /// Represents an "unbound generic type", ie. typeof (Foo<>).
2629 public class UnboundTypeExpression : TypeExpr
2633 public UnboundTypeExpression (MemberName name, Location l)
2639 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2642 if (name.Left != null) {
2643 Expression lexpr = name.Left.GetTypeExpression ();
2644 expr = new MemberAccess (lexpr, name.Basename);
2646 expr = new SimpleName (name.Basename, loc);
2649 FullNamedExpression fne = expr.ResolveAsTypeStep (ec, false);
2654 return new TypeExpression (type, loc);
2657 public override string Name {
2658 get { return name.FullName; }
2661 public override string FullName {
2662 get { return name.FullName; }
2666 public class TypeAliasExpression : TypeExpr {
2667 FullNamedExpression alias;
2672 public TypeAliasExpression (FullNamedExpression alias, TypeArguments args, Location l)
2678 eclass = ExprClass.Type;
2680 name = alias.FullName + "<" + args.ToString () + ">";
2682 name = alias.FullName;
2685 public override string Name {
2686 get { return alias.FullName; }
2689 public override string FullName {
2690 get { return name; }
2693 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2695 texpr = alias.ResolveAsTypeTerminal (ec, false);
2699 Type type = texpr.Type;
2700 int num_args = TypeManager.GetNumberOfTypeArguments (type);
2703 if (num_args == 0) {
2704 Report.Error (308, loc,
2705 "The non-generic type `{0}' cannot " +
2706 "be used with type arguments.",
2707 TypeManager.CSharpName (type));
2711 ConstructedType ctype = new ConstructedType (type, args, loc);
2712 return ctype.ResolveAsTypeTerminal (ec, false);
2713 } else if (num_args > 0) {
2714 Report.Error (305, loc,
2715 "Using the generic type `{0}' " +
2716 "requires {1} type arguments",
2717 TypeManager.CSharpName (type), num_args.ToString ());
2724 public override bool CheckAccessLevel (DeclSpace ds)
2726 return texpr.CheckAccessLevel (ds);
2729 public override bool AsAccessible (DeclSpace ds, int flags)
2731 return texpr.AsAccessible (ds, flags);
2734 public override bool IsClass {
2735 get { return texpr.IsClass; }
2738 public override bool IsValueType {
2739 get { return texpr.IsValueType; }
2742 public override bool IsInterface {
2743 get { return texpr.IsInterface; }
2746 public override bool IsSealed {
2747 get { return texpr.IsSealed; }
2752 /// This class denotes an expression which evaluates to a member
2753 /// of a struct or a class.
2755 public abstract class MemberExpr : Expression
2758 /// The name of this member.
2760 public abstract string Name {
2765 /// Whether this is an instance member.
2767 public abstract bool IsInstance {
2772 /// Whether this is a static member.
2774 public abstract bool IsStatic {
2779 /// The type which declares this member.
2781 public abstract Type DeclaringType {
2786 /// The instance expression associated with this member, if it's a
2787 /// non-static member.
2789 public Expression InstanceExpression;
2791 public static void error176 (Location loc, string name)
2793 Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
2794 "with an instance reference, qualify it with a type name instead", name);
2797 // TODO: possible optimalization
2798 // Cache resolved constant result in FieldBuilder <-> expression map
2799 public virtual Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
2800 SimpleName original)
2804 // original == null || original.Resolve (...) ==> left
2807 if (left is TypeExpr) {
2809 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
2817 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
2820 error176 (loc, GetSignatureForError ());
2824 InstanceExpression = left;
2829 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
2834 if (InstanceExpression == EmptyExpression.Null) {
2835 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
2839 if (InstanceExpression.Type.IsValueType) {
2840 if (InstanceExpression is IMemoryLocation) {
2841 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
2843 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
2844 InstanceExpression.Emit (ec);
2846 t.AddressOf (ec, AddressOp.Store);
2849 InstanceExpression.Emit (ec);
2851 if (prepare_for_load)
2852 ec.ig.Emit (OpCodes.Dup);
2857 /// Represents group of extension methods
2859 public class ExtensionMethodGroupExpr : MethodGroupExpr
2861 NamespaceEntry namespaceEntry;
2862 readonly bool usingCandidates;
2864 public ExtensionMethodGroupExpr (ArrayList list, NamespaceEntry n, bool usingCandidates,
2865 Type extensionType, Location l)
2868 this.namespaceEntry = n;
2869 this.usingCandidates = usingCandidates;
2870 this.type = extensionType;
2873 public override bool IsBase {
2874 get { return true; }
2877 public override bool IsStatic {
2878 get { return true; }
2881 public bool IsTopLevel {
2882 get { return namespaceEntry == null; }
2885 public override MethodBase OverloadExtensionResolve (EmitContext ec, ref ArrayList arguments, ref MethodGroupExpr mg,
2886 Expression expr, Location loc)
2888 if (arguments == null)
2889 arguments = new ArrayList (1);
2891 Argument a = new Argument (((MemberAccess)expr).Expr);
2892 a.Resolve (ec, loc);
2893 arguments.Insert (0, a);
2897 MethodBase method = mg.OverloadResolve (ec, arguments, true, loc);
2901 ExtensionMethodGroupExpr e = namespaceEntry.LookupExtensionMethod (type, usingCandidates, Name);
2903 return mg.OverloadResolve (ec, arguments, false, loc);
2906 namespaceEntry = e.namespaceEntry;
2912 /// MethodGroup Expression.
2914 /// This is a fully resolved expression that evaluates to a type
2916 public class MethodGroupExpr : MemberExpr {
2917 public MethodBase [] Methods;
2918 bool has_type_arguments = false;
2919 bool identical_type_name = false;
2922 public MethodGroupExpr (MemberInfo [] mi, Location l)
2924 Methods = new MethodBase [mi.Length];
2925 mi.CopyTo (Methods, 0);
2926 eclass = ExprClass.MethodGroup;
2928 // Set the type to something that will never be useful, which will
2929 // trigger the proper conversions.
2930 type = typeof (MethodGroupExpr);
2934 public MethodGroupExpr (ArrayList list, Location l)
2936 Methods = new MethodBase [list.Count];
2939 list.CopyTo (Methods, 0);
2941 foreach (MemberInfo m in list){
2942 if (!(m is MethodBase)){
2943 Console.WriteLine ("Name " + m.Name);
2944 Console.WriteLine ("Found a: " + m.GetType ().FullName);
2951 eclass = ExprClass.MethodGroup;
2952 type = TypeManager.object_type;
2955 public override Type DeclaringType {
2958 // We assume that the top-level type is in the end
2960 return Methods [Methods.Length - 1].DeclaringType;
2961 //return Methods [0].DeclaringType;
2965 public bool HasTypeArguments {
2967 return has_type_arguments;
2971 has_type_arguments = value;
2975 public bool IdenticalTypeName {
2977 return identical_type_name;
2981 identical_type_name = value;
2985 public virtual bool IsBase {
2994 public override string GetSignatureForError ()
2996 return TypeManager.CSharpSignature (Methods [0]);
2999 public override string Name {
3001 return Methods [0].Name;
3005 public override bool IsInstance {
3007 foreach (MethodBase mb in Methods)
3015 public override bool IsStatic {
3017 foreach (MethodBase mb in Methods)
3026 /// Determines "better conversion" as specified in 14.4.2.3
3028 /// Returns : p if a->p is better,
3029 /// q if a->q is better,
3030 /// null if neither is better
3032 static Type BetterConversion (EmitContext ec, Argument a, Type p, Type q)
3034 Type argument_type = TypeManager.TypeToCoreType (a.Type);
3035 Expression argument_expr = a.Expr;
3037 if (argument_type == null)
3038 throw new Exception ("Expression of type " + a.Expr +
3039 " does not resolve its type");
3041 if (p == null || q == null)
3042 throw new InternalErrorException ("BetterConversion Got a null conversion");
3047 if (argument_expr is NullLiteral)
3050 // If the argument is null and one of the types to compare is 'object' and
3051 // the other is a reference type, we prefer the other.
3053 // This follows from the usual rules:
3054 // * There is an implicit conversion from 'null' to type 'object'
3055 // * There is an implicit conversion from 'null' to any reference type
3056 // * There is an implicit conversion from any reference type to type 'object'
3057 // * There is no implicit conversion from type 'object' to other reference types
3058 // => Conversion of 'null' to a reference type is better than conversion to 'object'
3060 // FIXME: This probably isn't necessary, since the type of a NullLiteral is the
3061 // null type. I think it used to be 'object' and thus needed a special
3062 // case to avoid the immediately following two checks.
3064 if (!p.IsValueType && q == TypeManager.object_type)
3066 if (!q.IsValueType && p == TypeManager.object_type)
3070 if (argument_type == p)
3073 if (argument_type == q)
3076 Expression p_tmp = new EmptyExpression (p);
3077 Expression q_tmp = new EmptyExpression (q);
3079 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3080 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3082 if (p_to_q && !q_to_p)
3085 if (q_to_p && !p_to_q)
3088 if (p == TypeManager.sbyte_type)
3089 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3090 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3092 if (q == TypeManager.sbyte_type)
3093 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3094 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3097 if (p == TypeManager.short_type)
3098 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3099 q == TypeManager.uint64_type)
3101 if (q == TypeManager.short_type)
3102 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3103 p == TypeManager.uint64_type)
3106 if (p == TypeManager.int32_type)
3107 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3109 if (q == TypeManager.int32_type)
3110 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3113 if (p == TypeManager.int64_type)
3114 if (q == TypeManager.uint64_type)
3116 if (q == TypeManager.int64_type)
3117 if (p == TypeManager.uint64_type)
3124 /// Determines "Better function" between candidate
3125 /// and the current best match
3128 /// Returns a boolean indicating :
3129 /// false if candidate ain't better
3130 /// true if candidate is better than the current best match
3132 static bool BetterFunction (EmitContext ec, ArrayList args, int argument_count,
3133 MethodBase candidate, bool candidate_params,
3134 MethodBase best, bool best_params)
3136 ParameterData candidate_pd = TypeManager.GetParameterData (candidate);
3137 ParameterData best_pd = TypeManager.GetParameterData (best);
3139 bool better_at_least_one = false;
3141 for (int j = 0, c_idx = 0, b_idx = 0; j < argument_count; ++j, ++c_idx, ++b_idx)
3143 Argument a = (Argument) args [j];
3145 Type ct = TypeManager.TypeToCoreType (candidate_pd.ParameterType (c_idx));
3146 Type bt = TypeManager.TypeToCoreType (best_pd.ParameterType (b_idx));
3148 if (candidate_params && candidate_pd.ParameterModifier (c_idx) == Parameter.Modifier.PARAMS)
3150 ct = TypeManager.GetElementType (ct);
3154 if (best_params && best_pd.ParameterModifier (b_idx) == Parameter.Modifier.PARAMS)
3156 bt = TypeManager.GetElementType (bt);
3164 Type better = BetterConversion (ec, a, ct, bt);
3166 // for each argument, the conversion to 'ct' should be no worse than
3167 // the conversion to 'bt'.
3171 // for at least one argument, the conversion to 'ct' should be better than
3172 // the conversion to 'bt'.
3174 better_at_least_one = true;
3177 if (better_at_least_one)
3181 // This handles the case
3183 // Add (float f1, float f2, float f3);
3184 // Add (params decimal [] foo);
3186 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3187 // first candidate would've chosen as better.
3193 // The two methods have equal parameter types. Now apply tie-breaking rules
3195 if (TypeManager.IsGenericMethod (best) && !TypeManager.IsGenericMethod (candidate))
3197 if (!TypeManager.IsGenericMethod (best) && TypeManager.IsGenericMethod (candidate))
3201 // This handles the following cases:
3203 // Trim () is better than Trim (params char[] chars)
3204 // Concat (string s1, string s2, string s3) is better than
3205 // Concat (string s1, params string [] srest)
3206 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3208 if (!candidate_params && best_params)
3210 if (candidate_params && !best_params)
3213 int candidate_param_count = candidate_pd.Count;
3214 int best_param_count = best_pd.Count;
3216 if (candidate_param_count != best_param_count)
3217 // can only happen if (candidate_params && best_params)
3218 return candidate_param_count > best_param_count;
3221 // now, both methods have the same number of parameters, and the parameters have the same types
3222 // Pick the "more specific" signature
3225 MethodBase orig_candidate = TypeManager.DropGenericMethodArguments (candidate);
3226 MethodBase orig_best = TypeManager.DropGenericMethodArguments (best);
3228 ParameterData orig_candidate_pd = TypeManager.GetParameterData (orig_candidate);
3229 ParameterData orig_best_pd = TypeManager.GetParameterData (orig_best);
3231 bool specific_at_least_once = false;
3232 for (int j = 0; j < candidate_param_count; ++j)
3234 Type ct = TypeManager.TypeToCoreType (orig_candidate_pd.ParameterType (j));
3235 Type bt = TypeManager.TypeToCoreType (orig_best_pd.ParameterType (j));
3238 Type specific = MoreSpecific (ct, bt);
3242 specific_at_least_once = true;
3245 if (specific_at_least_once)
3248 // FIXME: handle lifted operators
3254 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3255 SimpleName original)
3257 if (!(left is TypeExpr) &&
3258 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3259 IdenticalTypeName = true;
3261 return base.ResolveMemberAccess (ec, left, loc, original);
3264 override public Expression DoResolve (EmitContext ec)
3267 InstanceExpression = null;
3269 if (InstanceExpression != null) {
3270 InstanceExpression = InstanceExpression.DoResolve (ec);
3271 if (InstanceExpression == null)
3278 public void ReportUsageError ()
3280 Report.Error (654, loc, "Method `" + DeclaringType + "." +
3281 Name + "()' is referenced without parentheses");
3284 override public void Emit (EmitContext ec)
3286 ReportUsageError ();
3289 public static bool IsAncestralType (Type first_type, Type second_type)
3291 return first_type != second_type &&
3292 (TypeManager.IsSubclassOf (second_type, first_type) ||
3293 TypeManager.ImplementsInterface (second_type, first_type));
3296 public static bool IsOverride (MethodBase cand_method, MethodBase base_method)
3298 if (!IsAncestralType (base_method.DeclaringType, cand_method.DeclaringType))
3301 ParameterData cand_pd = TypeManager.GetParameterData (cand_method);
3302 ParameterData base_pd = TypeManager.GetParameterData (base_method);
3304 if (cand_pd.Count != base_pd.Count)
3307 for (int j = 0; j < cand_pd.Count; ++j)
3309 Parameter.Modifier cm = cand_pd.ParameterModifier (j);
3310 Parameter.Modifier bm = base_pd.ParameterModifier (j);
3311 Type ct = TypeManager.TypeToCoreType (cand_pd.ParameterType (j));
3312 Type bt = TypeManager.TypeToCoreType (base_pd.ParameterType (j));
3314 if (cm != bm || ct != bt)
3321 static Type MoreSpecific (Type p, Type q)
3323 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
3325 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
3328 if (TypeManager.HasElementType (p))
3330 Type pe = TypeManager.GetElementType (p);
3331 Type qe = TypeManager.GetElementType (q);
3332 Type specific = MoreSpecific (pe, qe);
3338 else if (TypeManager.IsGenericType (p))
3340 Type[] pargs = TypeManager.GetTypeArguments (p);
3341 Type[] qargs = TypeManager.GetTypeArguments (q);
3343 bool p_specific_at_least_once = false;
3344 bool q_specific_at_least_once = false;
3346 for (int i = 0; i < pargs.Length; i++)
3348 Type specific = MoreSpecific (pargs [i], qargs [i]);
3349 if (specific == pargs [i])
3350 p_specific_at_least_once = true;
3351 if (specific == qargs [i])
3352 q_specific_at_least_once = true;
3355 if (p_specific_at_least_once && !q_specific_at_least_once)
3357 if (!p_specific_at_least_once && q_specific_at_least_once)
3364 public virtual MethodBase OverloadExtensionResolve (EmitContext ec, ref ArrayList arguments, ref MethodGroupExpr mg,
3365 Expression expr, Location loc)
3367 MethodBase method = OverloadResolve (ec, arguments, true, loc);
3368 if (method != null) {
3373 MemberAccess mexpr = expr as MemberAccess;
3374 if (mexpr != null) {
3375 ExtensionMethodGroupExpr emg = ec.DeclContainer.LookupExtensionMethod (mexpr.Expr.Type, Name);
3377 return OverloadExtensionResolve (ec, ref arguments, ref mg, expr, loc);
3381 return OverloadResolve (ec, arguments, false, loc);
3385 /// Find the Applicable Function Members (7.4.2.1)
3387 /// me: Method Group expression with the members to select.
3388 /// it might contain constructors or methods (or anything
3389 /// that maps to a method).
3391 /// Arguments: ArrayList containing resolved Argument objects.
3393 /// loc: The location if we want an error to be reported, or a Null
3394 /// location for "probing" purposes.
3396 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3397 /// that is the best match of me on Arguments.
3400 public virtual MethodBase OverloadResolve (EmitContext ec, ArrayList Arguments,
3401 bool may_fail, Location loc)
3403 MethodBase method = null;
3404 bool method_params = false;
3405 Type applicable_type = null;
3407 ArrayList candidates = new ArrayList (2);
3408 ArrayList candidate_overrides = null;
3411 // Used to keep a map between the candidate
3412 // and whether it is being considered in its
3413 // normal or expanded form
3415 // false is normal form, true is expanded form
3417 Hashtable candidate_to_form = null;
3419 if (Arguments != null)
3420 arg_count = Arguments.Count;
3422 if (RootContext.Version == LanguageVersion.ISO_1 && Name == "Invoke" && TypeManager.IsDelegateType (DeclaringType)) {
3424 Report.Error (1533, loc, "Invoke cannot be called directly on a delegate");
3428 int nmethods = Methods.Length;
3432 // Methods marked 'override' don't take part in 'applicable_type'
3433 // computation, nor in the actual overload resolution.
3434 // However, they still need to be emitted instead of a base virtual method.
3435 // So, we salt them away into the 'candidate_overrides' array.
3437 // In case of reflected methods, we replace each overriding method with
3438 // its corresponding base virtual method. This is to improve compatibility
3439 // with non-C# libraries which change the visibility of overrides (#75636)
3442 for (int i = 0; i < Methods.Length; ++i) {
3443 MethodBase m = Methods [i];
3445 Type [] gen_args = null;
3446 if (m.IsGenericMethod && !m.IsGenericMethodDefinition)
3447 gen_args = m.GetGenericArguments ();
3449 if (TypeManager.IsOverride (m)) {
3450 if (candidate_overrides == null)
3451 candidate_overrides = new ArrayList ();
3452 candidate_overrides.Add (m);
3453 m = TypeManager.TryGetBaseDefinition (m);
3455 if (m != null && gen_args != null) {
3456 if (!m.IsGenericMethodDefinition)
3457 throw new InternalErrorException ("GetBaseDefinition didn't return a GenericMethodDefinition");
3458 m = ((MethodInfo) m).MakeGenericMethod (gen_args);
3468 int applicable_errors = Report.Errors;
3471 // First we construct the set of applicable methods
3473 bool is_sorted = true;
3474 for (int i = 0; i < nmethods; i++) {
3475 Type decl_type = Methods [i].DeclaringType;
3478 // If we have already found an applicable method
3479 // we eliminate all base types (Section 14.5.5.1)
3481 if (applicable_type != null && IsAncestralType (decl_type, applicable_type))
3485 // Check if candidate is applicable (section 14.4.2.1)
3486 // Is candidate applicable in normal form?
3488 bool is_applicable = Invocation.IsApplicable (ec, this, Arguments, arg_count, ref Methods [i]);
3490 if (!is_applicable && Invocation.IsParamsMethodApplicable (ec, this, Arguments, arg_count, ref Methods [i])) {
3491 MethodBase candidate = Methods [i];
3492 if (candidate_to_form == null)
3493 candidate_to_form = new PtrHashtable ();
3494 candidate_to_form [candidate] = candidate;
3495 // Candidate is applicable in expanded form
3496 is_applicable = true;
3502 candidates.Add (Methods [i]);
3504 if (applicable_type == null)
3505 applicable_type = decl_type;
3506 else if (applicable_type != decl_type) {
3508 if (IsAncestralType (applicable_type, decl_type))
3509 applicable_type = decl_type;
3513 if (applicable_errors != Report.Errors)
3516 int candidate_top = candidates.Count;
3518 if (applicable_type == null) {
3520 // Okay so we have failed to find anything so we
3521 // return by providing info about the closest match
3523 int errors = Report.Errors;
3524 for (int i = 0; i < nmethods; ++i) {
3525 MethodBase c = Methods [i];
3526 ParameterData pd = TypeManager.GetParameterData (c);
3528 if (pd.Count != arg_count)
3532 if (!TypeManager.InferTypeArguments (Arguments, ref c))
3534 if (TypeManager.IsGenericMethodDefinition (c))
3538 Invocation.VerifyArgumentsCompat (ec, Arguments, arg_count,
3539 c, false, null, may_fail, loc);
3541 if (!may_fail && errors == Report.Errors)
3542 throw new InternalErrorException (
3543 "VerifyArgumentsCompat and IsApplicable do not agree; " +
3544 "likely reason: ImplicitConversion and ImplicitConversionExists have gone out of sync");
3549 if (!may_fail && errors == Report.Errors) {
3550 string report_name = Name;
3551 if (report_name == ".ctor")
3552 report_name = TypeManager.CSharpName (DeclaringType);
3558 for (int i = 0; i < Methods.Length; ++i) {
3559 MethodBase c = Methods [i];
3560 ParameterData pd = TypeManager.GetParameterData (c);
3562 if (pd.Count != arg_count)
3565 if (TypeManager.InferTypeArguments (Arguments, ref c))
3569 411, loc, "The type arguments for " +
3570 "method `{0}' cannot be inferred from " +
3571 "the usage. Try specifying the type " +
3572 "arguments explicitly.", report_name);
3577 Invocation.Error_WrongNumArguments (loc, report_name, arg_count);
3585 // At this point, applicable_type is _one_ of the most derived types
3586 // in the set of types containing the methods in this MethodGroup.
3587 // Filter the candidates so that they only contain methods from the
3588 // most derived types.
3591 int finalized = 0; // Number of finalized candidates
3594 // Invariant: applicable_type is a most derived type
3596 // We'll try to complete Section 14.5.5.1 for 'applicable_type' by
3597 // eliminating all it's base types. At the same time, we'll also move
3598 // every unrelated type to the end of the array, and pick the next
3599 // 'applicable_type'.
3601 Type next_applicable_type = null;
3602 int j = finalized; // where to put the next finalized candidate
3603 int k = finalized; // where to put the next undiscarded candidate
3604 for (int i = finalized; i < candidate_top; ++i) {
3605 MethodBase candidate = (MethodBase) candidates [i];
3606 Type decl_type = candidate.DeclaringType;
3608 if (decl_type == applicable_type) {
3609 candidates [k++] = candidates [j];
3610 candidates [j++] = candidates [i];
3614 if (IsAncestralType (decl_type, applicable_type))
3617 if (next_applicable_type != null &&
3618 IsAncestralType (decl_type, next_applicable_type))
3621 candidates [k++] = candidates [i];
3623 if (next_applicable_type == null ||
3624 IsAncestralType (next_applicable_type, decl_type))
3625 next_applicable_type = decl_type;
3628 applicable_type = next_applicable_type;
3631 } while (applicable_type != null);
3635 // Now we actually find the best method
3638 method = (MethodBase) candidates [0];
3639 method_params = candidate_to_form != null && candidate_to_form.Contains (method);
3640 for (int ix = 1; ix < candidate_top; ix++) {
3641 MethodBase candidate = (MethodBase) candidates [ix];
3643 if (candidate == method)
3646 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
3648 if (BetterFunction (ec, Arguments, arg_count,
3649 candidate, cand_params,
3650 method, method_params)) {
3652 method_params = cand_params;
3656 // Now check that there are no ambiguities i.e the selected method
3657 // should be better than all the others
3659 MethodBase ambiguous = null;
3660 for (int ix = 0; ix < candidate_top; ix++) {
3661 MethodBase candidate = (MethodBase) candidates [ix];
3663 if (candidate == method)
3666 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
3667 if (!BetterFunction (ec, Arguments, arg_count,
3668 method, method_params,
3669 candidate, cand_params))
3672 Report.SymbolRelatedToPreviousError (candidate);
3673 ambiguous = candidate;
3677 if (ambiguous != null) {
3678 Report.SymbolRelatedToPreviousError (method);
3679 Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
3680 TypeManager.CSharpSignature (ambiguous), TypeManager.CSharpSignature (method));
3685 // If the method is a virtual function, pick an override closer to the LHS type.
3687 if (!IsBase && method.IsVirtual) {
3688 if (TypeManager.IsOverride (method))
3689 throw new InternalErrorException (
3690 "Should not happen. An 'override' method took part in overload resolution: " + method);
3692 if (candidate_overrides != null)
3693 foreach (MethodBase candidate in candidate_overrides) {
3694 if (IsOverride (candidate, method))
3700 // And now check if the arguments are all
3701 // compatible, perform conversions if
3702 // necessary etc. and return if everything is
3705 if (!Invocation.VerifyArgumentsCompat (ec, Arguments, arg_count, method,
3706 method_params, null, may_fail, loc))
3712 MethodBase the_method = TypeManager.DropGenericMethodArguments (method);
3714 if (the_method.IsGenericMethodDefinition &&
3715 !ConstraintChecker.CheckConstraints (ec, the_method, method, loc))
3719 IMethodData data = TypeManager.GetMethod (the_method);
3721 data.SetMemberIsUsed ();
3727 bool RemoveMethods (bool keep_static)
3729 ArrayList smethods = new ArrayList ();
3731 foreach (MethodBase mb in Methods){
3732 if (mb.IsStatic == keep_static)
3736 if (smethods.Count == 0)
3739 Methods = new MethodBase [smethods.Count];
3740 smethods.CopyTo (Methods, 0);
3746 /// Removes any instance methods from the MethodGroup, returns
3747 /// false if the resulting set is empty.
3749 public bool RemoveInstanceMethods ()
3751 return RemoveMethods (true);
3755 /// Removes any static methods from the MethodGroup, returns
3756 /// false if the resulting set is empty.
3758 public bool RemoveStaticMethods ()
3760 return RemoveMethods (false);
3763 public Expression ResolveGeneric (EmitContext ec, TypeArguments args)
3766 if (args.Resolve (ec) == false)
3769 Type[] atypes = args.Arguments;
3771 int first_count = 0;
3772 MethodInfo first = null;
3774 ArrayList list = new ArrayList ();
3775 foreach (MethodBase mb in Methods) {
3776 MethodInfo mi = mb as MethodInfo;
3777 if ((mi == null) || !mi.IsGenericMethod)
3780 Type[] gen_params = mi.GetGenericArguments ();
3782 if (first == null) {
3784 first_count = gen_params.Length;
3787 if (gen_params.Length != atypes.Length)
3790 list.Add (mi.MakeGenericMethod (atypes));
3793 if (list.Count > 0) {
3794 MethodGroupExpr new_mg = new MethodGroupExpr (list, Location);
3795 new_mg.InstanceExpression = InstanceExpression;
3796 new_mg.HasTypeArguments = true;
3797 new_mg.IsBase = IsBase;
3803 305, loc, "Using the generic method `{0}' " +
3804 "requires {1} type arguments", Name,
3805 first_count.ToString ());
3808 308, loc, "The non-generic method `{0}' " +
3809 "cannot be used with type arguments", Name);
3813 throw new NotImplementedException ();
3819 /// Fully resolved expression that evaluates to a Field
3821 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariable {
3822 public readonly FieldInfo FieldInfo;
3823 VariableInfo variable_info;
3825 LocalTemporary temp;
3827 bool in_initializer;
3829 public FieldExpr (FieldInfo fi, Location l, bool in_initializer):
3832 this.in_initializer = in_initializer;
3835 public FieldExpr (FieldInfo fi, Location l)
3838 eclass = ExprClass.Variable;
3839 type = TypeManager.TypeToCoreType (fi.FieldType);
3843 public override string Name {
3845 return FieldInfo.Name;
3849 public override bool IsInstance {
3851 return !FieldInfo.IsStatic;
3855 public override bool IsStatic {
3857 return FieldInfo.IsStatic;
3861 public override Type DeclaringType {
3863 return FieldInfo.DeclaringType;
3867 public override string GetSignatureForError ()
3869 return TypeManager.GetFullNameSignature (FieldInfo);
3872 public VariableInfo VariableInfo {
3874 return variable_info;
3878 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3879 SimpleName original)
3881 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
3883 Type t = fi.FieldType;
3885 if (fi.IsLiteral || (fi.IsInitOnly && t == TypeManager.decimal_type)) {
3886 IConstant ic = TypeManager.GetConstant (fi);
3889 ic = new ExternalConstant (fi);
3891 ic = ExternalConstant.CreateDecimal (fi);
3893 return base.ResolveMemberAccess (ec, left, loc, original);
3896 TypeManager.RegisterConstant (fi, ic);
3899 bool left_is_type = left is TypeExpr;
3900 if (!left_is_type && (original == null || !original.IdenticalNameAndTypeName (ec, left, loc))) {
3901 Report.SymbolRelatedToPreviousError (FieldInfo);
3902 error176 (loc, TypeManager.GetFullNameSignature (FieldInfo));
3906 if (ic.ResolveValue ()) {
3907 if (!ec.IsInObsoleteScope)
3908 ic.CheckObsoleteness (loc);
3911 return ic.CreateConstantReference (loc);
3914 if (t.IsPointer && !ec.InUnsafe) {
3919 return base.ResolveMemberAccess (ec, left, loc, original);
3922 override public Expression DoResolve (EmitContext ec)
3924 return DoResolve (ec, false, false);
3927 Expression DoResolve (EmitContext ec, bool lvalue_instance, bool out_access)
3929 if (!FieldInfo.IsStatic){
3930 if (InstanceExpression == null){
3932 // This can happen when referencing an instance field using
3933 // a fully qualified type expression: TypeName.InstanceField = xxx
3935 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3939 // Resolve the field's instance expression while flow analysis is turned
3940 // off: when accessing a field "a.b", we must check whether the field
3941 // "a.b" is initialized, not whether the whole struct "a" is initialized.
3943 if (lvalue_instance) {
3944 using (ec.With (EmitContext.Flags.DoFlowAnalysis, false)) {
3945 Expression right_side =
3946 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
3947 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side, loc);
3950 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
3951 InstanceExpression = InstanceExpression.Resolve (ec, rf);
3954 if (InstanceExpression == null)
3957 InstanceExpression.CheckMarshalByRefAccess ();
3960 if (!in_initializer && !ec.IsFieldInitializer) {
3961 ObsoleteAttribute oa;
3962 FieldBase f = TypeManager.GetField (FieldInfo);
3964 if (!ec.IsInObsoleteScope)
3965 f.CheckObsoleteness (loc);
3967 // To be sure that type is external because we do not register generated fields
3968 } else if (!(FieldInfo.DeclaringType is TypeBuilder)) {
3969 oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
3971 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
3975 AnonymousContainer am = ec.CurrentAnonymousMethod;
3977 if (!FieldInfo.IsStatic){
3978 if (!am.IsIterator && (ec.TypeContainer is Struct)){
3979 Report.Error (1673, loc,
3980 "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",
3987 // If the instance expression is a local variable or parameter.
3988 IVariable var = InstanceExpression as IVariable;
3989 if ((var == null) || (var.VariableInfo == null))
3992 VariableInfo vi = var.VariableInfo;
3993 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
3996 variable_info = vi.GetSubStruct (FieldInfo.Name);
4000 static readonly int [] codes = {
4001 191, // instance, write access
4002 192, // instance, out access
4003 198, // static, write access
4004 199, // static, out access
4005 1648, // member of value instance, write access
4006 1649, // member of value instance, out access
4007 1650, // member of value static, write access
4008 1651 // member of value static, out access
4011 static readonly string [] msgs = {
4012 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4013 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4014 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4015 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4016 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4017 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4018 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4019 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4022 // The return value is always null. Returning a value simplifies calling code.
4023 Expression Report_AssignToReadonly (Expression right_side)
4026 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4030 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4032 Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4037 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4039 IVariable var = InstanceExpression as IVariable;
4040 if ((var != null) && (var.VariableInfo != null))
4041 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
4043 bool lvalue_instance = !FieldInfo.IsStatic && FieldInfo.DeclaringType.IsValueType;
4044 bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
4046 Expression e = DoResolve (ec, lvalue_instance, out_access);
4051 FieldBase fb = TypeManager.GetField (FieldInfo);
4055 if (FieldInfo.IsInitOnly) {
4056 // InitOnly fields can only be assigned in constructors or initializers
4057 if (!ec.IsFieldInitializer && !ec.IsConstructor)
4058 return Report_AssignToReadonly (right_side);
4060 if (ec.IsConstructor) {
4061 Type ctype = ec.TypeContainer.CurrentType;
4063 ctype = ec.ContainerType;
4065 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4066 if (!TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
4067 return Report_AssignToReadonly (right_side);
4068 // static InitOnly fields cannot be assigned-to in an instance constructor
4069 if (IsStatic && !ec.IsStatic)
4070 return Report_AssignToReadonly (right_side);
4071 // instance constructors can't modify InitOnly fields of other instances of the same type
4072 if (!IsStatic && !(InstanceExpression is This))
4073 return Report_AssignToReadonly (right_side);
4077 if (right_side == EmptyExpression.OutAccess &&
4078 !IsStatic && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
4079 Report.SymbolRelatedToPreviousError (DeclaringType);
4080 Report.Warning (197, 1, loc,
4081 "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",
4082 GetSignatureForError ());
4088 public override void CheckMarshalByRefAccess ()
4090 if (!IsStatic && Type.IsValueType && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
4091 Report.SymbolRelatedToPreviousError (DeclaringType);
4092 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",
4093 GetSignatureForError ());
4097 public bool VerifyFixed ()
4099 IVariable variable = InstanceExpression as IVariable;
4100 // A variable of the form V.I is fixed when V is a fixed variable of a struct type.
4101 // We defer the InstanceExpression check after the variable check to avoid a
4102 // separate null check on InstanceExpression.
4103 return variable != null && InstanceExpression.Type.IsValueType && variable.VerifyFixed ();
4106 public override int GetHashCode ()
4108 return FieldInfo.GetHashCode ();
4111 public override bool Equals (object obj)
4113 FieldExpr fe = obj as FieldExpr;
4117 if (FieldInfo != fe.FieldInfo)
4120 if (InstanceExpression == null || fe.InstanceExpression == null)
4123 return InstanceExpression.Equals (fe.InstanceExpression);
4126 public void Emit (EmitContext ec, bool leave_copy)
4128 ILGenerator ig = ec.ig;
4129 bool is_volatile = false;
4131 FieldBase f = TypeManager.GetField (FieldInfo);
4133 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4136 f.SetMemberIsUsed ();
4139 if (FieldInfo.IsStatic){
4141 ig.Emit (OpCodes.Volatile);
4143 ig.Emit (OpCodes.Ldsfld, FieldInfo);
4146 EmitInstance (ec, false);
4149 ig.Emit (OpCodes.Volatile);
4151 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
4154 ig.Emit (OpCodes.Ldflda, FieldInfo);
4155 ig.Emit (OpCodes.Ldflda, ff.Element);
4158 ig.Emit (OpCodes.Ldfld, FieldInfo);
4163 ec.ig.Emit (OpCodes.Dup);
4164 if (!FieldInfo.IsStatic) {
4165 temp = new LocalTemporary (this.Type);
4171 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4173 FieldAttributes fa = FieldInfo.Attributes;
4174 bool is_static = (fa & FieldAttributes.Static) != 0;
4175 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
4176 ILGenerator ig = ec.ig;
4177 prepared = prepare_for_load;
4179 if (is_readonly && !ec.IsConstructor){
4180 Report_AssignToReadonly (source);
4184 EmitInstance (ec, prepare_for_load);
4188 ec.ig.Emit (OpCodes.Dup);
4189 if (!FieldInfo.IsStatic) {
4190 temp = new LocalTemporary (this.Type);
4195 FieldBase f = TypeManager.GetField (FieldInfo);
4197 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4198 ig.Emit (OpCodes.Volatile);
4204 ig.Emit (OpCodes.Stsfld, FieldInfo);
4206 ig.Emit (OpCodes.Stfld, FieldInfo);
4214 public override void Emit (EmitContext ec)
4219 public void AddressOf (EmitContext ec, AddressOp mode)
4221 ILGenerator ig = ec.ig;
4223 FieldBase f = TypeManager.GetField (FieldInfo);
4225 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
4226 Report.Warning (420, 1, loc, "`{0}': A volatile fields cannot be passed using a ref or out parameter",
4227 f.GetSignatureForError ());
4231 if ((mode & AddressOp.Store) != 0)
4233 if ((mode & AddressOp.Load) != 0)
4234 f.SetMemberIsUsed ();
4238 // Handle initonly fields specially: make a copy and then
4239 // get the address of the copy.
4242 if (FieldInfo.IsInitOnly){
4244 if (ec.IsConstructor){
4245 if (FieldInfo.IsStatic){
4257 local = ig.DeclareLocal (type);
4258 ig.Emit (OpCodes.Stloc, local);
4259 ig.Emit (OpCodes.Ldloca, local);
4264 if (FieldInfo.IsStatic){
4265 ig.Emit (OpCodes.Ldsflda, FieldInfo);
4268 EmitInstance (ec, false);
4269 ig.Emit (OpCodes.Ldflda, FieldInfo);
4275 // A FieldExpr whose address can not be taken
4277 public class FieldExprNoAddress : FieldExpr, IMemoryLocation {
4278 public FieldExprNoAddress (FieldInfo fi, Location loc) : base (fi, loc)
4282 public new void AddressOf (EmitContext ec, AddressOp mode)
4284 Report.Error (-215, "Report this: Taking the address of a remapped parameter not supported");
4289 /// Expression that evaluates to a Property. The Assign class
4290 /// might set the `Value' expression if we are in an assignment.
4292 /// This is not an LValue because we need to re-write the expression, we
4293 /// can not take data from the stack and store it.
4295 public class PropertyExpr : MemberExpr, IAssignMethod {
4296 public readonly PropertyInfo PropertyInfo;
4299 // This is set externally by the `BaseAccess' class
4302 MethodInfo getter, setter;
4307 LocalTemporary temp;
4310 public PropertyExpr (Type containerType, PropertyInfo pi, Location l)
4313 eclass = ExprClass.PropertyAccess;
4317 type = TypeManager.TypeToCoreType (pi.PropertyType);
4319 ResolveAccessors (containerType);
4322 public override string Name {
4324 return PropertyInfo.Name;
4328 public override bool IsInstance {
4334 public override bool IsStatic {
4340 public override Type DeclaringType {
4342 return PropertyInfo.DeclaringType;
4346 public override string GetSignatureForError ()
4348 return TypeManager.GetFullNameSignature (PropertyInfo);
4351 void FindAccessors (Type invocation_type)
4353 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
4354 BindingFlags.Static | BindingFlags.Instance |
4355 BindingFlags.DeclaredOnly;
4357 Type current = PropertyInfo.DeclaringType;
4358 for (; current != null; current = current.BaseType) {
4359 MemberInfo[] group = TypeManager.MemberLookup (
4360 invocation_type, invocation_type, current,
4361 MemberTypes.Property, flags, PropertyInfo.Name, null);
4366 if (group.Length != 1)
4367 // Oooops, can this ever happen ?
4370 PropertyInfo pi = (PropertyInfo) group [0];
4373 getter = pi.GetGetMethod (true);
4376 setter = pi.GetSetMethod (true);
4378 MethodInfo accessor = getter != null ? getter : setter;
4380 if (!accessor.IsVirtual)
4386 // We also perform the permission checking here, as the PropertyInfo does not
4387 // hold the information for the accessibility of its setter/getter
4389 // TODO: Refactor to use some kind of cache together with GetPropertyFromAccessor
4390 void ResolveAccessors (Type containerType)
4392 FindAccessors (containerType);
4394 if (getter != null) {
4395 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
4396 IMethodData md = TypeManager.GetMethod (the_getter);
4398 md.SetMemberIsUsed ();
4400 is_static = getter.IsStatic;
4403 if (setter != null) {
4404 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
4405 IMethodData md = TypeManager.GetMethod (the_setter);
4407 md.SetMemberIsUsed ();
4409 is_static = setter.IsStatic;
4413 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
4416 InstanceExpression = null;
4420 if (InstanceExpression == null) {
4421 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4425 InstanceExpression = InstanceExpression.DoResolve (ec);
4426 if (lvalue_instance && InstanceExpression != null)
4427 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
4429 if (InstanceExpression == null)
4432 InstanceExpression.CheckMarshalByRefAccess ();
4434 if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) &&
4435 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
4436 !TypeManager.IsNestedChildOf (ec.ContainerType, InstanceExpression.Type) &&
4437 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.ContainerType)) {
4438 Report.SymbolRelatedToPreviousError (PropertyInfo);
4439 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
4446 void Error_PropertyNotFound (MethodInfo mi, bool getter)
4448 // TODO: correctly we should compare arguments but it will lead to bigger changes
4449 if (mi is MethodBuilder) {
4450 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
4454 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
4456 ParameterData iparams = TypeManager.GetParameterData (mi);
4457 sig.Append (getter ? "get_" : "set_");
4459 sig.Append (iparams.GetSignatureForError ());
4461 Report.SymbolRelatedToPreviousError (mi);
4462 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
4463 Name, sig.ToString ());
4466 override public Expression DoResolve (EmitContext ec)
4471 if (getter != null){
4472 if (TypeManager.GetParameterData (getter).Count != 0){
4473 Error_PropertyNotFound (getter, true);
4478 if (getter == null){
4480 // The following condition happens if the PropertyExpr was
4481 // created, but is invalid (ie, the property is inaccessible),
4482 // and we did not want to embed the knowledge about this in
4483 // the caller routine. This only avoids double error reporting.
4488 if (InstanceExpression != EmptyExpression.Null) {
4489 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
4490 TypeManager.GetFullNameSignature (PropertyInfo));
4495 bool must_do_cs1540_check = false;
4496 if (getter != null &&
4497 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
4498 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
4499 if (pm != null && pm.HasCustomAccessModifier) {
4500 Report.SymbolRelatedToPreviousError (pm);
4501 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
4502 TypeManager.CSharpSignature (getter));
4505 Report.SymbolRelatedToPreviousError (getter);
4506 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
4511 if (!InstanceResolve (ec, false, must_do_cs1540_check))
4515 // Only base will allow this invocation to happen.
4517 if (IsBase && getter.IsAbstract) {
4518 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
4522 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
4532 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4534 if (right_side == EmptyExpression.OutAccess) {
4535 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
4536 GetSignatureForError ());
4540 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
4541 Report.Error (1612, loc, "Cannot modify the return value of `{0}' because it is not a variable",
4542 GetSignatureForError ());
4546 if (setter == null){
4548 // The following condition happens if the PropertyExpr was
4549 // created, but is invalid (ie, the property is inaccessible),
4550 // and we did not want to embed the knowledge about this in
4551 // the caller routine. This only avoids double error reporting.
4555 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
4556 GetSignatureForError ());
4560 if (TypeManager.GetParameterData (setter).Count != 1){
4561 Error_PropertyNotFound (setter, false);
4565 bool must_do_cs1540_check;
4566 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
4567 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
4568 if (pm != null && pm.HasCustomAccessModifier) {
4569 Report.SymbolRelatedToPreviousError (pm);
4570 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
4571 TypeManager.CSharpSignature (setter));
4574 Report.SymbolRelatedToPreviousError (setter);
4575 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
4580 if (!InstanceResolve (ec, PropertyInfo.DeclaringType.IsValueType, must_do_cs1540_check))
4584 // Only base will allow this invocation to happen.
4586 if (IsBase && setter.IsAbstract){
4587 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
4594 public override void Emit (EmitContext ec)
4599 public void Emit (EmitContext ec, bool leave_copy)
4602 // Special case: length of single dimension array property is turned into ldlen
4604 if ((getter == TypeManager.system_int_array_get_length) ||
4605 (getter == TypeManager.int_array_get_length)){
4606 Type iet = InstanceExpression.Type;
4609 // System.Array.Length can be called, but the Type does not
4610 // support invoking GetArrayRank, so test for that case first
4612 if (iet != TypeManager.array_type && (iet.GetArrayRank () == 1)) {
4614 EmitInstance (ec, false);
4615 ec.ig.Emit (OpCodes.Ldlen);
4616 ec.ig.Emit (OpCodes.Conv_I4);
4621 Invocation.EmitCall (ec, IsBase, IsStatic, InstanceExpression, getter, null, loc, prepared, false);
4624 ec.ig.Emit (OpCodes.Dup);
4626 temp = new LocalTemporary (this.Type);
4633 // Implements the IAssignMethod interface for assignments
4635 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4637 Expression my_source = source;
4639 prepared = prepare_for_load;
4644 ec.ig.Emit (OpCodes.Dup);
4646 temp = new LocalTemporary (this.Type);
4650 } else if (leave_copy) {
4653 temp = new LocalTemporary (this.Type);
4659 ArrayList args = new ArrayList (1);
4660 args.Add (new Argument (my_source, Argument.AType.Expression));
4662 Invocation.EmitCall (ec, IsBase, IsStatic, InstanceExpression, setter, args, loc, false, prepared);
4672 /// Fully resolved expression that evaluates to an Event
4674 public class EventExpr : MemberExpr {
4675 public readonly EventInfo EventInfo;
4678 MethodInfo add_accessor, remove_accessor;
4680 public EventExpr (EventInfo ei, Location loc)
4684 eclass = ExprClass.EventAccess;
4686 add_accessor = TypeManager.GetAddMethod (ei);
4687 remove_accessor = TypeManager.GetRemoveMethod (ei);
4688 if (add_accessor.IsStatic || remove_accessor.IsStatic)
4691 if (EventInfo is MyEventBuilder){
4692 MyEventBuilder eb = (MyEventBuilder) EventInfo;
4693 type = eb.EventType;
4696 type = EventInfo.EventHandlerType;
4699 public override string Name {
4701 return EventInfo.Name;
4705 public override bool IsInstance {
4711 public override bool IsStatic {
4717 public override Type DeclaringType {
4719 return EventInfo.DeclaringType;
4723 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
4724 SimpleName original)
4727 // If the event is local to this class, we transform ourselves into a FieldExpr
4730 if (EventInfo.DeclaringType == ec.ContainerType ||
4731 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
4732 EventField mi = TypeManager.GetEventField (EventInfo);
4735 if (!ec.IsInObsoleteScope)
4736 mi.CheckObsoleteness (loc);
4738 FieldExpr ml = new FieldExpr (mi.FieldBuilder, loc);
4740 InstanceExpression = null;
4742 return ml.ResolveMemberAccess (ec, left, loc, original);
4746 return base.ResolveMemberAccess (ec, left, loc, original);
4750 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
4753 InstanceExpression = null;
4757 if (InstanceExpression == null) {
4758 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4762 InstanceExpression = InstanceExpression.DoResolve (ec);
4763 if (InstanceExpression == null)
4767 // This is using the same mechanism as the CS1540 check in PropertyExpr.
4768 // However, in the Event case, we reported a CS0122 instead.
4770 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
4771 InstanceExpression.Type != ec.ContainerType &&
4772 ec.ContainerType.IsSubclassOf (InstanceExpression.Type)) {
4773 Report.SymbolRelatedToPreviousError (EventInfo);
4774 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
4781 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
4783 return DoResolve (ec);
4786 public override Expression DoResolve (EmitContext ec)
4788 bool must_do_cs1540_check;
4789 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
4790 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
4791 Report.SymbolRelatedToPreviousError (EventInfo);
4792 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
4796 if (!InstanceResolve (ec, must_do_cs1540_check))
4802 public override void Emit (EmitContext ec)
4804 if (InstanceExpression is This)
4805 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of += or -=", GetSignatureForError ());
4807 Report.Error (70, loc, "The event `{0}' can only appear on the left hand side of += or -= "+
4808 "(except on the defining type)", Name);
4811 public override string GetSignatureForError ()
4813 return TypeManager.CSharpSignature (EventInfo);
4816 public void EmitAddOrRemove (EmitContext ec, Expression source)
4818 BinaryDelegate source_del = source as BinaryDelegate;
4819 if (source_del == null) {
4823 Expression handler = source_del.Right;
4825 Argument arg = new Argument (handler, Argument.AType.Expression);
4826 ArrayList args = new ArrayList ();
4830 if (source_del.IsAddition)
4831 Invocation.EmitCall (
4832 ec, false, IsStatic, InstanceExpression, add_accessor, args, loc);
4834 Invocation.EmitCall (
4835 ec, false, IsStatic, InstanceExpression, remove_accessor, args, loc);
4839 public class TemporaryVariable : Expression, IMemoryLocation
4844 public TemporaryVariable (Type type, Location loc)
4848 eclass = ExprClass.Value;
4851 public override Expression DoResolve (EmitContext ec)
4856 TypeExpr te = new TypeExpression (type, loc);
4857 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
4858 if (!li.Resolve (ec))
4861 if (ec.MustCaptureVariable (li)) {
4862 ScopeInfo scope = li.Block.CreateScopeInfo ();
4863 var = scope.AddLocal (li);
4870 public Variable Variable {
4871 get { return var != null ? var : li.Variable; }
4874 public override void Emit (EmitContext ec)
4876 Variable.EmitInstance (ec);
4880 public void EmitLoadAddress (EmitContext ec)
4882 Variable.EmitInstance (ec);
4883 Variable.EmitAddressOf (ec);
4886 public void Store (EmitContext ec, Expression right_side)
4888 Variable.EmitInstance (ec);
4889 right_side.Emit (ec);
4890 Variable.EmitAssign (ec);
4893 public void EmitThis (EmitContext ec)
4895 Variable.EmitInstance (ec);
4898 public void EmitStore (EmitContext ec)
4900 Variable.EmitAssign (ec);
4903 public void AddressOf (EmitContext ec, AddressOp mode)
4905 EmitLoadAddress (ec);