2 // ecore.cs: Core of the Expression representation for the intermediate tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@seznam.cz)
8 // (C) 2001, 2002, 2003 Ximian, Inc.
12 namespace Mono.CSharp {
14 using System.Collections;
15 using System.Diagnostics;
16 using System.Reflection;
17 using System.Reflection.Emit;
21 /// The ExprClass class contains the is used to pass the
22 /// classification of an expression (value, variable, namespace,
23 /// type, method group, property access, event access, indexer access,
26 public enum ExprClass : byte {
41 /// This is used to tell Resolve in which types of expressions we're
45 public enum ResolveFlags {
46 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
49 // Returns a type expression.
52 // Returns a method group.
55 // Mask of all the expression class flags.
58 // Disable control flow analysis while resolving the expression.
59 // This is used when resolving the instance expression of a field expression.
60 DisableFlowAnalysis = 8,
62 // Set if this is resolving the first part of a MemberAccess.
65 // Disable control flow analysis _of struct_ while resolving the expression.
66 // This is used when resolving the instance expression of a field expression.
67 DisableStructFlowAnalysis = 32,
72 // This is just as a hint to AddressOf of what will be done with the
75 public enum AddressOp {
82 /// This interface is implemented by variables
84 public interface IMemoryLocation {
86 /// The AddressOf method should generate code that loads
87 /// the address of the object and leaves it on the stack.
89 /// The `mode' argument is used to notify the expression
90 /// of whether this will be used to read from the address or
91 /// write to the address.
93 /// This is just a hint that can be used to provide good error
94 /// reporting, and should have no other side effects.
96 void AddressOf (EmitContext ec, AddressOp mode);
100 /// This interface is implemented by variables
102 public interface IVariable {
103 VariableInfo VariableInfo {
111 /// Base class for expressions
113 public abstract class Expression {
114 public ExprClass eclass;
116 protected Location loc;
120 set { type = value; }
123 public virtual Location Location {
128 /// Utility wrapper routine for Error, just to beautify the code
130 public void Error (int error, string s)
132 Report.Error (error, loc, s);
135 // Not nice but we have broken hierarchy.
136 public virtual void CheckMarshalByRefAccess ()
140 public virtual bool GetAttributableValue (Type valueType, out object value)
142 Attribute.Error_AttributeArgumentNotValid (loc);
147 public virtual string GetSignatureForError ()
149 return TypeManager.CSharpName (type);
152 public static bool IsAccessorAccessible (Type invocation_type, MethodInfo mi, out bool must_do_cs1540_check)
154 MethodAttributes ma = mi.Attributes & MethodAttributes.MemberAccessMask;
156 must_do_cs1540_check = false; // by default we do not check for this
158 if (ma == MethodAttributes.Public)
162 // If only accessible to the current class or children
164 if (ma == MethodAttributes.Private)
165 return TypeManager.IsPrivateAccessible (invocation_type, mi.DeclaringType) ||
166 TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType);
168 if (mi.DeclaringType.Assembly == invocation_type.Assembly ||
169 TypeManager.IsFriendAssembly (mi.DeclaringType.Assembly)) {
170 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamORAssem)
173 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamANDAssem)
177 // Family and FamANDAssem require that we derive.
178 // FamORAssem requires that we derive if in different assemblies.
179 if (!TypeManager.IsNestedFamilyAccessible (invocation_type, mi.DeclaringType))
182 if (!TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType))
183 must_do_cs1540_check = true;
189 /// Performs semantic analysis on the Expression
193 /// The Resolve method is invoked to perform the semantic analysis
196 /// The return value is an expression (it can be the
197 /// same expression in some cases) or a new
198 /// expression that better represents this node.
200 /// For example, optimizations of Unary (LiteralInt)
201 /// would return a new LiteralInt with a negated
204 /// If there is an error during semantic analysis,
205 /// then an error should be reported (using Report)
206 /// and a null value should be returned.
208 /// There are two side effects expected from calling
209 /// Resolve(): the the field variable "eclass" should
210 /// be set to any value of the enumeration
211 /// `ExprClass' and the type variable should be set
212 /// to a valid type (this is the type of the
215 public abstract Expression DoResolve (EmitContext ec);
217 public virtual Expression DoResolveLValue (EmitContext ec, Expression right_side)
223 // This is used if the expression should be resolved as a type or namespace name.
224 // the default implementation fails.
226 public virtual FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
232 // C# 3.0 introduced contextual keywords (var) which behaves like a type if type with
233 // same name exists or as a keyword when no type was found
235 public virtual TypeExpr ResolveAsContextualType (IResolveContext rc, bool silent)
237 return ResolveAsTypeTerminal (rc, silent);
241 // This is used to resolve the expression as a type, a null
242 // value will be returned if the expression is not a type
245 public virtual TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
247 TypeExpr te = ResolveAsBaseTerminal (ec, silent);
251 if (!silent) { // && !(te is TypeParameterExpr)) {
252 ObsoleteAttribute obsolete_attr = AttributeTester.GetObsoleteAttribute (te.Type);
253 if (obsolete_attr != null && !ec.IsInObsoleteScope) {
254 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location);
258 // Constrains don't need to be checked for overrides
259 GenericMethod gm = ec.GenericDeclContainer as GenericMethod;
260 if (gm != null && (gm.ModFlags & Modifiers.OVERRIDE) != 0) {
265 ConstructedType ct = te as ConstructedType;
266 if ((ct != null) && !ct.CheckConstraints (ec))
272 public TypeExpr ResolveAsBaseTerminal (IResolveContext ec, bool silent)
274 int errors = Report.Errors;
276 FullNamedExpression fne = ResolveAsTypeStep (ec, silent);
281 if (fne.eclass != ExprClass.Type) {
282 if (!silent && errors == Report.Errors)
283 fne.Error_UnexpectedKind (null, "type", loc);
287 TypeExpr te = fne as TypeExpr;
289 if (!te.CheckAccessLevel (ec.DeclContainer)) {
290 Report.SymbolRelatedToPreviousError (te.Type);
291 ErrorIsInaccesible (loc, TypeManager.CSharpName (te.Type));
299 public static void ErrorIsInaccesible (Location loc, string name)
301 Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", name);
304 protected static void Error_CannotAccessProtected (Location loc, MemberInfo m, Type qualifier, Type container)
306 Report.Error (1540, loc, "Cannot access protected member `{0}' via a qualifier of type `{1}'."
307 + " The qualifier must be of type `{2}' or derived from it",
308 TypeManager.GetFullNameSignature (m),
309 TypeManager.CSharpName (qualifier),
310 TypeManager.CSharpName (container));
314 public static void Error_InvalidExpressionStatement (Location loc)
316 Report.Error (201, loc, "Only assignment, call, increment, decrement, and new object " +
317 "expressions can be used as a statement");
320 public void Error_InvalidExpressionStatement ()
322 Error_InvalidExpressionStatement (loc);
325 protected void Error_CannotAssign (string to, string roContext)
327 Report.Error (1656, loc, "Cannot assign to `{0}' because it is a `{1}'",
331 public static void Error_VoidInvalidInTheContext (Location loc)
333 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
336 public virtual void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl)
338 if (Type.FullName == target.FullName){
339 Report.ExtraInformation (loc,
341 "The type {0} has two conflicting definitions, one comes from {1} and the other from {2}",
342 Type.FullName, Type.Assembly.FullName, target.Assembly.FullName));
347 Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
348 TypeManager.CSharpName (type), TypeManager.CSharpName (target));
352 Expression e = (this is EnumConstant) ? ((EnumConstant)this).Child : this;
353 bool b = Convert.ExplicitNumericConversion (e, target) != null;
356 Convert.ExplicitReferenceConversionExists (Type, target) ||
357 Convert.ExplicitUnsafe (e, target) != null ||
358 (ec != null && Convert.UserDefinedConversion (ec, this, target, Location.Null, true) != null))
360 Report.Error (266, loc, "Cannot implicitly convert type `{0}' to `{1}'. " +
361 "An explicit conversion exists (are you missing a cast?)",
362 TypeManager.CSharpName (Type), TypeManager.CSharpName (target));
366 if (Type != TypeManager.string_type && this is Constant && !(this is EmptyConstantCast)) {
367 Report.Error (31, loc, "Constant value `{0}' cannot be converted to a `{1}'",
368 ((Constant)(this)).GetValue ().ToString (), TypeManager.CSharpName (target));
372 Report.Error (29, loc, "Cannot implicitly convert type {0} to `{1}'",
373 Type == TypeManager.anonymous_method_type ?
374 "anonymous method" : "`" + GetSignatureForError () + "'",
375 TypeManager.CSharpName (target));
378 protected void Error_VariableIsUsedBeforeItIsDeclared (string name)
380 Report.Error (841, loc, "The variable `{0}' cannot be used before it is declared",
384 public static void Error_TypeDoesNotContainDefinition (Location loc, Type type, string name)
386 Report.SymbolRelatedToPreviousError (type);
387 Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
388 TypeManager.CSharpName (type), name);
391 protected static void Error_ValueAssignment (Location loc)
393 Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
396 ResolveFlags ExprClassToResolveFlags
401 case ExprClass.Namespace:
402 return ResolveFlags.Type;
404 case ExprClass.MethodGroup:
405 return ResolveFlags.MethodGroup;
407 case ExprClass.Value:
408 case ExprClass.Variable:
409 case ExprClass.PropertyAccess:
410 case ExprClass.EventAccess:
411 case ExprClass.IndexerAccess:
412 return ResolveFlags.VariableOrValue;
415 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
421 /// Resolves an expression and performs semantic analysis on it.
425 /// Currently Resolve wraps DoResolve to perform sanity
426 /// checking and assertion checking on what we expect from Resolve.
428 public Expression Resolve (EmitContext ec, ResolveFlags flags)
430 if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type)
431 return ResolveAsTypeStep (ec, false);
433 bool do_flow_analysis = ec.DoFlowAnalysis;
434 bool omit_struct_analysis = ec.OmitStructFlowAnalysis;
435 if ((flags & ResolveFlags.DisableFlowAnalysis) != 0)
436 do_flow_analysis = false;
437 if ((flags & ResolveFlags.DisableStructFlowAnalysis) != 0)
438 omit_struct_analysis = true;
441 using (ec.WithFlowAnalysis (do_flow_analysis, omit_struct_analysis)) {
442 if (this is SimpleName) {
443 bool intermediate = (flags & ResolveFlags.Intermediate) == ResolveFlags.Intermediate;
444 e = ((SimpleName) this).DoResolve (ec, intermediate);
453 if ((flags & e.ExprClassToResolveFlags) == 0) {
454 e.Error_UnexpectedKind (flags, loc);
458 if (e.type == null && !(e is Namespace)) {
459 throw new Exception (
460 "Expression " + e.GetType () +
461 " did not set its type after Resolve\n" +
462 "called from: " + this.GetType ());
469 /// Resolves an expression and performs semantic analysis on it.
471 public Expression Resolve (EmitContext ec)
473 Expression e = Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
475 if (e != null && e.eclass == ExprClass.MethodGroup && RootContext.Version == LanguageVersion.ISO_1) {
476 ((MethodGroupExpr) e).ReportUsageError ();
482 public Constant ResolveAsConstant (EmitContext ec, MemberCore mc)
484 Expression e = Resolve (ec);
488 Constant c = e as Constant;
492 Const.Error_ExpressionMustBeConstant (loc, mc.GetSignatureForError ());
497 /// Resolves an expression for LValue assignment
501 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
502 /// checking and assertion checking on what we expect from Resolve
504 public Expression ResolveLValue (EmitContext ec, Expression right_side, Location loc)
506 int errors = Report.Errors;
507 bool out_access = right_side == EmptyExpression.OutAccess;
509 Expression e = DoResolveLValue (ec, right_side);
511 if (e != null && out_access && !(e is IMemoryLocation)) {
512 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
513 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
515 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
516 // e.GetType () + " " + e.GetSignatureForError ());
521 if (errors == Report.Errors) {
523 Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
525 Error_ValueAssignment (loc);
530 if (e.eclass == ExprClass.Invalid)
531 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
533 if (e.eclass == ExprClass.MethodGroup) {
534 ((MethodGroupExpr) e).ReportUsageError ();
538 if ((e.type == null) && !(e is ConstructedType))
539 throw new Exception ("Expression " + e + " did not set its type after Resolve");
545 /// Emits the code for the expression
549 /// The Emit method is invoked to generate the code
550 /// for the expression.
552 public abstract void Emit (EmitContext ec);
554 public virtual void EmitBranchable (EmitContext ec, Label target, bool onTrue)
557 ec.ig.Emit (onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target);
561 /// Protected constructor. Only derivate types should
562 /// be able to be created
565 protected Expression ()
567 eclass = ExprClass.Invalid;
572 /// Returns a fully formed expression after a MemberLookup
575 public static Expression ExprClassFromMemberInfo (Type containerType, MemberInfo mi, Location loc)
578 return new EventExpr ((EventInfo) mi, loc);
579 else if (mi is FieldInfo)
580 return new FieldExpr ((FieldInfo) mi, loc);
581 else if (mi is PropertyInfo)
582 return new PropertyExpr (containerType, (PropertyInfo) mi, loc);
583 else if (mi is Type){
584 return new TypeExpression ((System.Type) mi, loc);
590 protected static ArrayList almostMatchedMembers = new ArrayList (4);
593 // FIXME: Probably implement a cache for (t,name,current_access_set)?
595 // This code could use some optimizations, but we need to do some
596 // measurements. For example, we could use a delegate to `flag' when
597 // something can not any longer be a method-group (because it is something
601 // If the return value is an Array, then it is an array of
604 // If the return value is an MemberInfo, it is anything, but a Method
608 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
609 // the arguments here and have MemberLookup return only the methods that
610 // match the argument count/type, unlike we are doing now (we delay this
613 // This is so we can catch correctly attempts to invoke instance methods
614 // from a static body (scan for error 120 in ResolveSimpleName).
617 // FIXME: Potential optimization, have a static ArrayList
620 public static Expression MemberLookup (Type container_type, Type queried_type, string name,
621 MemberTypes mt, BindingFlags bf, Location loc)
623 return MemberLookup (container_type, null, queried_type, name, mt, bf, loc);
627 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
628 // `qualifier_type' or null to lookup members in the current class.
631 public static Expression MemberLookup (Type container_type,
632 Type qualifier_type, Type queried_type,
633 string name, MemberTypes mt,
634 BindingFlags bf, Location loc)
636 almostMatchedMembers.Clear ();
638 MemberInfo [] mi = TypeManager.MemberLookup (container_type, qualifier_type,
639 queried_type, mt, bf, name, almostMatchedMembers);
645 bool is_interface = qualifier_type != null && qualifier_type.IsInterface;
646 ArrayList methods = new ArrayList (2);
647 ArrayList non_methods = null;
649 foreach (MemberInfo m in mi) {
650 if (m is MethodBase) {
655 if (non_methods == null) {
656 non_methods = new ArrayList (2);
661 foreach (MemberInfo n_m in non_methods) {
662 if (m.DeclaringType.IsInterface && TypeManager.ImplementsInterface (m.DeclaringType, n_m.DeclaringType))
665 Report.SymbolRelatedToPreviousError (m);
666 Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
667 TypeManager.GetFullNameSignature (m), TypeManager.GetFullNameSignature (n_m));
672 if (methods.Count == 0)
673 return ExprClassFromMemberInfo (container_type, (MemberInfo)non_methods [0], loc);
675 if (non_methods != null) {
676 MethodBase method = (MethodBase) methods [0];
677 MemberInfo non_method = (MemberInfo) non_methods [0];
678 if (method.DeclaringType == non_method.DeclaringType) {
679 // Cannot happen with C# code, but is valid in IL
680 Report.SymbolRelatedToPreviousError (method);
681 Report.SymbolRelatedToPreviousError (non_method);
682 Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
683 TypeManager.GetFullNameSignature (non_method),
684 TypeManager.CSharpSignature (method));
689 Report.SymbolRelatedToPreviousError (method);
690 Report.SymbolRelatedToPreviousError (non_method);
691 Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and non-method `{1}'. Using method `{0}'",
692 TypeManager.CSharpSignature (method), TypeManager.GetFullNameSignature (non_method));
696 return new MethodGroupExpr (methods, queried_type, loc);
699 if (mi [0] is MethodBase)
700 return new MethodGroupExpr (mi, queried_type, loc);
702 return ExprClassFromMemberInfo (container_type, mi [0], loc);
705 public const MemberTypes AllMemberTypes =
706 MemberTypes.Constructor |
710 MemberTypes.NestedType |
711 MemberTypes.Property;
713 public const BindingFlags AllBindingFlags =
714 BindingFlags.Public |
715 BindingFlags.Static |
716 BindingFlags.Instance;
718 public static Expression MemberLookup (Type container_type, Type queried_type,
719 string name, Location loc)
721 return MemberLookup (container_type, null, queried_type, name,
722 AllMemberTypes, AllBindingFlags, loc);
725 public static Expression MemberLookup (Type container_type, Type qualifier_type,
726 Type queried_type, string name, Location loc)
728 return MemberLookup (container_type, qualifier_type, queried_type,
729 name, AllMemberTypes, AllBindingFlags, loc);
732 public static MethodGroupExpr MethodLookup (Type container_type, Type queried_type,
733 string name, Location loc)
735 return (MethodGroupExpr)MemberLookup (container_type, null, queried_type, name,
736 MemberTypes.Method, AllBindingFlags, loc);
740 /// This is a wrapper for MemberLookup that is not used to "probe", but
741 /// to find a final definition. If the final definition is not found, we
742 /// look for private members and display a useful debugging message if we
745 protected Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
746 Type queried_type, string name,
747 MemberTypes mt, BindingFlags bf,
752 int errors = Report.Errors;
754 e = MemberLookup (ec.ContainerType, qualifier_type, queried_type, name, mt, bf, loc);
756 if (e != null || errors != Report.Errors)
759 // No errors were reported by MemberLookup, but there was an error.
760 return Error_MemberLookupFailed (ec.ContainerType, qualifier_type, queried_type,
764 protected virtual Expression Error_MemberLookupFailed (Type container_type, Type qualifier_type,
765 Type queried_type, string name, string class_name,
766 MemberTypes mt, BindingFlags bf)
768 if (almostMatchedMembers.Count != 0) {
769 for (int i = 0; i < almostMatchedMembers.Count; ++i) {
770 MemberInfo m = (MemberInfo) almostMatchedMembers [i];
771 for (int j = 0; j < i; ++j) {
772 if (m == almostMatchedMembers [j]) {
780 Type declaring_type = m.DeclaringType;
782 Report.SymbolRelatedToPreviousError (m);
783 if (qualifier_type == null) {
784 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
785 TypeManager.CSharpName (m.DeclaringType),
786 TypeManager.CSharpName (container_type));
788 } else if (qualifier_type != container_type &&
789 TypeManager.IsNestedFamilyAccessible (container_type, declaring_type)) {
790 // Although a derived class can access protected members of
791 // its base class it cannot do so through an instance of the
792 // base class (CS1540). If the qualifier_type is a base of the
793 // ec.ContainerType and the lookup succeeds with the latter one,
794 // then we are in this situation.
795 Error_CannotAccessProtected (loc, m, qualifier_type, container_type);
797 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (m));
800 almostMatchedMembers.Clear ();
804 MemberInfo[] lookup = null;
805 if (queried_type == null) {
806 class_name = "global::";
808 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
809 mt, (bf & ~BindingFlags.Public) | BindingFlags.NonPublic,
812 if (lookup != null) {
813 Report.SymbolRelatedToPreviousError (lookup [0]);
814 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (lookup [0]));
815 return Error_MemberLookupFailed (lookup);
818 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
819 AllMemberTypes, AllBindingFlags | BindingFlags.NonPublic,
823 if (lookup == null) {
824 if (class_name != null) {
825 Report.Error (103, loc, "The name `{0}' does not exist in the current context",
828 Error_TypeDoesNotContainDefinition (loc, queried_type, name);
833 if (TypeManager.MemberLookup (queried_type, null, queried_type,
834 AllMemberTypes, AllBindingFlags |
835 BindingFlags.NonPublic, name, null) == null) {
836 if ((lookup.Length == 1) && (lookup [0] is Type)) {
837 Type t = (Type) lookup [0];
839 Report.Error (305, loc,
840 "Using the generic type `{0}' " +
841 "requires {1} type arguments",
842 TypeManager.CSharpName (t),
843 TypeManager.GetNumberOfTypeArguments (t).ToString ());
848 return Error_MemberLookupFailed (lookup);
851 protected virtual Expression Error_MemberLookupFailed (MemberInfo[] members)
853 for (int i = 0; i < members.Length; ++i) {
854 if (!(members [i] is MethodBase))
858 // By default propagate the closest candidates upwards
859 return new MethodGroupExpr (members, type, loc);
863 /// Returns an expression that can be used to invoke operator true
864 /// on the expression if it exists.
866 static public Expression GetOperatorTrue (EmitContext ec, Expression e, Location loc)
868 return GetOperatorTrueOrFalse (ec, e, true, loc);
872 /// Returns an expression that can be used to invoke operator false
873 /// on the expression if it exists.
875 static public Expression GetOperatorFalse (EmitContext ec, Expression e, Location loc)
877 return GetOperatorTrueOrFalse (ec, e, false, loc);
880 static Expression GetOperatorTrueOrFalse (EmitContext ec, Expression e, bool is_true, Location loc)
882 MethodGroupExpr operator_group;
885 if (TypeManager.IsNullableType (e.Type))
886 return new Nullable.OperatorTrueOrFalse (e, is_true, loc).Resolve (ec);
889 operator_group = MethodLookup (ec.ContainerType, e.Type, is_true ? "op_True" : "op_False", loc) as MethodGroupExpr;
890 if (operator_group == null)
893 ArrayList arguments = new ArrayList (1);
894 arguments.Add (new Argument (e, Argument.AType.Expression));
895 operator_group = operator_group.OverloadResolve (
896 ec, arguments, false, loc);
898 if (operator_group == null)
901 return new StaticCallExpr ((MethodInfo) operator_group, arguments, loc);
905 /// Resolves the expression `e' into a boolean expression: either through
906 /// an implicit conversion, or through an `operator true' invocation
908 public static Expression ResolveBoolean (EmitContext ec, Expression e, Location loc)
914 if (e.Type == TypeManager.bool_type)
917 Expression converted = Convert.ImplicitConversion (ec, e, TypeManager.bool_type, Location.Null);
919 if (converted != null)
923 // If no implicit conversion to bool exists, try using `operator true'
925 converted = Expression.GetOperatorTrue (ec, e, loc);
926 if (converted == null){
927 e.Error_ValueCannotBeConverted (ec, loc, TypeManager.bool_type, false);
933 public virtual string ExprClassName
937 case ExprClass.Invalid:
939 case ExprClass.Value:
941 case ExprClass.Variable:
943 case ExprClass.Namespace:
947 case ExprClass.MethodGroup:
948 return "method group";
949 case ExprClass.PropertyAccess:
950 return "property access";
951 case ExprClass.EventAccess:
952 return "event access";
953 case ExprClass.IndexerAccess:
954 return "indexer access";
955 case ExprClass.Nothing:
958 throw new Exception ("Should not happen");
963 /// Reports that we were expecting `expr' to be of class `expected'
965 public void Error_UnexpectedKind (DeclSpace ds, string expected, Location loc)
967 Error_UnexpectedKind (ds, expected, ExprClassName, loc);
970 public void Error_UnexpectedKind (DeclSpace ds, string expected, string was, Location loc)
972 string name = GetSignatureForError ();
974 name = ds.GetSignatureForError () + '.' + name;
976 Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
977 name, was, expected);
980 public void Error_UnexpectedKind (ResolveFlags flags, Location loc)
982 string [] valid = new string [4];
985 if ((flags & ResolveFlags.VariableOrValue) != 0) {
986 valid [count++] = "variable";
987 valid [count++] = "value";
990 if ((flags & ResolveFlags.Type) != 0)
991 valid [count++] = "type";
993 if ((flags & ResolveFlags.MethodGroup) != 0)
994 valid [count++] = "method group";
997 valid [count++] = "unknown";
999 StringBuilder sb = new StringBuilder (valid [0]);
1000 for (int i = 1; i < count - 1; i++) {
1002 sb.Append (valid [i]);
1005 sb.Append ("' or `");
1006 sb.Append (valid [count - 1]);
1009 Report.Error (119, loc,
1010 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1013 public static void UnsafeError (Location loc)
1015 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1019 // Load the object from the pointer.
1021 public static void LoadFromPtr (ILGenerator ig, Type t)
1023 if (t == TypeManager.int32_type)
1024 ig.Emit (OpCodes.Ldind_I4);
1025 else if (t == TypeManager.uint32_type)
1026 ig.Emit (OpCodes.Ldind_U4);
1027 else if (t == TypeManager.short_type)
1028 ig.Emit (OpCodes.Ldind_I2);
1029 else if (t == TypeManager.ushort_type)
1030 ig.Emit (OpCodes.Ldind_U2);
1031 else if (t == TypeManager.char_type)
1032 ig.Emit (OpCodes.Ldind_U2);
1033 else if (t == TypeManager.byte_type)
1034 ig.Emit (OpCodes.Ldind_U1);
1035 else if (t == TypeManager.sbyte_type)
1036 ig.Emit (OpCodes.Ldind_I1);
1037 else if (t == TypeManager.uint64_type)
1038 ig.Emit (OpCodes.Ldind_I8);
1039 else if (t == TypeManager.int64_type)
1040 ig.Emit (OpCodes.Ldind_I8);
1041 else if (t == TypeManager.float_type)
1042 ig.Emit (OpCodes.Ldind_R4);
1043 else if (t == TypeManager.double_type)
1044 ig.Emit (OpCodes.Ldind_R8);
1045 else if (t == TypeManager.bool_type)
1046 ig.Emit (OpCodes.Ldind_I1);
1047 else if (t == TypeManager.intptr_type)
1048 ig.Emit (OpCodes.Ldind_I);
1049 else if (TypeManager.IsEnumType (t)) {
1050 if (t == TypeManager.enum_type)
1051 ig.Emit (OpCodes.Ldind_Ref);
1053 LoadFromPtr (ig, TypeManager.EnumToUnderlying (t));
1054 } else if (t.IsValueType || TypeManager.IsGenericParameter (t))
1055 ig.Emit (OpCodes.Ldobj, t);
1056 else if (t.IsPointer)
1057 ig.Emit (OpCodes.Ldind_I);
1059 ig.Emit (OpCodes.Ldind_Ref);
1063 // The stack contains the pointer and the value of type `type'
1065 public static void StoreFromPtr (ILGenerator ig, Type type)
1067 if (TypeManager.IsEnumType (type))
1068 type = TypeManager.EnumToUnderlying (type);
1069 if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
1070 ig.Emit (OpCodes.Stind_I4);
1071 else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
1072 ig.Emit (OpCodes.Stind_I8);
1073 else if (type == TypeManager.char_type || type == TypeManager.short_type ||
1074 type == TypeManager.ushort_type)
1075 ig.Emit (OpCodes.Stind_I2);
1076 else if (type == TypeManager.float_type)
1077 ig.Emit (OpCodes.Stind_R4);
1078 else if (type == TypeManager.double_type)
1079 ig.Emit (OpCodes.Stind_R8);
1080 else if (type == TypeManager.byte_type || type == TypeManager.sbyte_type ||
1081 type == TypeManager.bool_type)
1082 ig.Emit (OpCodes.Stind_I1);
1083 else if (type == TypeManager.intptr_type)
1084 ig.Emit (OpCodes.Stind_I);
1085 else if (type.IsValueType || TypeManager.IsGenericParameter (type))
1086 ig.Emit (OpCodes.Stobj, type);
1088 ig.Emit (OpCodes.Stind_Ref);
1092 // Returns the size of type `t' if known, otherwise, 0
1094 public static int GetTypeSize (Type t)
1096 t = TypeManager.TypeToCoreType (t);
1097 if (t == TypeManager.int32_type ||
1098 t == TypeManager.uint32_type ||
1099 t == TypeManager.float_type)
1101 else if (t == TypeManager.int64_type ||
1102 t == TypeManager.uint64_type ||
1103 t == TypeManager.double_type)
1105 else if (t == TypeManager.byte_type ||
1106 t == TypeManager.sbyte_type ||
1107 t == TypeManager.bool_type)
1109 else if (t == TypeManager.short_type ||
1110 t == TypeManager.char_type ||
1111 t == TypeManager.ushort_type)
1113 else if (t == TypeManager.decimal_type)
1119 public static void Error_NegativeArrayIndex (Location loc)
1121 Report.Error (248, loc, "Cannot create an array with a negative size");
1124 protected void Error_CannotCallAbstractBase (string name)
1126 Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
1130 // Converts `source' to an int, uint, long or ulong.
1132 public Expression ExpressionToArrayArgument (EmitContext ec, Expression source, Location loc)
1136 using (ec.With (EmitContext.Flags.CheckState, true)) {
1137 target = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, loc);
1139 target = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, loc);
1141 target = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, loc);
1143 target = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, loc);
1145 if (target == null) {
1146 source.Error_ValueCannotBeConverted (ec, loc, TypeManager.int32_type, false);
1152 // Only positive constants are allowed at compile time
1154 if (target is Constant){
1155 if (target is IntConstant){
1156 if (((IntConstant) target).Value < 0){
1157 Error_NegativeArrayIndex (loc);
1162 if (target is LongConstant){
1163 if (((LongConstant) target).Value < 0){
1164 Error_NegativeArrayIndex (loc);
1175 // Derived classes implement this method by cloning the fields that
1176 // could become altered during the Resolve stage
1178 // Only expressions that are created for the parser need to implement
1181 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1183 throw new NotImplementedException (
1185 "CloneTo not implemented for expression {0}", this.GetType ()));
1189 // Clones an expression created by the parser.
1191 // We only support expressions created by the parser so far, not
1192 // expressions that have been resolved (many more classes would need
1193 // to implement CloneTo).
1195 // This infrastructure is here merely for Lambda expressions which
1196 // compile the same code using different type values for the same
1197 // arguments to find the correct overload
1199 public Expression Clone (CloneContext clonectx)
1201 Expression cloned = (Expression) MemberwiseClone ();
1202 CloneTo (clonectx, cloned);
1209 /// This is just a base class for expressions that can
1210 /// appear on statements (invocations, object creation,
1211 /// assignments, post/pre increment and decrement). The idea
1212 /// being that they would support an extra Emition interface that
1213 /// does not leave a result on the stack.
1215 public abstract class ExpressionStatement : Expression {
1217 public virtual ExpressionStatement ResolveStatement (EmitContext ec)
1219 Expression e = Resolve (ec);
1223 ExpressionStatement es = e as ExpressionStatement;
1225 Error_InvalidExpressionStatement ();
1231 /// Requests the expression to be emitted in a `statement'
1232 /// context. This means that no new value is left on the
1233 /// stack after invoking this method (constrasted with
1234 /// Emit that will always leave a value on the stack).
1236 public abstract void EmitStatement (EmitContext ec);
1240 /// This kind of cast is used to encapsulate the child
1241 /// whose type is child.Type into an expression that is
1242 /// reported to return "return_type". This is used to encapsulate
1243 /// expressions which have compatible types, but need to be dealt
1244 /// at higher levels with.
1246 /// For example, a "byte" expression could be encapsulated in one
1247 /// of these as an "unsigned int". The type for the expression
1248 /// would be "unsigned int".
1251 public class EmptyCast : Expression
1253 protected Expression child;
1255 protected EmptyCast (Expression child, Type return_type)
1257 eclass = child.eclass;
1258 loc = child.Location;
1263 public static Expression Create (Expression child, Type type)
1265 Constant c = child as Constant;
1267 return new EmptyConstantCast (c, type);
1269 return new EmptyCast (child, type);
1272 public override Expression DoResolve (EmitContext ec)
1274 // This should never be invoked, we are born in fully
1275 // initialized state.
1280 public override void Emit (EmitContext ec)
1285 public override bool GetAttributableValue (Type valueType, out object value)
1287 return child.GetAttributableValue (valueType, out value);
1290 protected override void CloneTo (CloneContext clonectx, Expression t)
1292 EmptyCast target = (EmptyCast) t;
1294 target.child = child.Clone (clonectx);
1299 /// Performs a cast using an operator (op_Explicit or op_Implicit)
1301 public class OperatorCast : EmptyCast {
1302 MethodInfo conversion_operator;
1305 public OperatorCast (Expression child, Type target_type) : this (child, target_type, false) {}
1307 public OperatorCast (Expression child, Type target_type, bool find_explicit)
1308 : base (child, target_type)
1310 this.find_explicit = find_explicit;
1313 // Returns the implicit operator that converts from
1314 // 'child.Type' to our target type (type)
1315 MethodInfo GetConversionOperator (bool find_explicit)
1317 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1321 mi = TypeManager.MemberLookup (child.Type, child.Type, child.Type, MemberTypes.Method,
1322 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1325 mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1326 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1329 foreach (MethodInfo oper in mi) {
1330 ParameterData pd = TypeManager.GetParameterData (oper);
1332 if (pd.ParameterType (0) == child.Type && oper.ReturnType == type)
1340 public override void Emit (EmitContext ec)
1342 ILGenerator ig = ec.ig;
1345 conversion_operator = GetConversionOperator (find_explicit);
1347 if (conversion_operator == null)
1348 throw new InternalErrorException ("Outer conversion routine is out of sync");
1350 ig.Emit (OpCodes.Call, conversion_operator);
1356 /// This is a numeric cast to a Decimal
1358 public class CastToDecimal : EmptyCast {
1359 MethodInfo conversion_operator;
1361 public CastToDecimal (Expression child)
1362 : this (child, false)
1366 public CastToDecimal (Expression child, bool find_explicit)
1367 : base (child, TypeManager.decimal_type)
1369 conversion_operator = GetConversionOperator (find_explicit);
1371 if (conversion_operator == null)
1372 throw new InternalErrorException ("Outer conversion routine is out of sync");
1375 // Returns the implicit operator that converts from
1376 // 'child.Type' to System.Decimal.
1377 MethodInfo GetConversionOperator (bool find_explicit)
1379 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1381 MemberInfo [] mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1382 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1384 foreach (MethodInfo oper in mi) {
1385 ParameterData pd = TypeManager.GetParameterData (oper);
1387 if (pd.ParameterType (0) == child.Type && oper.ReturnType == type)
1393 public override void Emit (EmitContext ec)
1395 ILGenerator ig = ec.ig;
1398 ig.Emit (OpCodes.Call, conversion_operator);
1403 /// This is an explicit numeric cast from a Decimal
1405 public class CastFromDecimal : EmptyCast
1407 static IDictionary operators;
1409 public CastFromDecimal (Expression child, Type return_type)
1410 : base (child, return_type)
1412 if (child.Type != TypeManager.decimal_type)
1413 throw new InternalErrorException (
1414 "The expected type is Decimal, instead it is " + child.Type.FullName);
1417 // Returns the explicit operator that converts from an
1418 // express of type System.Decimal to 'type'.
1419 public Expression Resolve ()
1421 if (operators == null) {
1422 MemberInfo[] all_oper = TypeManager.MemberLookup (TypeManager.decimal_type,
1423 TypeManager.decimal_type, TypeManager.decimal_type, MemberTypes.Method,
1424 BindingFlags.Static | BindingFlags.Public, "op_Explicit", null);
1426 operators = new System.Collections.Specialized.HybridDictionary ();
1427 foreach (MethodInfo oper in all_oper) {
1428 ParameterData pd = TypeManager.GetParameterData (oper);
1429 if (pd.ParameterType (0) == TypeManager.decimal_type)
1430 operators.Add (oper.ReturnType, oper);
1434 return operators.Contains (type) ? this : null;
1437 public override void Emit (EmitContext ec)
1439 ILGenerator ig = ec.ig;
1442 ig.Emit (OpCodes.Call, (MethodInfo)operators [type]);
1448 // Constant specialization of EmptyCast.
1449 // We need to special case this since an empty cast of
1450 // a constant is still a constant.
1452 public class EmptyConstantCast : Constant
1454 public readonly Constant child;
1456 public EmptyConstantCast(Constant child, Type type)
1457 : base (child.Location)
1459 eclass = child.eclass;
1464 public override string AsString ()
1466 return child.AsString ();
1469 public override object GetValue ()
1471 return child.GetValue ();
1474 public override Constant ConvertExplicitly (bool inCheckedContext, Type target_type)
1476 // FIXME: check that 'type' can be converted to 'target_type' first
1477 return child.ConvertExplicitly (inCheckedContext, target_type);
1480 public override Constant Increment ()
1482 return child.Increment ();
1485 public override bool IsDefaultValue {
1486 get { return child.IsDefaultValue; }
1489 public override bool IsNegative {
1490 get { return child.IsNegative; }
1493 public override bool IsZeroInteger {
1494 get { return child.IsZeroInteger; }
1497 public override void Emit (EmitContext ec)
1502 public override Constant ConvertImplicitly (Type target_type)
1504 // FIXME: Do we need to check user conversions?
1505 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1507 return child.ConvertImplicitly (target_type);
1513 /// This class is used to wrap literals which belong inside Enums
1515 public class EnumConstant : Constant {
1516 public Constant Child;
1518 public EnumConstant (Constant child, Type enum_type):
1519 base (child.Location)
1521 eclass = child.eclass;
1526 public override Expression DoResolve (EmitContext ec)
1528 // This should never be invoked, we are born in fully
1529 // initialized state.
1534 public override void Emit (EmitContext ec)
1539 public override bool GetAttributableValue (Type valueType, out object value)
1541 value = GetTypedValue ();
1545 public override string GetSignatureForError()
1547 return TypeManager.CSharpName (Type);
1550 public override object GetValue ()
1552 return Child.GetValue ();
1555 public override object GetTypedValue ()
1557 // FIXME: runtime is not ready to work with just emited enums
1558 if (!RootContext.StdLib) {
1559 return Child.GetValue ();
1562 return System.Enum.ToObject (type, Child.GetValue ());
1565 public override string AsString ()
1567 return TypeManager.CSharpEnumValue (type, Child.GetValue ());
1570 public override Constant Increment()
1572 return new EnumConstant (Child.Increment (), type);
1575 public override bool IsDefaultValue {
1577 return Child.IsDefaultValue;
1581 public override bool IsZeroInteger {
1582 get { return Child.IsZeroInteger; }
1585 public override bool IsNegative {
1587 return Child.IsNegative;
1591 public override Constant ConvertExplicitly(bool inCheckedContext, Type target_type)
1593 if (Child.Type == target_type)
1596 return Child.ConvertExplicitly (inCheckedContext, target_type);
1599 public override Constant ConvertImplicitly (Type type)
1601 Type this_type = TypeManager.DropGenericTypeArguments (Type);
1602 type = TypeManager.DropGenericTypeArguments (type);
1604 if (this_type == type) {
1605 // This is workaround of mono bug. It can be removed when the latest corlib spreads enough
1606 if (TypeManager.IsEnumType (type.UnderlyingSystemType))
1609 Type child_type = TypeManager.DropGenericTypeArguments (Child.Type);
1610 if (type.UnderlyingSystemType != child_type)
1611 Child = Child.ConvertImplicitly (type.UnderlyingSystemType);
1615 if (!Convert.ImplicitStandardConversionExists (this, type)){
1619 return Child.ConvertImplicitly(type);
1625 /// This kind of cast is used to encapsulate Value Types in objects.
1627 /// The effect of it is to box the value type emitted by the previous
1630 public class BoxedCast : EmptyCast {
1632 public BoxedCast (Expression expr, Type target_type)
1633 : base (expr, target_type)
1635 eclass = ExprClass.Value;
1638 public override Expression DoResolve (EmitContext ec)
1640 // This should never be invoked, we are born in fully
1641 // initialized state.
1646 public override void Emit (EmitContext ec)
1650 ec.ig.Emit (OpCodes.Box, child.Type);
1654 public class UnboxCast : EmptyCast {
1655 public UnboxCast (Expression expr, Type return_type)
1656 : base (expr, return_type)
1660 public override Expression DoResolve (EmitContext ec)
1662 // This should never be invoked, we are born in fully
1663 // initialized state.
1668 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1670 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
1671 Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
1672 return base.DoResolveLValue (ec, right_side);
1675 public override void Emit (EmitContext ec)
1678 ILGenerator ig = ec.ig;
1682 if (t.IsGenericParameter || t.IsGenericType && t.IsValueType)
1683 ig.Emit (OpCodes.Unbox_Any, t);
1687 ig.Emit (OpCodes.Unbox, t);
1689 LoadFromPtr (ig, t);
1695 /// This is used to perform explicit numeric conversions.
1697 /// Explicit numeric conversions might trigger exceptions in a checked
1698 /// context, so they should generate the conv.ovf opcodes instead of
1701 public class ConvCast : EmptyCast {
1702 public enum Mode : byte {
1703 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1705 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1706 U2_I1, U2_U1, U2_I2, U2_CH,
1707 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1708 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1709 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH,
1710 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH,
1711 CH_I1, CH_U1, CH_I2,
1712 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1713 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4
1718 public ConvCast (Expression child, Type return_type, Mode m)
1719 : base (child, return_type)
1724 public override Expression DoResolve (EmitContext ec)
1726 // This should never be invoked, we are born in fully
1727 // initialized state.
1732 public override string ToString ()
1734 return String.Format ("ConvCast ({0}, {1})", mode, child);
1737 public override void Emit (EmitContext ec)
1739 ILGenerator ig = ec.ig;
1745 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1746 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1747 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1748 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1749 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1751 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1752 case Mode.U1_CH: /* nothing */ break;
1754 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1755 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1756 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1757 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1758 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1759 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1761 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1762 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1763 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1764 case Mode.U2_CH: /* nothing */ break;
1766 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1767 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1768 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1769 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1770 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1771 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1772 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1774 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1775 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1776 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1777 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1778 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1779 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1781 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1782 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1783 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1784 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1785 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1786 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1787 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1788 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1790 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1791 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1792 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1793 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1794 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1795 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1796 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1797 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1799 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1800 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1801 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1803 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1804 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1805 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1806 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1807 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1808 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1809 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1810 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1811 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1813 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1814 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1815 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1816 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1817 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1818 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1819 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1820 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1821 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1822 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1826 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
1827 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
1828 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
1829 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
1830 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
1832 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
1833 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
1835 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
1836 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
1837 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
1838 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
1839 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
1840 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
1842 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
1843 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
1844 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
1845 case Mode.U2_CH: /* nothing */ break;
1847 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
1848 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
1849 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
1850 case Mode.I4_U4: /* nothing */ break;
1851 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
1852 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
1853 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
1855 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
1856 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
1857 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
1858 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
1859 case Mode.U4_I4: /* nothing */ break;
1860 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
1862 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
1863 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
1864 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
1865 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
1866 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
1867 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
1868 case Mode.I8_U8: /* nothing */ break;
1869 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
1871 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
1872 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
1873 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
1874 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
1875 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
1876 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
1877 case Mode.U8_I8: /* nothing */ break;
1878 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
1880 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
1881 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
1882 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
1884 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
1885 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
1886 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
1887 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
1888 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
1889 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
1890 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
1891 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
1892 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
1894 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
1895 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
1896 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
1897 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
1898 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
1899 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
1900 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
1901 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
1902 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
1903 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1909 public class OpcodeCast : EmptyCast {
1913 public OpcodeCast (Expression child, Type return_type, OpCode op)
1914 : base (child, return_type)
1918 second_valid = false;
1921 public OpcodeCast (Expression child, Type return_type, OpCode op, OpCode op2)
1922 : base (child, return_type)
1927 second_valid = true;
1930 public override Expression DoResolve (EmitContext ec)
1932 // This should never be invoked, we are born in fully
1933 // initialized state.
1938 public override void Emit (EmitContext ec)
1949 /// This kind of cast is used to encapsulate a child and cast it
1950 /// to the class requested
1952 public class ClassCast : EmptyCast {
1953 public ClassCast (Expression child, Type return_type)
1954 : base (child, return_type)
1959 public override Expression DoResolve (EmitContext ec)
1961 // This should never be invoked, we are born in fully
1962 // initialized state.
1967 public override void Emit (EmitContext ec)
1971 if (TypeManager.IsGenericParameter (child.Type))
1972 ec.ig.Emit (OpCodes.Box, child.Type);
1975 if (type.IsGenericParameter)
1976 ec.ig.Emit (OpCodes.Unbox_Any, type);
1979 ec.ig.Emit (OpCodes.Castclass, type);
1984 /// SimpleName expressions are formed of a single word and only happen at the beginning
1985 /// of a dotted-name.
1987 public class SimpleName : Expression {
1988 public readonly string Name;
1989 public readonly TypeArguments Arguments;
1992 public SimpleName (string name, Location l)
1998 public SimpleName (string name, TypeArguments args, Location l)
2005 public SimpleName (string name, TypeParameter[] type_params, Location l)
2010 Arguments = new TypeArguments (l);
2011 foreach (TypeParameter type_param in type_params)
2012 Arguments.Add (new TypeParameterExpr (type_param, l));
2015 public static string RemoveGenericArity (string name)
2018 StringBuilder sb = null;
2020 int pos = name.IndexOf ('`', start);
2025 sb.Append (name.Substring (start));
2030 sb = new StringBuilder ();
2031 sb.Append (name.Substring (start, pos-start));
2034 while ((pos < name.Length) && Char.IsNumber (name [pos]))
2038 } while (start < name.Length);
2040 return sb.ToString ();
2043 public SimpleName GetMethodGroup ()
2045 return new SimpleName (RemoveGenericArity (Name), Arguments, loc);
2048 public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
2050 if (ec.IsInFieldInitializer)
2051 Report.Error (236, l,
2052 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2056 120, l, "`{0}': An object reference is required for the nonstatic field, method or property",
2060 public bool IdenticalNameAndTypeName (EmitContext ec, Expression resolved_to, Location loc)
2062 return resolved_to != null && resolved_to.Type != null &&
2063 resolved_to.Type.Name == Name &&
2064 (ec.DeclContainer.LookupNamespaceOrType (Name, loc, /* ignore_cs0104 = */ true) != null);
2067 public override Expression DoResolve (EmitContext ec)
2069 return SimpleNameResolve (ec, null, false);
2072 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
2074 return SimpleNameResolve (ec, right_side, false);
2078 public Expression DoResolve (EmitContext ec, bool intermediate)
2080 return SimpleNameResolve (ec, null, intermediate);
2083 private bool IsNestedChild (Type t, Type parent)
2088 while (parent != null) {
2089 parent = TypeManager.DropGenericTypeArguments (parent);
2090 if (TypeManager.IsNestedChildOf (t, parent))
2093 parent = parent.BaseType;
2099 FullNamedExpression ResolveNested (IResolveContext ec, Type t)
2101 if (!TypeManager.IsGenericTypeDefinition (t) && !TypeManager.IsGenericType (t))
2104 DeclSpace ds = ec.DeclContainer;
2105 while (ds != null) {
2106 if (IsNestedChild (t, ds.TypeBuilder))
2115 Type[] gen_params = TypeManager.GetTypeArguments (t);
2117 int arg_count = Arguments != null ? Arguments.Count : 0;
2119 for (; (ds != null) && ds.IsGeneric; ds = ds.Parent) {
2120 if (arg_count + ds.CountTypeParameters == gen_params.Length) {
2121 TypeArguments new_args = new TypeArguments (loc);
2122 foreach (TypeParameter param in ds.TypeParameters)
2123 new_args.Add (new TypeParameterExpr (param, loc));
2125 if (Arguments != null)
2126 new_args.Add (Arguments);
2128 return new ConstructedType (t, new_args, loc);
2135 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2137 FullNamedExpression fne = ec.GenericDeclContainer.LookupGeneric (Name, loc);
2139 return fne.ResolveAsTypeStep (ec, silent);
2141 int errors = Report.Errors;
2142 fne = ec.DeclContainer.LookupNamespaceOrType (Name, loc, /*ignore_cs0104=*/ false);
2145 if (fne.Type == null)
2148 FullNamedExpression nested = ResolveNested (ec, fne.Type);
2150 return nested.ResolveAsTypeStep (ec, false);
2152 if (Arguments != null) {
2153 ConstructedType ct = new ConstructedType (fne, Arguments, loc);
2154 return ct.ResolveAsTypeStep (ec, false);
2160 if (silent || errors != Report.Errors)
2163 Error_TypeOrNamespaceNotFound (ec);
2167 protected virtual void Error_TypeOrNamespaceNotFound (IResolveContext ec)
2169 MemberCore mc = ec.DeclContainer.GetDefinition (Name);
2171 Error_UnexpectedKind (ec.DeclContainer, "type", GetMemberType (mc), loc);
2175 string ns = ec.DeclContainer.NamespaceEntry.NS.Name;
2176 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2177 foreach (Assembly a in RootNamespace.Global.Assemblies) {
2178 Type type = a.GetType (fullname);
2180 Report.SymbolRelatedToPreviousError (type);
2181 Expression.ErrorIsInaccesible (loc, TypeManager.CSharpName (type));
2186 Type t = ec.DeclContainer.LookupAnyGeneric (Name);
2188 Namespace.Error_InvalidNumberOfTypeArguments (t, loc);
2192 if (Arguments != null) {
2193 FullNamedExpression retval = ec.DeclContainer.LookupNamespaceOrType (SimpleName.RemoveGenericArity (Name), loc, true);
2194 if (retval != null) {
2195 Namespace.Error_TypeArgumentsCannotBeUsed (retval.Type, loc, "type");
2200 NamespaceEntry.Error_NamespaceNotFound (loc, Name);
2203 // TODO: I am still not convinced about this. If someone else will need it
2204 // implement this as virtual property in MemberCore hierarchy
2205 public static string GetMemberType (MemberCore mc)
2211 if (mc is FieldBase)
2213 if (mc is MethodCore)
2215 if (mc is EnumMember)
2223 Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2229 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2235 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2242 /// 7.5.2: Simple Names.
2244 /// Local Variables and Parameters are handled at
2245 /// parse time, so they never occur as SimpleNames.
2247 /// The `intermediate' flag is used by MemberAccess only
2248 /// and it is used to inform us that it is ok for us to
2249 /// avoid the static check, because MemberAccess might end
2250 /// up resolving the Name as a Type name and the access as
2251 /// a static type access.
2253 /// ie: Type Type; .... { Type.GetType (""); }
2255 /// Type is both an instance variable and a Type; Type.GetType
2256 /// is the static method not an instance method of type.
2258 Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2260 Expression e = null;
2263 // Stage 1: Performed by the parser (binding to locals or parameters).
2265 Block current_block = ec.CurrentBlock;
2266 if (current_block != null){
2267 LocalInfo vi = current_block.GetLocalInfo (Name);
2269 if (Arguments != null) {
2270 Report.Error (307, loc,
2271 "The variable `{0}' cannot be used with type arguments",
2276 LocalVariableReference var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2277 if (right_side != null) {
2278 return var.ResolveLValue (ec, right_side, loc);
2280 ResolveFlags rf = ResolveFlags.VariableOrValue;
2282 rf |= ResolveFlags.DisableFlowAnalysis;
2283 return var.Resolve (ec, rf);
2287 ParameterReference pref = current_block.Toplevel.GetParameterReference (Name, loc);
2289 if (Arguments != null) {
2290 Report.Error (307, loc,
2291 "The variable `{0}' cannot be used with type arguments",
2296 if (right_side != null)
2297 return pref.ResolveLValue (ec, right_side, loc);
2299 return pref.Resolve (ec);
2302 Expression expr = current_block.Toplevel.GetTransparentIdentifier (Name);
2304 if (right_side != null)
2305 return expr.ResolveLValue (ec, right_side, loc);
2306 return expr.Resolve (ec);
2311 // Stage 2: Lookup members
2314 DeclSpace lookup_ds = ec.DeclContainer;
2315 Type almost_matched_type = null;
2316 ArrayList almost_matched = null;
2318 if (lookup_ds.TypeBuilder == null)
2321 e = MemberLookup (ec.ContainerType, lookup_ds.TypeBuilder, Name, loc);
2325 if (almost_matched == null && almostMatchedMembers.Count > 0) {
2326 almost_matched_type = lookup_ds.TypeBuilder;
2327 almost_matched = (ArrayList) almostMatchedMembers.Clone ();
2330 lookup_ds =lookup_ds.Parent;
2331 } while (lookup_ds != null);
2333 if (e == null && ec.ContainerType != null)
2334 e = MemberLookup (ec.ContainerType, ec.ContainerType, Name, loc);
2337 if (almost_matched == null && almostMatchedMembers.Count > 0) {
2338 almost_matched_type = ec.ContainerType;
2339 almost_matched = (ArrayList) almostMatchedMembers.Clone ();
2341 e = ResolveAsTypeStep (ec, true);
2345 if (current_block != null) {
2346 IKnownVariable ikv = current_block.Explicit.GetKnownVariable (Name);
2348 LocalInfo li = ikv as LocalInfo;
2349 // Supress CS0219 warning
2353 Error_VariableIsUsedBeforeItIsDeclared (Name);
2358 if (almost_matched != null)
2359 almostMatchedMembers = almost_matched;
2360 if (almost_matched_type == null)
2361 almost_matched_type = ec.ContainerType;
2362 Error_MemberLookupFailed (ec.ContainerType, null, almost_matched_type, Name,
2363 ec.DeclContainer.Name, AllMemberTypes, AllBindingFlags);
2367 if (e is TypeExpr) {
2368 if (Arguments == null)
2371 ConstructedType ct = new ConstructedType (
2372 (FullNamedExpression) e, Arguments, loc);
2373 return ct.ResolveAsTypeStep (ec, false);
2376 if (e is MemberExpr) {
2377 MemberExpr me = (MemberExpr) e;
2380 if (me.IsInstance) {
2381 if (ec.IsStatic || ec.IsInFieldInitializer) {
2383 // Note that an MemberExpr can be both IsInstance and IsStatic.
2384 // An unresolved MethodGroupExpr can contain both kinds of methods
2385 // and each predicate is true if the MethodGroupExpr contains
2386 // at least one of that kind of method.
2390 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2391 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2392 return EmptyExpression.Null;
2396 // Pass the buck to MemberAccess and Invocation.
2398 left = EmptyExpression.Null;
2400 left = ec.GetThis (loc);
2403 left = new TypeExpression (ec.ContainerType, loc);
2406 e = me.ResolveMemberAccess (ec, left, loc, null);
2410 me = e as MemberExpr;
2414 if (Arguments != null) {
2415 MethodGroupExpr mg = me as MethodGroupExpr;
2419 return mg.ResolveGeneric (ec, Arguments);
2422 if (!me.IsStatic && (me.InstanceExpression != null) &&
2423 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2424 me.InstanceExpression.Type != me.DeclaringType &&
2425 !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2426 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2427 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2428 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2432 return (right_side != null)
2433 ? me.DoResolveLValue (ec, right_side)
2434 : me.DoResolve (ec);
2440 public override void Emit (EmitContext ec)
2442 throw new InternalErrorException ("The resolve phase was not executed");
2445 public override string ToString ()
2450 public override string GetSignatureForError ()
2452 if (Arguments != null) {
2453 return TypeManager.RemoveGenericArity (Name) + "<" +
2454 Arguments.GetSignatureForError () + ">";
2460 protected override void CloneTo (CloneContext clonectx, Expression target)
2462 // CloneTo: Nothing, we do not keep any state on this expression
2467 /// Represents a namespace or a type. The name of the class was inspired by
2468 /// section 10.8.1 (Fully Qualified Names).
2470 public abstract class FullNamedExpression : Expression {
2471 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2476 public abstract string FullName {
2482 /// Expression that evaluates to a type
2484 public abstract class TypeExpr : FullNamedExpression {
2485 override public FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2487 TypeExpr t = DoResolveAsTypeStep (ec);
2491 eclass = ExprClass.Type;
2495 override public Expression DoResolve (EmitContext ec)
2497 return ResolveAsTypeTerminal (ec, false);
2500 override public void Emit (EmitContext ec)
2502 throw new Exception ("Should never be called");
2505 public virtual bool CheckAccessLevel (DeclSpace ds)
2507 return ds.CheckAccessLevel (Type);
2510 public virtual bool AsAccessible (DeclSpace ds, int flags)
2512 return ds.AsAccessible (Type, flags);
2515 public virtual bool IsClass {
2516 get { return Type.IsClass; }
2519 public virtual bool IsValueType {
2520 get { return Type.IsValueType; }
2523 public virtual bool IsInterface {
2524 get { return Type.IsInterface; }
2527 public virtual bool IsSealed {
2528 get { return Type.IsSealed; }
2531 public virtual bool CanInheritFrom ()
2533 if (Type == TypeManager.enum_type ||
2534 (Type == TypeManager.value_type && RootContext.StdLib) ||
2535 Type == TypeManager.multicast_delegate_type ||
2536 Type == TypeManager.delegate_type ||
2537 Type == TypeManager.array_type)
2543 protected abstract TypeExpr DoResolveAsTypeStep (IResolveContext ec);
2545 public abstract string Name {
2549 public override bool Equals (object obj)
2551 TypeExpr tobj = obj as TypeExpr;
2555 return Type == tobj.Type;
2558 public override int GetHashCode ()
2560 return Type.GetHashCode ();
2563 public override string ToString ()
2570 /// Fully resolved Expression that already evaluated to a type
2572 public class TypeExpression : TypeExpr {
2573 public TypeExpression (Type t, Location l)
2576 eclass = ExprClass.Type;
2580 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2585 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2590 public override string Name {
2591 get { return Type.ToString (); }
2594 public override string FullName {
2595 get { return Type.FullName; }
2600 /// Used to create types from a fully qualified name. These are just used
2601 /// by the parser to setup the core types. A TypeLookupExpression is always
2602 /// classified as a type.
2604 public sealed class TypeLookupExpression : TypeExpr {
2605 readonly string name;
2607 public TypeLookupExpression (string name)
2610 eclass = ExprClass.Type;
2613 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2615 // It's null for corlib compilation only
2617 return DoResolveAsTypeStep (ec);
2622 private class UnexpectedType
2626 // This performes recursive type lookup, providing support for generic types.
2627 // For example, given the type:
2629 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]]
2631 // The types will be checked in the following order:
2634 // System.Collections |
2635 // System.Collections.Generic |
2637 // System | recursive call 1 |
2638 // System.Int32 _| | main method call
2640 // System | recursive call 2 |
2641 // System.String _| |
2643 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]] _|
2645 private Type TypeLookup (IResolveContext ec, string name)
2650 FullNamedExpression resolved = null;
2652 Type recursive_type = null;
2653 while (index < name.Length) {
2654 if (name[index] == '[') {
2659 if (name[index] == '[')
2661 else if (name[index] == ']')
2663 } while (braces > 0);
2664 recursive_type = TypeLookup (ec, name.Substring (open + 1, index - open - 1));
2665 if (recursive_type == null || (recursive_type == typeof(UnexpectedType)))
2666 return recursive_type;
2669 if (name[index] == ',')
2671 else if ((name[index] == '.' && !done) || (index == name.Length && name[0] != '[')) {
2672 string substring = name.Substring(dot, index - dot);
2674 if (resolved == null)
2675 resolved = RootNamespace.Global.Lookup (ec.DeclContainer, substring, Location.Null);
2676 else if (resolved is Namespace)
2677 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
2678 else if (type != null)
2679 type = TypeManager.GetNestedType (type, substring);
2683 if (resolved == null)
2685 else if (type == null && resolved is TypeExpr)
2686 type = resolved.Type;
2693 if (name[0] != '[') {
2694 string substring = name.Substring(dot, index - dot);
2697 return TypeManager.GetNestedType (type, substring);
2699 if (resolved != null) {
2700 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
2701 if (resolved is TypeExpr)
2702 return resolved.Type;
2704 if (resolved == null)
2707 resolved.Error_UnexpectedKind (ec.DeclContainer, "type", loc);
2708 return typeof (UnexpectedType);
2714 return recursive_type;
2717 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2719 Type t = TypeLookup (ec, name);
2721 NamespaceEntry.Error_NamespaceNotFound (loc, name);
2724 if (t == typeof(UnexpectedType))
2730 public override string Name {
2731 get { return name; }
2734 public override string FullName {
2735 get { return name; }
2738 protected override void CloneTo (CloneContext clonectx, Expression target)
2740 // CloneTo: Nothing, we do not keep any state on this expression
2743 public override string GetSignatureForError ()
2746 return TypeManager.CSharpName (name);
2748 return base.GetSignatureForError ();
2753 /// Represents an "unbound generic type", ie. typeof (Foo<>).
2756 public class UnboundTypeExpression : TypeExpr
2760 public UnboundTypeExpression (MemberName name, Location l)
2766 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2769 if (name.Left != null) {
2770 Expression lexpr = name.Left.GetTypeExpression ();
2771 expr = new MemberAccess (lexpr, name.Basename);
2773 expr = new SimpleName (name.Basename, loc);
2776 FullNamedExpression fne = expr.ResolveAsTypeStep (ec, false);
2781 return new TypeExpression (type, loc);
2784 public override string Name {
2785 get { return name.FullName; }
2788 public override string FullName {
2789 get { return name.FullName; }
2793 public class TypeAliasExpression : TypeExpr {
2794 FullNamedExpression alias;
2799 public TypeAliasExpression (FullNamedExpression alias, TypeArguments args, Location l)
2805 eclass = ExprClass.Type;
2807 name = alias.FullName + "<" + args.ToString () + ">";
2809 name = alias.FullName;
2812 public override string Name {
2813 get { return alias.FullName; }
2816 public override string FullName {
2817 get { return name; }
2820 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2822 texpr = alias.ResolveAsTypeTerminal (ec, false);
2826 Type type = texpr.Type;
2827 int num_args = TypeManager.GetNumberOfTypeArguments (type);
2830 if (num_args == 0) {
2831 Report.Error (308, loc,
2832 "The non-generic type `{0}' cannot " +
2833 "be used with type arguments.",
2834 TypeManager.CSharpName (type));
2838 ConstructedType ctype = new ConstructedType (type, args, loc);
2839 return ctype.ResolveAsTypeTerminal (ec, false);
2840 } else if (num_args > 0) {
2841 Report.Error (305, loc,
2842 "Using the generic type `{0}' " +
2843 "requires {1} type arguments",
2844 TypeManager.CSharpName (type), num_args.ToString ());
2851 public override bool CheckAccessLevel (DeclSpace ds)
2853 return texpr.CheckAccessLevel (ds);
2856 public override bool AsAccessible (DeclSpace ds, int flags)
2858 return texpr.AsAccessible (ds, flags);
2861 public override bool IsClass {
2862 get { return texpr.IsClass; }
2865 public override bool IsValueType {
2866 get { return texpr.IsValueType; }
2869 public override bool IsInterface {
2870 get { return texpr.IsInterface; }
2873 public override bool IsSealed {
2874 get { return texpr.IsSealed; }
2879 /// This class denotes an expression which evaluates to a member
2880 /// of a struct or a class.
2882 public abstract class MemberExpr : Expression
2885 /// The name of this member.
2887 public abstract string Name {
2892 /// Whether this is an instance member.
2894 public abstract bool IsInstance {
2899 /// Whether this is a static member.
2901 public abstract bool IsStatic {
2906 /// The type which declares this member.
2908 public abstract Type DeclaringType {
2913 /// The instance expression associated with this member, if it's a
2914 /// non-static member.
2916 public Expression InstanceExpression;
2918 public static void error176 (Location loc, string name)
2920 Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
2921 "with an instance reference, qualify it with a type name instead", name);
2924 // TODO: possible optimalization
2925 // Cache resolved constant result in FieldBuilder <-> expression map
2926 public virtual Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
2927 SimpleName original)
2931 // original == null || original.Resolve (...) ==> left
2934 if (left is TypeExpr) {
2935 left = left.ResolveAsTypeTerminal (ec, true);
2940 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
2948 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
2951 error176 (loc, GetSignatureForError ());
2955 InstanceExpression = left;
2960 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
2965 if (InstanceExpression == EmptyExpression.Null) {
2966 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
2970 if (InstanceExpression.Type.IsValueType) {
2971 if (InstanceExpression is IMemoryLocation) {
2972 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
2974 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
2975 InstanceExpression.Emit (ec);
2977 t.AddressOf (ec, AddressOp.Store);
2980 InstanceExpression.Emit (ec);
2982 if (prepare_for_load)
2983 ec.ig.Emit (OpCodes.Dup);
2988 /// Represents group of extension methods
2990 public class ExtensionMethodGroupExpr : MethodGroupExpr
2992 readonly NamespaceEntry namespaceEntry;
2993 public Expression ExtensionExpression;
2995 public ExtensionMethodGroupExpr (ArrayList list, NamespaceEntry n, Type extensionType, Location l)
2996 : base (list, extensionType, l)
2998 this.namespaceEntry = n;
3001 public override bool IsBase {
3002 get { return true; }
3005 public override bool IsStatic {
3006 get { return true; }
3009 public bool IsTopLevel {
3010 get { return namespaceEntry == null; }
3013 public override void EmitArguments (EmitContext ec, ArrayList arguments)
3015 if (arguments == null)
3016 arguments = new ArrayList (1);
3017 arguments.Insert (0, new Argument (ExtensionExpression));
3018 base.EmitArguments (ec, arguments);
3021 public override void EmitCall (EmitContext ec, ArrayList arguments)
3023 if (arguments == null)
3024 arguments = new ArrayList (1);
3025 arguments.Insert (0, new Argument (ExtensionExpression));
3026 base.EmitCall (ec, arguments);
3029 public override MethodGroupExpr OverloadResolve (EmitContext ec, ArrayList arguments, bool may_fail, Location loc)
3031 if ((ExtensionExpression.eclass & (ExprClass.Value | ExprClass.Variable)) == 0)
3032 return base.OverloadResolve (ec, arguments, may_fail, loc);
3034 if (arguments == null)
3035 arguments = new ArrayList (1);
3037 arguments.Insert (0, new Argument (ExtensionExpression));
3038 MethodGroupExpr mg = ResolveOverloadExtensions (ec, arguments, namespaceEntry, loc);
3040 // Restore original arguments
3041 arguments.RemoveAt (0);
3047 return base.OverloadResolve (ec, arguments, may_fail, loc);
3052 MethodGroupExpr ResolveOverloadExtensions (EmitContext ec, ArrayList arguments, NamespaceEntry ns, Location loc)
3054 // Use normal resolve rules
3055 MethodGroupExpr mg = base.OverloadResolve (ec, arguments, true, loc);
3063 ExtensionMethodGroupExpr e = ns.LookupExtensionMethod (type, null, Name);
3067 e.ExtensionExpression = ExtensionExpression;
3068 return e.ResolveOverloadExtensions (ec, arguments, e.namespaceEntry, loc);
3073 /// MethodGroupExpr represents a group of method candidates which
3074 /// can be resolved to the best method overload
3076 public class MethodGroupExpr : MemberExpr {
3077 public MethodBase [] Methods;
3078 MethodBase best_candidate;
3079 bool has_type_arguments;
3080 bool identical_type_name;
3083 public MethodGroupExpr (MemberInfo [] mi, Type type, Location l)
3085 Methods = new MethodBase [mi.Length];
3086 mi.CopyTo (Methods, 0);
3087 eclass = ExprClass.MethodGroup;
3092 public MethodGroupExpr (ArrayList list, Type type, Location l)
3095 Methods = (MethodBase[])list.ToArray (typeof (MethodBase));
3097 foreach (MemberInfo m in list){
3098 if (!(m is MethodBase)){
3099 Console.WriteLine ("Name " + m.Name);
3100 Console.WriteLine ("Found a: " + m.GetType ().FullName);
3107 eclass = ExprClass.MethodGroup;
3111 public override Type DeclaringType {
3114 // We assume that the top-level type is in the end
3116 return Methods [Methods.Length - 1].DeclaringType;
3117 //return Methods [0].DeclaringType;
3121 public bool HasTypeArguments {
3123 return has_type_arguments;
3127 public bool IdenticalTypeName {
3129 return identical_type_name;
3133 identical_type_name = value;
3137 public virtual bool IsBase {
3146 public override string GetSignatureForError ()
3148 if (best_candidate != null)
3149 return TypeManager.CSharpSignature (best_candidate);
3151 return TypeManager.CSharpSignature (Methods [0]);
3154 public override string Name {
3156 return Methods [0].Name;
3160 public override bool IsInstance {
3162 foreach (MethodBase mb in Methods)
3170 public override bool IsStatic {
3172 foreach (MethodBase mb in Methods)
3180 public static explicit operator ConstructorInfo (MethodGroupExpr mg)
3182 return (ConstructorInfo)mg.best_candidate;
3185 public static explicit operator MethodInfo (MethodGroupExpr mg)
3187 return (MethodInfo)mg.best_candidate;
3191 /// Determines "better conversion" as specified in 14.4.2.3
3193 /// Returns : p if a->p is better,
3194 /// q if a->q is better,
3195 /// null if neither is better
3197 static Type BetterConversion (EmitContext ec, Argument a, Type p, Type q)
3199 Type argument_type = TypeManager.TypeToCoreType (a.Type);
3200 Expression argument_expr = a.Expr;
3202 if (argument_type == null)
3203 throw new Exception ("Expression of type " + a.Expr +
3204 " does not resolve its type");
3206 if (p == null || q == null)
3207 throw new InternalErrorException ("BetterConversion Got a null conversion");
3212 if (argument_expr is NullLiteral)
3215 // If the argument is null and one of the types to compare is 'object' and
3216 // the other is a reference type, we prefer the other.
3218 // This follows from the usual rules:
3219 // * There is an implicit conversion from 'null' to type 'object'
3220 // * There is an implicit conversion from 'null' to any reference type
3221 // * There is an implicit conversion from any reference type to type 'object'
3222 // * There is no implicit conversion from type 'object' to other reference types
3223 // => Conversion of 'null' to a reference type is better than conversion to 'object'
3225 // FIXME: This probably isn't necessary, since the type of a NullLiteral is the
3226 // null type. I think it used to be 'object' and thus needed a special
3227 // case to avoid the immediately following two checks.
3229 if (!p.IsValueType && q == TypeManager.object_type)
3231 if (!q.IsValueType && p == TypeManager.object_type)
3235 if (argument_type == p)
3238 if (argument_type == q)
3241 Expression p_tmp = new EmptyExpression (p);
3242 Expression q_tmp = new EmptyExpression (q);
3244 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3245 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3247 if (p_to_q && !q_to_p)
3250 if (q_to_p && !p_to_q)
3253 if (p == TypeManager.sbyte_type)
3254 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3255 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3257 if (q == TypeManager.sbyte_type)
3258 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3259 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3262 if (p == TypeManager.short_type)
3263 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3264 q == TypeManager.uint64_type)
3266 if (q == TypeManager.short_type)
3267 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3268 p == TypeManager.uint64_type)
3271 if (p == TypeManager.int32_type)
3272 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3274 if (q == TypeManager.int32_type)
3275 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3278 if (p == TypeManager.int64_type)
3279 if (q == TypeManager.uint64_type)
3281 if (q == TypeManager.int64_type)
3282 if (p == TypeManager.uint64_type)
3289 /// Determines "Better function" between candidate
3290 /// and the current best match
3293 /// Returns a boolean indicating :
3294 /// false if candidate ain't better
3295 /// true if candidate is better than the current best match
3297 static bool BetterFunction (EmitContext ec, ArrayList args, int argument_count,
3298 MethodBase candidate, bool candidate_params,
3299 MethodBase best, bool best_params)
3301 ParameterData candidate_pd = TypeManager.GetParameterData (candidate);
3302 ParameterData best_pd = TypeManager.GetParameterData (best);
3304 bool better_at_least_one = false;
3306 for (int j = 0, c_idx = 0, b_idx = 0; j < argument_count; ++j, ++c_idx, ++b_idx)
3308 Argument a = (Argument) args [j];
3310 Type ct = TypeManager.TypeToCoreType (candidate_pd.ParameterType (c_idx));
3311 Type bt = TypeManager.TypeToCoreType (best_pd.ParameterType (b_idx));
3313 if (candidate_params && candidate_pd.ParameterModifier (c_idx) == Parameter.Modifier.PARAMS)
3315 ct = TypeManager.GetElementType (ct);
3319 if (best_params && best_pd.ParameterModifier (b_idx) == Parameter.Modifier.PARAMS)
3321 bt = TypeManager.GetElementType (bt);
3329 Type better = BetterConversion (ec, a, ct, bt);
3331 // for each argument, the conversion to 'ct' should be no worse than
3332 // the conversion to 'bt'.
3336 // for at least one argument, the conversion to 'ct' should be better than
3337 // the conversion to 'bt'.
3339 better_at_least_one = true;
3342 if (better_at_least_one)
3346 // This handles the case
3348 // Add (float f1, float f2, float f3);
3349 // Add (params decimal [] foo);
3351 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3352 // first candidate would've chosen as better.
3358 // The two methods have equal parameter types. Now apply tie-breaking rules
3360 if (TypeManager.IsGenericMethod (best) && !TypeManager.IsGenericMethod (candidate))
3362 if (!TypeManager.IsGenericMethod (best) && TypeManager.IsGenericMethod (candidate))
3366 // This handles the following cases:
3368 // Trim () is better than Trim (params char[] chars)
3369 // Concat (string s1, string s2, string s3) is better than
3370 // Concat (string s1, params string [] srest)
3371 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3373 if (!candidate_params && best_params)
3375 if (candidate_params && !best_params)
3378 int candidate_param_count = candidate_pd.Count;
3379 int best_param_count = best_pd.Count;
3381 if (candidate_param_count != best_param_count)
3382 // can only happen if (candidate_params && best_params)
3383 return candidate_param_count > best_param_count;
3386 // now, both methods have the same number of parameters, and the parameters have the same types
3387 // Pick the "more specific" signature
3390 MethodBase orig_candidate = TypeManager.DropGenericMethodArguments (candidate);
3391 MethodBase orig_best = TypeManager.DropGenericMethodArguments (best);
3393 ParameterData orig_candidate_pd = TypeManager.GetParameterData (orig_candidate);
3394 ParameterData orig_best_pd = TypeManager.GetParameterData (orig_best);
3396 bool specific_at_least_once = false;
3397 for (int j = 0; j < candidate_param_count; ++j)
3399 Type ct = TypeManager.TypeToCoreType (orig_candidate_pd.ParameterType (j));
3400 Type bt = TypeManager.TypeToCoreType (orig_best_pd.ParameterType (j));
3403 Type specific = MoreSpecific (ct, bt);
3407 specific_at_least_once = true;
3410 if (specific_at_least_once)
3413 // FIXME: handle lifted operators
3419 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3420 SimpleName original)
3422 if (!(left is TypeExpr) &&
3423 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3424 IdenticalTypeName = true;
3426 return base.ResolveMemberAccess (ec, left, loc, original);
3429 override public Expression DoResolve (EmitContext ec)
3431 if (InstanceExpression != null) {
3432 InstanceExpression = InstanceExpression.DoResolve (ec);
3433 if (InstanceExpression == null)
3440 public void ReportUsageError ()
3442 Report.Error (654, loc, "Method `" + DeclaringType + "." +
3443 Name + "()' is referenced without parentheses");
3446 override public void Emit (EmitContext ec)
3448 ReportUsageError ();
3451 public virtual void EmitArguments (EmitContext ec, ArrayList arguments)
3453 Invocation.EmitArguments (ec, best_candidate, arguments, false, null);
3456 public virtual void EmitCall (EmitContext ec, ArrayList arguments)
3458 Invocation.EmitCall (ec, IsBase, InstanceExpression, best_candidate, arguments, loc);
3461 public static bool IsAncestralType (Type first_type, Type second_type)
3463 return first_type != second_type &&
3464 (TypeManager.IsSubclassOf (second_type, first_type) ||
3465 TypeManager.ImplementsInterface (second_type, first_type));
3468 public static bool IsOverride (MethodBase cand_method, MethodBase base_method)
3470 if (!IsAncestralType (base_method.DeclaringType, cand_method.DeclaringType))
3473 ParameterData cand_pd = TypeManager.GetParameterData (cand_method);
3474 ParameterData base_pd = TypeManager.GetParameterData (base_method);
3476 if (cand_pd.Count != base_pd.Count)
3479 for (int j = 0; j < cand_pd.Count; ++j)
3481 Parameter.Modifier cm = cand_pd.ParameterModifier (j);
3482 Parameter.Modifier bm = base_pd.ParameterModifier (j);
3483 Type ct = TypeManager.TypeToCoreType (cand_pd.ParameterType (j));
3484 Type bt = TypeManager.TypeToCoreType (base_pd.ParameterType (j));
3486 if (cm != bm || ct != bt)
3493 public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2, Location loc)
3495 MemberInfo [] miset;
3496 MethodGroupExpr union;
3501 return (MethodGroupExpr) mg2;
3504 return (MethodGroupExpr) mg1;
3507 MethodGroupExpr left_set = null, right_set = null;
3508 int length1 = 0, length2 = 0;
3510 left_set = (MethodGroupExpr) mg1;
3511 length1 = left_set.Methods.Length;
3513 right_set = (MethodGroupExpr) mg2;
3514 length2 = right_set.Methods.Length;
3516 ArrayList common = new ArrayList ();
3518 foreach (MethodBase r in right_set.Methods){
3519 if (TypeManager.ArrayContainsMethod (left_set.Methods, r))
3523 miset = new MemberInfo [length1 + length2 - common.Count];
3524 left_set.Methods.CopyTo (miset, 0);
3528 foreach (MethodBase r in right_set.Methods) {
3529 if (!common.Contains (r))
3533 union = new MethodGroupExpr (miset, mg1.Type, loc);
3538 static Type MoreSpecific (Type p, Type q)
3540 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
3542 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
3545 if (TypeManager.HasElementType (p))
3547 Type pe = TypeManager.GetElementType (p);
3548 Type qe = TypeManager.GetElementType (q);
3549 Type specific = MoreSpecific (pe, qe);
3555 else if (TypeManager.IsGenericType (p))
3557 Type[] pargs = TypeManager.GetTypeArguments (p);
3558 Type[] qargs = TypeManager.GetTypeArguments (q);
3560 bool p_specific_at_least_once = false;
3561 bool q_specific_at_least_once = false;
3563 for (int i = 0; i < pargs.Length; i++)
3565 Type specific = MoreSpecific (pargs [i], qargs [i]);
3566 if (specific == pargs [i])
3567 p_specific_at_least_once = true;
3568 if (specific == qargs [i])
3569 q_specific_at_least_once = true;
3572 if (p_specific_at_least_once && !q_specific_at_least_once)
3574 if (!p_specific_at_least_once && q_specific_at_least_once)
3582 /// Find the Applicable Function Members (7.4.2.1)
3584 /// me: Method Group expression with the members to select.
3585 /// it might contain constructors or methods (or anything
3586 /// that maps to a method).
3588 /// Arguments: ArrayList containing resolved Argument objects.
3590 /// loc: The location if we want an error to be reported, or a Null
3591 /// location for "probing" purposes.
3593 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3594 /// that is the best match of me on Arguments.
3597 public virtual MethodGroupExpr OverloadResolve (EmitContext ec, ArrayList Arguments,
3598 bool may_fail, Location loc)
3600 bool method_params = false;
3601 Type applicable_type = null;
3603 ArrayList candidates = new ArrayList (2);
3604 ArrayList candidate_overrides = null;
3607 // Used to keep a map between the candidate
3608 // and whether it is being considered in its
3609 // normal or expanded form
3611 // false is normal form, true is expanded form
3613 Hashtable candidate_to_form = null;
3615 if (Arguments != null)
3616 arg_count = Arguments.Count;
3618 if (RootContext.Version == LanguageVersion.ISO_1 && Name == "Invoke" && TypeManager.IsDelegateType (DeclaringType)) {
3620 Report.Error (1533, loc, "Invoke cannot be called directly on a delegate");
3624 int nmethods = Methods.Length;
3628 // Methods marked 'override' don't take part in 'applicable_type'
3629 // computation, nor in the actual overload resolution.
3630 // However, they still need to be emitted instead of a base virtual method.
3631 // So, we salt them away into the 'candidate_overrides' array.
3633 // In case of reflected methods, we replace each overriding method with
3634 // its corresponding base virtual method. This is to improve compatibility
3635 // with non-C# libraries which change the visibility of overrides (#75636)
3638 for (int i = 0; i < Methods.Length; ++i) {
3639 MethodBase m = Methods [i];
3641 Type [] gen_args = null;
3642 if (m.IsGenericMethod && !m.IsGenericMethodDefinition)
3643 gen_args = m.GetGenericArguments ();
3645 if (TypeManager.IsOverride (m)) {
3646 if (candidate_overrides == null)
3647 candidate_overrides = new ArrayList ();
3648 candidate_overrides.Add (m);
3649 m = TypeManager.TryGetBaseDefinition (m);
3651 if (m != null && gen_args != null) {
3652 if (!m.IsGenericMethodDefinition)
3653 throw new InternalErrorException ("GetBaseDefinition didn't return a GenericMethodDefinition");
3654 m = ((MethodInfo) m).MakeGenericMethod (gen_args);
3664 int applicable_errors = Report.Errors;
3667 // First we construct the set of applicable methods
3669 bool is_sorted = true;
3670 for (int i = 0; i < nmethods; i++) {
3671 Type decl_type = Methods [i].DeclaringType;
3674 // If we have already found an applicable method
3675 // we eliminate all base types (Section 14.5.5.1)
3677 if (applicable_type != null && IsAncestralType (decl_type, applicable_type))
3681 // Check if candidate is applicable (section 14.4.2.1)
3682 // Is candidate applicable in normal form?
3684 bool is_applicable = Invocation.IsApplicable (ec, this, Arguments, arg_count, ref Methods [i]);
3686 if (!is_applicable && Invocation.IsParamsMethodApplicable (ec, this, Arguments, arg_count, ref Methods [i])) {
3687 MethodBase candidate = Methods [i];
3688 if (candidate_to_form == null)
3689 candidate_to_form = new PtrHashtable ();
3690 candidate_to_form [candidate] = candidate;
3691 // Candidate is applicable in expanded form
3692 is_applicable = true;
3698 candidates.Add (Methods [i]);
3700 if (applicable_type == null)
3701 applicable_type = decl_type;
3702 else if (applicable_type != decl_type) {
3704 if (IsAncestralType (applicable_type, decl_type))
3705 applicable_type = decl_type;
3709 if (applicable_errors != Report.Errors)
3712 int candidate_top = candidates.Count;
3714 if (applicable_type == null) {
3715 if (ec.IsInProbingMode)
3719 // Okay so we have failed to find anything so we
3720 // return by providing info about the closest match
3722 int errors = Report.Errors;
3723 for (int i = 0; i < nmethods; ++i) {
3724 MethodBase c = Methods [i];
3725 ParameterData pd = TypeManager.GetParameterData (c);
3727 if (pd.Count != arg_count)
3731 if (!TypeManager.InferTypeArguments (ec, Arguments, ref c))
3733 if (TypeManager.IsGenericMethodDefinition (c))
3737 Invocation.VerifyArgumentsCompat (ec, Arguments, arg_count,
3738 c, false, null, may_fail, loc);
3740 if (!may_fail && errors == Report.Errors){
3742 throw new InternalErrorException (
3743 "VerifyArgumentsCompat and IsApplicable do not agree; " +
3744 "likely reason: ImplicitConversion and ImplicitConversionExists have gone out of sync");
3750 if (!may_fail && errors == Report.Errors) {
3751 string report_name = Name;
3752 if (report_name == ".ctor")
3753 report_name = TypeManager.CSharpName (DeclaringType);
3759 for (int i = 0; i < Methods.Length; ++i) {
3760 MethodBase c = Methods [i];
3761 ParameterData pd = TypeManager.GetParameterData (c);
3763 if (pd.Count != arg_count)
3766 if (TypeManager.InferTypeArguments (ec, Arguments, ref c))
3770 411, loc, "The type arguments for " +
3771 "method `{0}' cannot be inferred from " +
3772 "the usage. Try specifying the type " +
3773 "arguments explicitly", TypeManager.CSharpSignature (c));
3778 if (Name == ConstructorInfo.ConstructorName) {
3779 if (almostMatchedMembers.Count != 0) {
3780 Error_MemberLookupFailed (ec.ContainerType, type, type, ".ctor",
3781 null, MemberTypes.Constructor, AllBindingFlags);
3783 Report.SymbolRelatedToPreviousError (type);
3784 Report.Error (1729, loc,
3785 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
3786 TypeManager.CSharpName (type), arg_count);
3789 Invocation.Error_WrongNumArguments (loc, report_name, arg_count);
3798 // At this point, applicable_type is _one_ of the most derived types
3799 // in the set of types containing the methods in this MethodGroup.
3800 // Filter the candidates so that they only contain methods from the
3801 // most derived types.
3804 int finalized = 0; // Number of finalized candidates
3807 // Invariant: applicable_type is a most derived type
3809 // We'll try to complete Section 14.5.5.1 for 'applicable_type' by
3810 // eliminating all it's base types. At the same time, we'll also move
3811 // every unrelated type to the end of the array, and pick the next
3812 // 'applicable_type'.
3814 Type next_applicable_type = null;
3815 int j = finalized; // where to put the next finalized candidate
3816 int k = finalized; // where to put the next undiscarded candidate
3817 for (int i = finalized; i < candidate_top; ++i) {
3818 MethodBase candidate = (MethodBase) candidates [i];
3819 Type decl_type = candidate.DeclaringType;
3821 if (decl_type == applicable_type) {
3822 candidates [k++] = candidates [j];
3823 candidates [j++] = candidates [i];
3827 if (IsAncestralType (decl_type, applicable_type))
3830 if (next_applicable_type != null &&
3831 IsAncestralType (decl_type, next_applicable_type))
3834 candidates [k++] = candidates [i];
3836 if (next_applicable_type == null ||
3837 IsAncestralType (next_applicable_type, decl_type))
3838 next_applicable_type = decl_type;
3841 applicable_type = next_applicable_type;
3844 } while (applicable_type != null);
3848 // Now we actually find the best method
3851 best_candidate = (MethodBase) candidates [0];
3852 method_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
3853 for (int ix = 1; ix < candidate_top; ix++) {
3854 MethodBase candidate = (MethodBase) candidates [ix];
3856 if (candidate == best_candidate)
3859 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
3861 if (BetterFunction (ec, Arguments, arg_count,
3862 candidate, cand_params,
3863 best_candidate, method_params)) {
3864 best_candidate = candidate;
3865 method_params = cand_params;
3869 // Now check that there are no ambiguities i.e the selected method
3870 // should be better than all the others
3872 MethodBase ambiguous = null;
3873 for (int ix = 0; ix < candidate_top; ix++) {
3874 MethodBase candidate = (MethodBase) candidates [ix];
3876 if (candidate == best_candidate)
3879 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
3880 if (!BetterFunction (ec, Arguments, arg_count,
3881 best_candidate, method_params,
3882 candidate, cand_params))
3885 Report.SymbolRelatedToPreviousError (candidate);
3886 ambiguous = candidate;
3890 if (ambiguous != null) {
3891 Report.SymbolRelatedToPreviousError (best_candidate);
3892 Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
3893 TypeManager.CSharpSignature (ambiguous), TypeManager.CSharpSignature (best_candidate));
3898 // If the method is a virtual function, pick an override closer to the LHS type.
3900 if (!IsBase && best_candidate.IsVirtual) {
3901 if (TypeManager.IsOverride (best_candidate))
3902 throw new InternalErrorException (
3903 "Should not happen. An 'override' method took part in overload resolution: " + best_candidate);
3905 if (candidate_overrides != null)
3906 foreach (MethodBase candidate in candidate_overrides) {
3907 if (IsOverride (candidate, best_candidate))
3908 best_candidate = candidate;
3912 // We can stop here when probing is on
3913 if (ec.IsInProbingMode)
3917 // And now check if the arguments are all
3918 // compatible, perform conversions if
3919 // necessary etc. and return if everything is
3922 if (!Invocation.VerifyArgumentsCompat (ec, Arguments, arg_count, best_candidate,
3923 method_params, null, may_fail, loc))
3926 if (best_candidate == null)
3929 MethodBase the_method = TypeManager.DropGenericMethodArguments (best_candidate);
3931 if (the_method.IsGenericMethodDefinition &&
3932 !ConstraintChecker.CheckConstraints (ec, the_method, best_candidate, loc))
3936 IMethodData data = TypeManager.GetMethod (the_method);
3938 data.SetMemberIsUsed ();
3943 public Expression ResolveGeneric (EmitContext ec, TypeArguments args)
3946 if (!args.Resolve (ec))
3949 Type[] atypes = args.Arguments;
3951 int first_count = 0;
3952 MethodInfo first = null;
3954 ArrayList list = new ArrayList ();
3955 foreach (MethodBase mb in Methods) {
3956 MethodInfo mi = mb as MethodInfo;
3957 if ((mi == null) || !mb.IsGenericMethod)
3960 Type[] gen_params = mb.GetGenericArguments ();
3962 if (first == null) {
3964 first_count = gen_params.Length;
3967 if (gen_params.Length != atypes.Length)
3970 mi = mi.MakeGenericMethod (atypes);
3974 // MS implementation throws NotSupportedException for GetParameters
3975 // on unbaked generic method
3976 Parameters p = TypeManager.GetParameterData (mi) as Parameters;
3979 p.InflateTypes (gen_params, atypes);
3980 TypeManager.RegisterMethod (mi, p);
3985 if (list.Count > 0) {
3986 this.Methods = (MethodBase []) list.ToArray (typeof (MethodBase));
3987 has_type_arguments = true;
3991 if (first != null) {
3992 Report.SymbolRelatedToPreviousError (first);
3994 305, loc, "Using the generic method `{0}' requires `{1}' type arguments",
3995 TypeManager.CSharpSignature (first), first_count.ToString ());
3998 308, loc, "The non-generic method `{0}' " +
3999 "cannot be used with type arguments", Name);
4003 throw new NotImplementedException ();
4009 /// Fully resolved expression that evaluates to a Field
4011 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariable {
4012 public readonly FieldInfo FieldInfo;
4013 VariableInfo variable_info;
4015 LocalTemporary temp;
4017 bool in_initializer;
4019 public FieldExpr (FieldInfo fi, Location l, bool in_initializer):
4022 this.in_initializer = in_initializer;
4025 public FieldExpr (FieldInfo fi, Location l)
4028 eclass = ExprClass.Variable;
4029 type = TypeManager.TypeToCoreType (fi.FieldType);
4033 public override string Name {
4035 return FieldInfo.Name;
4039 public override bool IsInstance {
4041 return !FieldInfo.IsStatic;
4045 public override bool IsStatic {
4047 return FieldInfo.IsStatic;
4051 public override Type DeclaringType {
4053 return FieldInfo.DeclaringType;
4057 public override string GetSignatureForError ()
4059 return TypeManager.GetFullNameSignature (FieldInfo);
4062 public VariableInfo VariableInfo {
4064 return variable_info;
4068 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
4069 SimpleName original)
4071 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
4073 Type t = fi.FieldType;
4075 if (fi.IsLiteral || (fi.IsInitOnly && t == TypeManager.decimal_type)) {
4076 IConstant ic = TypeManager.GetConstant (fi);
4079 ic = new ExternalConstant (fi);
4081 ic = ExternalConstant.CreateDecimal (fi);
4083 return base.ResolveMemberAccess (ec, left, loc, original);
4086 TypeManager.RegisterConstant (fi, ic);
4089 bool left_is_type = left is TypeExpr;
4090 if (!left_is_type && (original == null || !original.IdenticalNameAndTypeName (ec, left, loc))) {
4091 Report.SymbolRelatedToPreviousError (FieldInfo);
4092 error176 (loc, TypeManager.GetFullNameSignature (FieldInfo));
4096 if (ic.ResolveValue ()) {
4097 if (!ec.IsInObsoleteScope)
4098 ic.CheckObsoleteness (loc);
4101 return ic.CreateConstantReference (loc);
4104 if (t.IsPointer && !ec.InUnsafe) {
4108 return base.ResolveMemberAccess (ec, left, loc, original);
4111 override public Expression DoResolve (EmitContext ec)
4113 return DoResolve (ec, false, false);
4116 Expression DoResolve (EmitContext ec, bool lvalue_instance, bool out_access)
4118 if (!FieldInfo.IsStatic){
4119 if (InstanceExpression == null){
4121 // This can happen when referencing an instance field using
4122 // a fully qualified type expression: TypeName.InstanceField = xxx
4124 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4128 // Resolve the field's instance expression while flow analysis is turned
4129 // off: when accessing a field "a.b", we must check whether the field
4130 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4132 if (lvalue_instance) {
4133 using (ec.With (EmitContext.Flags.DoFlowAnalysis, false)) {
4134 Expression right_side =
4135 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4136 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side, loc);
4139 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
4140 InstanceExpression = InstanceExpression.Resolve (ec, rf);
4143 if (InstanceExpression == null)
4146 InstanceExpression.CheckMarshalByRefAccess ();
4149 if (!in_initializer && !ec.IsInFieldInitializer) {
4150 ObsoleteAttribute oa;
4151 FieldBase f = TypeManager.GetField (FieldInfo);
4153 if (!ec.IsInObsoleteScope)
4154 f.CheckObsoleteness (loc);
4156 // To be sure that type is external because we do not register generated fields
4157 } else if (!(FieldInfo.DeclaringType is TypeBuilder)) {
4158 oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
4160 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
4164 AnonymousContainer am = ec.CurrentAnonymousMethod;
4166 if (!FieldInfo.IsStatic){
4167 if (!am.IsIterator && (ec.TypeContainer is Struct)){
4168 Report.Error (1673, loc,
4169 "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",
4176 IFixedBuffer fb = AttributeTester.GetFixedBuffer (FieldInfo);
4178 if (!ec.InFixedInitializer && ec.ContainerType.IsValueType) {
4179 Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4182 if (!(InstanceExpression is LocalVariableReference) &&
4183 !(InstanceExpression is This)) {
4184 Report.SymbolRelatedToPreviousError (FieldInfo);
4185 Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4186 TypeManager.GetFullNameSignature (FieldInfo));
4189 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4192 // If the instance expression is a local variable or parameter.
4193 IVariable var = InstanceExpression as IVariable;
4194 if ((var == null) || (var.VariableInfo == null))
4197 VariableInfo vi = var.VariableInfo;
4198 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
4201 variable_info = vi.GetSubStruct (FieldInfo.Name);
4205 static readonly int [] codes = {
4206 191, // instance, write access
4207 192, // instance, out access
4208 198, // static, write access
4209 199, // static, out access
4210 1648, // member of value instance, write access
4211 1649, // member of value instance, out access
4212 1650, // member of value static, write access
4213 1651 // member of value static, out access
4216 static readonly string [] msgs = {
4217 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4218 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4219 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4220 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4221 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4222 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4223 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4224 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4227 // The return value is always null. Returning a value simplifies calling code.
4228 Expression Report_AssignToReadonly (Expression right_side)
4231 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4235 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4237 Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4242 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4244 IVariable var = InstanceExpression as IVariable;
4245 if ((var != null) && (var.VariableInfo != null))
4246 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
4248 bool lvalue_instance = !FieldInfo.IsStatic && FieldInfo.DeclaringType.IsValueType;
4249 bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
4251 Expression e = DoResolve (ec, lvalue_instance, out_access);
4256 FieldBase fb = TypeManager.GetField (FieldInfo);
4260 if (FieldInfo.IsInitOnly) {
4261 // InitOnly fields can only be assigned in constructors or initializers
4262 if (!ec.IsInFieldInitializer && !ec.IsConstructor)
4263 return Report_AssignToReadonly (right_side);
4265 if (ec.IsConstructor) {
4266 Type ctype = ec.TypeContainer.CurrentType;
4268 ctype = ec.ContainerType;
4270 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4271 if (!TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
4272 return Report_AssignToReadonly (right_side);
4273 // static InitOnly fields cannot be assigned-to in an instance constructor
4274 if (IsStatic && !ec.IsStatic)
4275 return Report_AssignToReadonly (right_side);
4276 // instance constructors can't modify InitOnly fields of other instances of the same type
4277 if (!IsStatic && !(InstanceExpression is This))
4278 return Report_AssignToReadonly (right_side);
4282 if (right_side == EmptyExpression.OutAccess &&
4283 !IsStatic && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
4284 Report.SymbolRelatedToPreviousError (DeclaringType);
4285 Report.Warning (197, 1, loc,
4286 "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",
4287 GetSignatureForError ());
4293 public override void CheckMarshalByRefAccess ()
4295 if (!IsStatic && Type.IsValueType && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
4296 Report.SymbolRelatedToPreviousError (DeclaringType);
4297 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",
4298 GetSignatureForError ());
4302 public bool VerifyFixed ()
4304 IVariable variable = InstanceExpression as IVariable;
4305 // A variable of the form V.I is fixed when V is a fixed variable of a struct type.
4306 // We defer the InstanceExpression check after the variable check to avoid a
4307 // separate null check on InstanceExpression.
4308 return variable != null && InstanceExpression.Type.IsValueType && variable.VerifyFixed ();
4311 public override int GetHashCode ()
4313 return FieldInfo.GetHashCode ();
4316 public override bool Equals (object obj)
4318 FieldExpr fe = obj as FieldExpr;
4322 if (FieldInfo != fe.FieldInfo)
4325 if (InstanceExpression == null || fe.InstanceExpression == null)
4328 return InstanceExpression.Equals (fe.InstanceExpression);
4331 public void Emit (EmitContext ec, bool leave_copy)
4333 ILGenerator ig = ec.ig;
4334 bool is_volatile = false;
4336 FieldBase f = TypeManager.GetField (FieldInfo);
4338 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4341 f.SetMemberIsUsed ();
4344 if (FieldInfo.IsStatic){
4346 ig.Emit (OpCodes.Volatile);
4348 ig.Emit (OpCodes.Ldsfld, FieldInfo);
4351 EmitInstance (ec, false);
4353 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
4355 ig.Emit (OpCodes.Ldflda, FieldInfo);
4356 ig.Emit (OpCodes.Ldflda, ff.Element);
4359 ig.Emit (OpCodes.Volatile);
4361 ig.Emit (OpCodes.Ldfld, FieldInfo);
4366 ec.ig.Emit (OpCodes.Dup);
4367 if (!FieldInfo.IsStatic) {
4368 temp = new LocalTemporary (this.Type);
4374 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4376 FieldAttributes fa = FieldInfo.Attributes;
4377 bool is_static = (fa & FieldAttributes.Static) != 0;
4378 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
4379 ILGenerator ig = ec.ig;
4380 prepared = prepare_for_load;
4382 if (is_readonly && !ec.IsConstructor){
4383 Report_AssignToReadonly (source);
4387 EmitInstance (ec, prepare_for_load);
4391 ec.ig.Emit (OpCodes.Dup);
4392 if (!FieldInfo.IsStatic) {
4393 temp = new LocalTemporary (this.Type);
4398 FieldBase f = TypeManager.GetField (FieldInfo);
4400 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4401 ig.Emit (OpCodes.Volatile);
4407 ig.Emit (OpCodes.Stsfld, FieldInfo);
4409 ig.Emit (OpCodes.Stfld, FieldInfo);
4417 public override void Emit (EmitContext ec)
4422 public void AddressOf (EmitContext ec, AddressOp mode)
4424 ILGenerator ig = ec.ig;
4426 FieldBase f = TypeManager.GetField (FieldInfo);
4428 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
4429 Report.Warning (420, 1, loc, "`{0}': A volatile field references will not be treated as volatile",
4430 f.GetSignatureForError ());
4433 if ((mode & AddressOp.Store) != 0)
4435 if ((mode & AddressOp.Load) != 0)
4436 f.SetMemberIsUsed ();
4440 // Handle initonly fields specially: make a copy and then
4441 // get the address of the copy.
4444 if (FieldInfo.IsInitOnly){
4446 if (ec.IsConstructor){
4447 if (FieldInfo.IsStatic){
4459 local = ig.DeclareLocal (type);
4460 ig.Emit (OpCodes.Stloc, local);
4461 ig.Emit (OpCodes.Ldloca, local);
4466 if (FieldInfo.IsStatic){
4467 ig.Emit (OpCodes.Ldsflda, FieldInfo);
4470 EmitInstance (ec, false);
4471 ig.Emit (OpCodes.Ldflda, FieldInfo);
4477 // A FieldExpr whose address can not be taken
4479 public class FieldExprNoAddress : FieldExpr, IMemoryLocation {
4480 public FieldExprNoAddress (FieldInfo fi, Location loc) : base (fi, loc)
4484 public new void AddressOf (EmitContext ec, AddressOp mode)
4486 Report.Error (-215, "Report this: Taking the address of a remapped parameter not supported");
4491 /// Expression that evaluates to a Property. The Assign class
4492 /// might set the `Value' expression if we are in an assignment.
4494 /// This is not an LValue because we need to re-write the expression, we
4495 /// can not take data from the stack and store it.
4497 public class PropertyExpr : MemberExpr, IAssignMethod {
4498 public readonly PropertyInfo PropertyInfo;
4501 // This is set externally by the `BaseAccess' class
4504 MethodInfo getter, setter;
4509 LocalTemporary temp;
4512 public PropertyExpr (Type containerType, PropertyInfo pi, Location l)
4515 eclass = ExprClass.PropertyAccess;
4519 type = TypeManager.TypeToCoreType (pi.PropertyType);
4521 ResolveAccessors (containerType);
4524 public override string Name {
4526 return PropertyInfo.Name;
4530 public override bool IsInstance {
4536 public override bool IsStatic {
4542 public override Type DeclaringType {
4544 return PropertyInfo.DeclaringType;
4548 public override string GetSignatureForError ()
4550 return TypeManager.GetFullNameSignature (PropertyInfo);
4553 void FindAccessors (Type invocation_type)
4555 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
4556 BindingFlags.Static | BindingFlags.Instance |
4557 BindingFlags.DeclaredOnly;
4559 Type current = PropertyInfo.DeclaringType;
4560 for (; current != null; current = current.BaseType) {
4561 MemberInfo[] group = TypeManager.MemberLookup (
4562 invocation_type, invocation_type, current,
4563 MemberTypes.Property, flags, PropertyInfo.Name, null);
4568 if (group.Length != 1)
4569 // Oooops, can this ever happen ?
4572 PropertyInfo pi = (PropertyInfo) group [0];
4575 getter = pi.GetGetMethod (true);
4578 setter = pi.GetSetMethod (true);
4580 MethodInfo accessor = getter != null ? getter : setter;
4582 if (!accessor.IsVirtual)
4588 // We also perform the permission checking here, as the PropertyInfo does not
4589 // hold the information for the accessibility of its setter/getter
4591 // TODO: Refactor to use some kind of cache together with GetPropertyFromAccessor
4592 void ResolveAccessors (Type containerType)
4594 FindAccessors (containerType);
4596 if (getter != null) {
4597 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
4598 IMethodData md = TypeManager.GetMethod (the_getter);
4600 md.SetMemberIsUsed ();
4602 is_static = getter.IsStatic;
4605 if (setter != null) {
4606 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
4607 IMethodData md = TypeManager.GetMethod (the_setter);
4609 md.SetMemberIsUsed ();
4611 is_static = setter.IsStatic;
4615 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
4618 InstanceExpression = null;
4622 if (InstanceExpression == null) {
4623 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4627 InstanceExpression = InstanceExpression.DoResolve (ec);
4628 if (lvalue_instance && InstanceExpression != null)
4629 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
4631 if (InstanceExpression == null)
4634 InstanceExpression.CheckMarshalByRefAccess ();
4636 if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) &&
4637 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
4638 !TypeManager.IsNestedChildOf (ec.ContainerType, InstanceExpression.Type) &&
4639 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.ContainerType)) {
4640 Report.SymbolRelatedToPreviousError (PropertyInfo);
4641 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
4648 void Error_PropertyNotFound (MethodInfo mi, bool getter)
4650 // TODO: correctly we should compare arguments but it will lead to bigger changes
4651 if (mi is MethodBuilder) {
4652 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
4656 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
4658 ParameterData iparams = TypeManager.GetParameterData (mi);
4659 sig.Append (getter ? "get_" : "set_");
4661 sig.Append (iparams.GetSignatureForError ());
4663 Report.SymbolRelatedToPreviousError (mi);
4664 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
4665 Name, sig.ToString ());
4668 override public Expression DoResolve (EmitContext ec)
4673 if (getter != null){
4674 if (TypeManager.GetParameterData (getter).Count != 0){
4675 Error_PropertyNotFound (getter, true);
4680 if (getter == null){
4682 // The following condition happens if the PropertyExpr was
4683 // created, but is invalid (ie, the property is inaccessible),
4684 // and we did not want to embed the knowledge about this in
4685 // the caller routine. This only avoids double error reporting.
4690 if (InstanceExpression != EmptyExpression.Null) {
4691 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
4692 TypeManager.GetFullNameSignature (PropertyInfo));
4697 bool must_do_cs1540_check = false;
4698 if (getter != null &&
4699 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
4700 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
4701 if (pm != null && pm.HasCustomAccessModifier) {
4702 Report.SymbolRelatedToPreviousError (pm);
4703 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
4704 TypeManager.CSharpSignature (getter));
4707 Report.SymbolRelatedToPreviousError (getter);
4708 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
4713 if (!InstanceResolve (ec, false, must_do_cs1540_check))
4717 // Only base will allow this invocation to happen.
4719 if (IsBase && getter.IsAbstract) {
4720 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
4724 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
4734 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4736 if (right_side == EmptyExpression.OutAccess) {
4737 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
4738 GetSignatureForError ());
4742 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
4743 Report.Error (1612, loc, "Cannot modify the return value of `{0}' because it is not a variable",
4744 GetSignatureForError ());
4748 if (setter == null){
4750 // The following condition happens if the PropertyExpr was
4751 // created, but is invalid (ie, the property is inaccessible),
4752 // and we did not want to embed the knowledge about this in
4753 // the caller routine. This only avoids double error reporting.
4757 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
4758 GetSignatureForError ());
4762 if (TypeManager.GetParameterData (setter).Count != 1){
4763 Error_PropertyNotFound (setter, false);
4767 bool must_do_cs1540_check;
4768 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
4769 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
4770 if (pm != null && pm.HasCustomAccessModifier) {
4771 Report.SymbolRelatedToPreviousError (pm);
4772 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
4773 TypeManager.CSharpSignature (setter));
4776 Report.SymbolRelatedToPreviousError (setter);
4777 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
4782 if (!InstanceResolve (ec, PropertyInfo.DeclaringType.IsValueType, must_do_cs1540_check))
4786 // Only base will allow this invocation to happen.
4788 if (IsBase && setter.IsAbstract){
4789 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
4796 public override void Emit (EmitContext ec)
4801 public void Emit (EmitContext ec, bool leave_copy)
4804 // Special case: length of single dimension array property is turned into ldlen
4806 if ((getter == TypeManager.system_int_array_get_length) ||
4807 (getter == TypeManager.int_array_get_length)){
4808 Type iet = InstanceExpression.Type;
4811 // System.Array.Length can be called, but the Type does not
4812 // support invoking GetArrayRank, so test for that case first
4814 if (iet != TypeManager.array_type && (iet.GetArrayRank () == 1)) {
4816 EmitInstance (ec, false);
4817 ec.ig.Emit (OpCodes.Ldlen);
4818 ec.ig.Emit (OpCodes.Conv_I4);
4823 Invocation.EmitCall (ec, IsBase, InstanceExpression, getter, null, loc, prepared, false);
4826 ec.ig.Emit (OpCodes.Dup);
4828 temp = new LocalTemporary (this.Type);
4835 // Implements the IAssignMethod interface for assignments
4837 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4839 Expression my_source = source;
4841 prepared = prepare_for_load;
4846 ec.ig.Emit (OpCodes.Dup);
4848 temp = new LocalTemporary (this.Type);
4852 } else if (leave_copy) {
4854 temp = new LocalTemporary (this.Type);
4859 ArrayList args = new ArrayList (1);
4860 args.Add (new Argument (my_source, Argument.AType.Expression));
4862 Invocation.EmitCall (ec, IsBase, InstanceExpression, setter, args, loc, false, prepared);
4872 /// Fully resolved expression that evaluates to an Event
4874 public class EventExpr : MemberExpr {
4875 public readonly EventInfo EventInfo;
4879 MethodInfo add_accessor, remove_accessor;
4881 public EventExpr (EventInfo ei, Location loc)
4885 eclass = ExprClass.EventAccess;
4887 add_accessor = TypeManager.GetAddMethod (ei);
4888 remove_accessor = TypeManager.GetRemoveMethod (ei);
4889 if (add_accessor.IsStatic || remove_accessor.IsStatic)
4892 if (EventInfo is MyEventBuilder){
4893 MyEventBuilder eb = (MyEventBuilder) EventInfo;
4894 type = eb.EventType;
4897 type = EventInfo.EventHandlerType;
4900 public override string Name {
4902 return EventInfo.Name;
4906 public override bool IsInstance {
4912 public override bool IsStatic {
4918 public override Type DeclaringType {
4920 return EventInfo.DeclaringType;
4924 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
4925 SimpleName original)
4928 // If the event is local to this class, we transform ourselves into a FieldExpr
4931 if (EventInfo.DeclaringType == ec.ContainerType ||
4932 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
4933 EventField mi = TypeManager.GetEventField (EventInfo);
4936 if (!ec.IsInObsoleteScope)
4937 mi.CheckObsoleteness (loc);
4939 FieldExpr ml = new FieldExpr (mi.FieldBuilder, loc);
4941 InstanceExpression = null;
4943 return ml.ResolveMemberAccess (ec, left, loc, original);
4947 return base.ResolveMemberAccess (ec, left, loc, original);
4951 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
4954 InstanceExpression = null;
4958 if (InstanceExpression == null) {
4959 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4963 InstanceExpression = InstanceExpression.DoResolve (ec);
4964 if (InstanceExpression == null)
4967 if (IsBase && add_accessor.IsAbstract) {
4968 Error_CannotCallAbstractBase(TypeManager.CSharpSignature(add_accessor));
4973 // This is using the same mechanism as the CS1540 check in PropertyExpr.
4974 // However, in the Event case, we reported a CS0122 instead.
4976 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
4977 InstanceExpression.Type != ec.ContainerType &&
4978 ec.ContainerType.IsSubclassOf (InstanceExpression.Type)) {
4979 Report.SymbolRelatedToPreviousError (EventInfo);
4980 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
4987 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
4989 return DoResolve (ec);
4992 public override Expression DoResolve (EmitContext ec)
4994 bool must_do_cs1540_check;
4995 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
4996 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
4997 Report.SymbolRelatedToPreviousError (EventInfo);
4998 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5002 if (!InstanceResolve (ec, must_do_cs1540_check))
5008 public override void Emit (EmitContext ec)
5010 if (InstanceExpression is This)
5011 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of += or -=", GetSignatureForError ());
5013 Report.Error (70, loc, "The event `{0}' can only appear on the left hand side of += or -= "+
5014 "(except on the defining type)", Name);
5017 public override string GetSignatureForError ()
5019 return TypeManager.CSharpSignature (EventInfo);
5022 public void EmitAddOrRemove (EmitContext ec, Expression source)
5024 BinaryDelegate source_del = source as BinaryDelegate;
5025 if (source_del == null) {
5029 Expression handler = source_del.Right;
5031 Argument arg = new Argument (handler, Argument.AType.Expression);
5032 ArrayList args = new ArrayList ();
5036 if (source_del.IsAddition)
5037 Invocation.EmitCall (
5038 ec, IsBase, InstanceExpression, add_accessor, args, loc);
5040 Invocation.EmitCall (
5041 ec, IsBase, InstanceExpression, remove_accessor, args, loc);
5045 public class TemporaryVariable : Expression, IMemoryLocation
5050 public TemporaryVariable (Type type, Location loc)
5054 eclass = ExprClass.Value;
5057 public override Expression DoResolve (EmitContext ec)
5062 TypeExpr te = new TypeExpression (type, loc);
5063 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
5064 if (!li.Resolve (ec))
5067 if (ec.MustCaptureVariable (li)) {
5068 ScopeInfo scope = li.Block.CreateScopeInfo ();
5069 var = scope.AddLocal (li);
5076 public Variable Variable {
5077 get { return var != null ? var : li.Variable; }
5080 public override void Emit (EmitContext ec)
5082 Variable.EmitInstance (ec);
5086 public void EmitLoadAddress (EmitContext ec)
5088 Variable.EmitInstance (ec);
5089 Variable.EmitAddressOf (ec);
5092 public void Store (EmitContext ec, Expression right_side)
5094 Variable.EmitInstance (ec);
5095 right_side.Emit (ec);
5096 Variable.EmitAssign (ec);
5099 public void EmitThis (EmitContext ec)
5101 Variable.EmitInstance (ec);
5104 public void EmitStore (EmitContext ec)
5106 Variable.EmitAssign (ec);
5109 public void AddressOf (EmitContext ec, AddressOp mode)
5111 EmitLoadAddress (ec);
5116 /// Handles `var' contextual keyword; var becomes a keyword only
5117 /// if no type called var exists in a variable scope
5119 public class VarExpr : SimpleName
5121 // Used for error reporting only
5122 ArrayList initializer;
5124 public VarExpr (string name, Location loc)
5129 public ArrayList VariableInitializer {
5131 this.initializer = value;
5135 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5138 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
5140 type = right_side.Type;
5141 if (type == TypeManager.null_type || type == TypeManager.void_type || type == TypeManager.anonymous_method_type) {
5142 Report.Error (815, loc, "An implicitly typed local variable declaration cannot be initialized with `{0}'",
5143 right_side.GetSignatureForError ());
5147 eclass = ExprClass.Variable;
5151 protected override void Error_TypeOrNamespaceNotFound (IResolveContext ec)
5153 if (ec is FieldBase) {
5154 Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");
5158 base.Error_TypeOrNamespaceNotFound (ec);
5161 public override TypeExpr ResolveAsContextualType (IResolveContext rc, bool silent)
5163 TypeExpr te = base.ResolveAsContextualType (rc, true);
5167 if (initializer == null)
5170 // TODO: refactor, the error is reported too many times
5171 if (initializer.Count > 1) {
5172 Location loc = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [1]).Location;
5173 Report.Error (819, loc, "An implicitly typed local variable declaration cannot include multiple declarators");
5177 Expression variable_initializer = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [0]).expression_or_array_initializer;
5178 if (variable_initializer == null) {
5179 Report.Error (818, loc, "An implicitly typed local variable declarator must include an initializer");