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 GetSignatureForError (), 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, loc);
699 if (mi [0] is MethodBase)
700 return new MethodGroupExpr (mi, 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 public static Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
746 Type queried_type, string name, Location loc)
748 return MemberLookupFinal (ec, qualifier_type, queried_type, name,
749 AllMemberTypes, AllBindingFlags, loc);
752 public static Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
753 Type queried_type, string name,
754 MemberTypes mt, BindingFlags bf,
759 int errors = Report.Errors;
761 e = MemberLookup (ec.ContainerType, qualifier_type, queried_type, name, mt, bf, loc);
763 if (e == null && errors == Report.Errors)
764 // No errors were reported by MemberLookup, but there was an error.
765 MemberLookupFailed (ec.ContainerType, qualifier_type, queried_type, name, null, true, loc);
770 public static void MemberLookupFailed (Type container_type, Type qualifier_type,
771 Type queried_type, string name,
772 string class_name, bool complain_if_none_found,
775 if (almostMatchedMembers.Count != 0) {
776 for (int i = 0; i < almostMatchedMembers.Count; ++i) {
777 MemberInfo m = (MemberInfo) almostMatchedMembers [i];
778 for (int j = 0; j < i; ++j) {
779 if (m == almostMatchedMembers [j]) {
787 Type declaring_type = m.DeclaringType;
789 Report.SymbolRelatedToPreviousError (m);
790 if (qualifier_type == null) {
791 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
792 TypeManager.CSharpName (m.DeclaringType),
793 TypeManager.CSharpName (container_type));
795 } else if (qualifier_type != container_type &&
796 TypeManager.IsNestedFamilyAccessible (container_type, declaring_type)) {
797 // Although a derived class can access protected members of
798 // its base class it cannot do so through an instance of the
799 // base class (CS1540). If the qualifier_type is a base of the
800 // ec.ContainerType and the lookup succeeds with the latter one,
801 // then we are in this situation.
802 Error_CannotAccessProtected (loc, m, qualifier_type, container_type);
804 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (m));
807 almostMatchedMembers.Clear ();
811 MemberInfo[] lookup = null;
812 if (queried_type == null) {
813 class_name = "global::";
815 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
816 AllMemberTypes, AllBindingFlags |
817 BindingFlags.NonPublic, name, null);
820 if (lookup == null) {
821 if (!complain_if_none_found)
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);
832 if (TypeManager.MemberLookup (queried_type, null, queried_type,
833 AllMemberTypes, AllBindingFlags |
834 BindingFlags.NonPublic, name, null) == null) {
835 if ((lookup.Length == 1) && (lookup [0] is Type)) {
836 Type t = (Type) lookup [0];
838 Report.Error (305, loc,
839 "Using the generic type `{0}' " +
840 "requires {1} type arguments",
841 TypeManager.CSharpName (t),
842 TypeManager.GetNumberOfTypeArguments (t).ToString ());
847 MemberList ml = TypeManager.FindMembers (queried_type, MemberTypes.Constructor,
848 BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.DeclaredOnly, null, null);
849 if (name == ".ctor" && ml.Count == 0)
851 Report.Error (143, loc, "The type `{0}' has no constructors defined", TypeManager.CSharpName (queried_type));
855 Report.SymbolRelatedToPreviousError (lookup [0]);
856 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (lookup [0]));
860 /// Returns an expression that can be used to invoke operator true
861 /// on the expression if it exists.
863 static public Expression GetOperatorTrue (EmitContext ec, Expression e, Location loc)
865 return GetOperatorTrueOrFalse (ec, e, true, loc);
869 /// Returns an expression that can be used to invoke operator false
870 /// on the expression if it exists.
872 static public Expression GetOperatorFalse (EmitContext ec, Expression e, Location loc)
874 return GetOperatorTrueOrFalse (ec, e, false, loc);
877 static Expression GetOperatorTrueOrFalse (EmitContext ec, Expression e, bool is_true, Location loc)
879 MethodGroupExpr operator_group;
882 if (TypeManager.IsNullableType (e.Type))
883 return new Nullable.OperatorTrueOrFalse (e, is_true, loc).Resolve (ec);
886 operator_group = MethodLookup (ec.ContainerType, e.Type, is_true ? "op_True" : "op_False", loc) as MethodGroupExpr;
887 if (operator_group == null)
890 ArrayList arguments = new ArrayList (1);
891 arguments.Add (new Argument (e, Argument.AType.Expression));
892 operator_group = operator_group.OverloadResolve (
893 ec, arguments, false, loc);
895 if (operator_group == null)
898 return new StaticCallExpr ((MethodInfo) operator_group, arguments, loc);
902 /// Resolves the expression `e' into a boolean expression: either through
903 /// an implicit conversion, or through an `operator true' invocation
905 public static Expression ResolveBoolean (EmitContext ec, Expression e, Location loc)
911 if (e.Type == TypeManager.bool_type)
914 Expression converted = Convert.ImplicitConversion (ec, e, TypeManager.bool_type, Location.Null);
916 if (converted != null)
920 // If no implicit conversion to bool exists, try using `operator true'
922 converted = Expression.GetOperatorTrue (ec, e, loc);
923 if (converted == null){
924 e.Error_ValueCannotBeConverted (ec, loc, TypeManager.bool_type, false);
930 public virtual string ExprClassName
934 case ExprClass.Invalid:
936 case ExprClass.Value:
938 case ExprClass.Variable:
940 case ExprClass.Namespace:
944 case ExprClass.MethodGroup:
945 return "method group";
946 case ExprClass.PropertyAccess:
947 return "property access";
948 case ExprClass.EventAccess:
949 return "event access";
950 case ExprClass.IndexerAccess:
951 return "indexer access";
952 case ExprClass.Nothing:
955 throw new Exception ("Should not happen");
960 /// Reports that we were expecting `expr' to be of class `expected'
962 public void Error_UnexpectedKind (DeclSpace ds, string expected, Location loc)
964 Error_UnexpectedKind (ds, expected, ExprClassName, loc);
967 public void Error_UnexpectedKind (DeclSpace ds, string expected, string was, Location loc)
969 string name = GetSignatureForError ();
971 name = ds.GetSignatureForError () + '.' + name;
973 Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
974 name, was, expected);
977 public void Error_UnexpectedKind (ResolveFlags flags, Location loc)
979 string [] valid = new string [4];
982 if ((flags & ResolveFlags.VariableOrValue) != 0) {
983 valid [count++] = "variable";
984 valid [count++] = "value";
987 if ((flags & ResolveFlags.Type) != 0)
988 valid [count++] = "type";
990 if ((flags & ResolveFlags.MethodGroup) != 0)
991 valid [count++] = "method group";
994 valid [count++] = "unknown";
996 StringBuilder sb = new StringBuilder (valid [0]);
997 for (int i = 1; i < count - 1; i++) {
999 sb.Append (valid [i]);
1002 sb.Append ("' or `");
1003 sb.Append (valid [count - 1]);
1006 Report.Error (119, loc,
1007 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1010 public static void UnsafeError (Location loc)
1012 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1016 // Load the object from the pointer.
1018 public static void LoadFromPtr (ILGenerator ig, Type t)
1020 if (t == TypeManager.int32_type)
1021 ig.Emit (OpCodes.Ldind_I4);
1022 else if (t == TypeManager.uint32_type)
1023 ig.Emit (OpCodes.Ldind_U4);
1024 else if (t == TypeManager.short_type)
1025 ig.Emit (OpCodes.Ldind_I2);
1026 else if (t == TypeManager.ushort_type)
1027 ig.Emit (OpCodes.Ldind_U2);
1028 else if (t == TypeManager.char_type)
1029 ig.Emit (OpCodes.Ldind_U2);
1030 else if (t == TypeManager.byte_type)
1031 ig.Emit (OpCodes.Ldind_U1);
1032 else if (t == TypeManager.sbyte_type)
1033 ig.Emit (OpCodes.Ldind_I1);
1034 else if (t == TypeManager.uint64_type)
1035 ig.Emit (OpCodes.Ldind_I8);
1036 else if (t == TypeManager.int64_type)
1037 ig.Emit (OpCodes.Ldind_I8);
1038 else if (t == TypeManager.float_type)
1039 ig.Emit (OpCodes.Ldind_R4);
1040 else if (t == TypeManager.double_type)
1041 ig.Emit (OpCodes.Ldind_R8);
1042 else if (t == TypeManager.bool_type)
1043 ig.Emit (OpCodes.Ldind_I1);
1044 else if (t == TypeManager.intptr_type)
1045 ig.Emit (OpCodes.Ldind_I);
1046 else if (TypeManager.IsEnumType (t)) {
1047 if (t == TypeManager.enum_type)
1048 ig.Emit (OpCodes.Ldind_Ref);
1050 LoadFromPtr (ig, TypeManager.EnumToUnderlying (t));
1051 } else if (t.IsValueType || TypeManager.IsGenericParameter (t))
1052 ig.Emit (OpCodes.Ldobj, t);
1053 else if (t.IsPointer)
1054 ig.Emit (OpCodes.Ldind_I);
1056 ig.Emit (OpCodes.Ldind_Ref);
1060 // The stack contains the pointer and the value of type `type'
1062 public static void StoreFromPtr (ILGenerator ig, Type type)
1064 if (TypeManager.IsEnumType (type))
1065 type = TypeManager.EnumToUnderlying (type);
1066 if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
1067 ig.Emit (OpCodes.Stind_I4);
1068 else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
1069 ig.Emit (OpCodes.Stind_I8);
1070 else if (type == TypeManager.char_type || type == TypeManager.short_type ||
1071 type == TypeManager.ushort_type)
1072 ig.Emit (OpCodes.Stind_I2);
1073 else if (type == TypeManager.float_type)
1074 ig.Emit (OpCodes.Stind_R4);
1075 else if (type == TypeManager.double_type)
1076 ig.Emit (OpCodes.Stind_R8);
1077 else if (type == TypeManager.byte_type || type == TypeManager.sbyte_type ||
1078 type == TypeManager.bool_type)
1079 ig.Emit (OpCodes.Stind_I1);
1080 else if (type == TypeManager.intptr_type)
1081 ig.Emit (OpCodes.Stind_I);
1082 else if (type.IsValueType || TypeManager.IsGenericParameter (type))
1083 ig.Emit (OpCodes.Stobj, type);
1085 ig.Emit (OpCodes.Stind_Ref);
1089 // Returns the size of type `t' if known, otherwise, 0
1091 public static int GetTypeSize (Type t)
1093 t = TypeManager.TypeToCoreType (t);
1094 if (t == TypeManager.int32_type ||
1095 t == TypeManager.uint32_type ||
1096 t == TypeManager.float_type)
1098 else if (t == TypeManager.int64_type ||
1099 t == TypeManager.uint64_type ||
1100 t == TypeManager.double_type)
1102 else if (t == TypeManager.byte_type ||
1103 t == TypeManager.sbyte_type ||
1104 t == TypeManager.bool_type)
1106 else if (t == TypeManager.short_type ||
1107 t == TypeManager.char_type ||
1108 t == TypeManager.ushort_type)
1110 else if (t == TypeManager.decimal_type)
1116 public static void Error_NegativeArrayIndex (Location loc)
1118 Report.Error (248, loc, "Cannot create an array with a negative size");
1121 protected void Error_CannotCallAbstractBase (string name)
1123 Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
1127 // Converts `source' to an int, uint, long or ulong.
1129 public Expression ExpressionToArrayArgument (EmitContext ec, Expression source, Location loc)
1133 using (ec.With (EmitContext.Flags.CheckState, true)) {
1134 target = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, loc);
1136 target = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, loc);
1138 target = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, loc);
1140 target = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, loc);
1142 if (target == null) {
1143 source.Error_ValueCannotBeConverted (ec, loc, TypeManager.int32_type, false);
1149 // Only positive constants are allowed at compile time
1151 if (target is Constant){
1152 if (target is IntConstant){
1153 if (((IntConstant) target).Value < 0){
1154 Error_NegativeArrayIndex (loc);
1159 if (target is LongConstant){
1160 if (((LongConstant) target).Value < 0){
1161 Error_NegativeArrayIndex (loc);
1172 // Derived classes implement this method by cloning the fields that
1173 // could become altered during the Resolve stage
1175 // Only expressions that are created for the parser need to implement
1178 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1180 throw new NotImplementedException (
1182 "CloneTo not implemented for expression {0}", this.GetType ()));
1186 // Clones an expression created by the parser.
1188 // We only support expressions created by the parser so far, not
1189 // expressions that have been resolved (many more classes would need
1190 // to implement CloneTo).
1192 // This infrastructure is here merely for Lambda expressions which
1193 // compile the same code using different type values for the same
1194 // arguments to find the correct overload
1196 public Expression Clone (CloneContext clonectx)
1198 Expression cloned = (Expression) MemberwiseClone ();
1199 CloneTo (clonectx, cloned);
1206 /// This is just a base class for expressions that can
1207 /// appear on statements (invocations, object creation,
1208 /// assignments, post/pre increment and decrement). The idea
1209 /// being that they would support an extra Emition interface that
1210 /// does not leave a result on the stack.
1212 public abstract class ExpressionStatement : Expression {
1214 public virtual ExpressionStatement ResolveStatement (EmitContext ec)
1216 Expression e = Resolve (ec);
1220 ExpressionStatement es = e as ExpressionStatement;
1222 Error_InvalidExpressionStatement ();
1228 /// Requests the expression to be emitted in a `statement'
1229 /// context. This means that no new value is left on the
1230 /// stack after invoking this method (constrasted with
1231 /// Emit that will always leave a value on the stack).
1233 public abstract void EmitStatement (EmitContext ec);
1237 /// This kind of cast is used to encapsulate the child
1238 /// whose type is child.Type into an expression that is
1239 /// reported to return "return_type". This is used to encapsulate
1240 /// expressions which have compatible types, but need to be dealt
1241 /// at higher levels with.
1243 /// For example, a "byte" expression could be encapsulated in one
1244 /// of these as an "unsigned int". The type for the expression
1245 /// would be "unsigned int".
1248 public class EmptyCast : Expression {
1249 protected Expression child;
1251 public EmptyCast (Expression child, Type return_type)
1253 eclass = child.eclass;
1254 loc = child.Location;
1259 public override Expression DoResolve (EmitContext ec)
1261 // This should never be invoked, we are born in fully
1262 // initialized state.
1267 public override void Emit (EmitContext ec)
1272 public override bool GetAttributableValue (Type valueType, out object value)
1274 return child.GetAttributableValue (valueType, out value);
1277 protected override void CloneTo (CloneContext clonectx, Expression t)
1279 EmptyCast target = (EmptyCast) t;
1281 target.child = child.Clone (clonectx);
1286 /// Performs a cast using an operator (op_Explicit or op_Implicit)
1288 public class OperatorCast : EmptyCast {
1289 MethodInfo conversion_operator;
1292 public OperatorCast (Expression child, Type target_type) : this (child, target_type, false) {}
1294 public OperatorCast (Expression child, Type target_type, bool find_explicit)
1295 : base (child, target_type)
1297 this.find_explicit = find_explicit;
1300 // Returns the implicit operator that converts from
1301 // 'child.Type' to our target type (type)
1302 MethodInfo GetConversionOperator (bool find_explicit)
1304 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1308 mi = TypeManager.MemberLookup (child.Type, child.Type, child.Type, MemberTypes.Method,
1309 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1312 mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1313 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1316 foreach (MethodInfo oper in mi) {
1317 ParameterData pd = TypeManager.GetParameterData (oper);
1319 if (pd.ParameterType (0) == child.Type && oper.ReturnType == type)
1327 public override void Emit (EmitContext ec)
1329 ILGenerator ig = ec.ig;
1332 conversion_operator = GetConversionOperator (find_explicit);
1334 if (conversion_operator == null)
1335 throw new InternalErrorException ("Outer conversion routine is out of sync");
1337 ig.Emit (OpCodes.Call, conversion_operator);
1343 /// This is a numeric cast to a Decimal
1345 public class CastToDecimal : EmptyCast {
1346 MethodInfo conversion_operator;
1348 public CastToDecimal (Expression child)
1349 : this (child, false)
1353 public CastToDecimal (Expression child, bool find_explicit)
1354 : base (child, TypeManager.decimal_type)
1356 conversion_operator = GetConversionOperator (find_explicit);
1358 if (conversion_operator == null)
1359 throw new InternalErrorException ("Outer conversion routine is out of sync");
1362 // Returns the implicit operator that converts from
1363 // 'child.Type' to System.Decimal.
1364 MethodInfo GetConversionOperator (bool find_explicit)
1366 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1368 MemberInfo [] mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1369 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1371 foreach (MethodInfo oper in mi) {
1372 ParameterData pd = TypeManager.GetParameterData (oper);
1374 if (pd.ParameterType (0) == child.Type && oper.ReturnType == type)
1380 public override void Emit (EmitContext ec)
1382 ILGenerator ig = ec.ig;
1385 ig.Emit (OpCodes.Call, conversion_operator);
1390 /// This is an explicit numeric cast from a Decimal
1392 public class CastFromDecimal : EmptyCast
1394 static IDictionary operators;
1396 public CastFromDecimal (Expression child, Type return_type)
1397 : base (child, return_type)
1399 if (child.Type != TypeManager.decimal_type)
1400 throw new InternalErrorException (
1401 "The expected type is Decimal, instead it is " + child.Type.FullName);
1404 // Returns the explicit operator that converts from an
1405 // express of type System.Decimal to 'type'.
1406 public Expression Resolve ()
1408 if (operators == null) {
1409 MemberInfo[] all_oper = TypeManager.MemberLookup (TypeManager.decimal_type,
1410 TypeManager.decimal_type, TypeManager.decimal_type, MemberTypes.Method,
1411 BindingFlags.Static | BindingFlags.Public, "op_Explicit", null);
1413 operators = new System.Collections.Specialized.HybridDictionary ();
1414 foreach (MethodInfo oper in all_oper) {
1415 ParameterData pd = TypeManager.GetParameterData (oper);
1416 if (pd.ParameterType (0) == TypeManager.decimal_type)
1417 operators.Add (oper.ReturnType, oper);
1421 return operators.Contains (type) ? this : null;
1424 public override void Emit (EmitContext ec)
1426 ILGenerator ig = ec.ig;
1429 ig.Emit (OpCodes.Call, (MethodInfo)operators [type]);
1435 // Constant specialization of EmptyCast.
1436 // We need to special case this since an empty cast of
1437 // a constant is still a constant.
1439 public class EmptyConstantCast : Constant
1441 public readonly Constant child;
1443 public EmptyConstantCast(Constant child, Type type)
1444 : base (child.Location)
1446 eclass = child.eclass;
1451 public override string AsString ()
1453 return child.AsString ();
1456 public override object GetValue ()
1458 return child.GetValue ();
1461 public override Constant ConvertExplicitly (bool inCheckedContext, Type target_type)
1463 // FIXME: check that 'type' can be converted to 'target_type' first
1464 return child.ConvertExplicitly (inCheckedContext, target_type);
1467 public override Constant Increment ()
1469 return child.Increment ();
1472 public override bool IsDefaultValue {
1473 get { return child.IsDefaultValue; }
1476 public override bool IsNegative {
1477 get { return child.IsNegative; }
1480 public override void Emit (EmitContext ec)
1485 public override Constant ConvertImplicitly (Type target_type)
1487 // FIXME: Do we need to check user conversions?
1488 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1490 return child.ConvertImplicitly (target_type);
1496 /// This class is used to wrap literals which belong inside Enums
1498 public class EnumConstant : Constant {
1499 public Constant Child;
1501 public EnumConstant (Constant child, Type enum_type):
1502 base (child.Location)
1504 eclass = child.eclass;
1509 public override Expression DoResolve (EmitContext ec)
1511 // This should never be invoked, we are born in fully
1512 // initialized state.
1517 public override void Emit (EmitContext ec)
1522 public override bool GetAttributableValue (Type valueType, out object value)
1524 value = GetTypedValue ();
1528 public override string GetSignatureForError()
1530 return TypeManager.CSharpName (Type);
1533 public override object GetValue ()
1535 return Child.GetValue ();
1538 public override object GetTypedValue ()
1540 // FIXME: runtime is not ready to work with just emited enums
1541 if (!RootContext.StdLib) {
1542 return Child.GetValue ();
1545 return System.Enum.ToObject (type, Child.GetValue ());
1548 public override string AsString ()
1550 return TypeManager.CSharpEnumValue (type, Child.GetValue ());
1553 public override Constant Increment()
1555 return new EnumConstant (Child.Increment (), type);
1558 public override bool IsDefaultValue {
1560 return Child.IsDefaultValue;
1564 public override bool IsZeroInteger {
1565 get { return Child.IsZeroInteger; }
1568 public override bool IsNegative {
1570 return Child.IsNegative;
1574 public override Constant ConvertExplicitly(bool inCheckedContext, Type target_type)
1576 if (Child.Type == target_type)
1579 return Child.ConvertExplicitly (inCheckedContext, target_type);
1582 public override Constant ConvertImplicitly (Type type)
1584 Type this_type = TypeManager.DropGenericTypeArguments (Type);
1585 type = TypeManager.DropGenericTypeArguments (type);
1587 if (this_type == type) {
1588 // This is workaround of mono bug. It can be removed when the latest corlib spreads enough
1589 if (TypeManager.IsEnumType (type.UnderlyingSystemType))
1592 Type child_type = TypeManager.DropGenericTypeArguments (Child.Type);
1593 if (type.UnderlyingSystemType != child_type)
1594 Child = Child.ConvertImplicitly (type.UnderlyingSystemType);
1598 if (!Convert.ImplicitStandardConversionExists (this, type)){
1602 return Child.ConvertImplicitly(type);
1608 /// This kind of cast is used to encapsulate Value Types in objects.
1610 /// The effect of it is to box the value type emitted by the previous
1613 public class BoxedCast : EmptyCast {
1615 public BoxedCast (Expression expr, Type target_type)
1616 : base (expr, target_type)
1618 eclass = ExprClass.Value;
1621 public override Expression DoResolve (EmitContext ec)
1623 // This should never be invoked, we are born in fully
1624 // initialized state.
1629 public override void Emit (EmitContext ec)
1633 ec.ig.Emit (OpCodes.Box, child.Type);
1637 public class UnboxCast : EmptyCast {
1638 public UnboxCast (Expression expr, Type return_type)
1639 : base (expr, return_type)
1643 public override Expression DoResolve (EmitContext ec)
1645 // This should never be invoked, we are born in fully
1646 // initialized state.
1651 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1653 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
1654 Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
1655 return base.DoResolveLValue (ec, right_side);
1658 public override void Emit (EmitContext ec)
1661 ILGenerator ig = ec.ig;
1665 if (t.IsGenericParameter || t.IsGenericType && t.IsValueType)
1666 ig.Emit (OpCodes.Unbox_Any, t);
1670 ig.Emit (OpCodes.Unbox, t);
1672 LoadFromPtr (ig, t);
1678 /// This is used to perform explicit numeric conversions.
1680 /// Explicit numeric conversions might trigger exceptions in a checked
1681 /// context, so they should generate the conv.ovf opcodes instead of
1684 public class ConvCast : EmptyCast {
1685 public enum Mode : byte {
1686 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1688 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1689 U2_I1, U2_U1, U2_I2, U2_CH,
1690 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1691 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1692 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH,
1693 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH,
1694 CH_I1, CH_U1, CH_I2,
1695 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1696 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4
1701 public ConvCast (Expression child, Type return_type, Mode m)
1702 : base (child, return_type)
1707 public override Expression DoResolve (EmitContext ec)
1709 // This should never be invoked, we are born in fully
1710 // initialized state.
1715 public override string ToString ()
1717 return String.Format ("ConvCast ({0}, {1})", mode, child);
1720 public override void Emit (EmitContext ec)
1722 ILGenerator ig = ec.ig;
1728 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1729 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1730 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1731 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1732 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1734 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1735 case Mode.U1_CH: /* nothing */ break;
1737 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1738 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1739 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1740 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1741 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1742 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1744 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1745 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1746 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1747 case Mode.U2_CH: /* nothing */ break;
1749 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1750 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1751 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1752 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1753 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1754 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1755 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1757 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1758 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1759 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1760 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1761 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1762 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1764 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1765 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1766 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1767 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1768 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1769 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1770 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1771 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1773 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1774 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1775 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1776 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1777 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1778 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1779 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1780 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1782 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1783 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1784 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1786 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1787 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1788 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1789 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1790 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1791 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1792 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1793 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1794 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1796 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1797 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1798 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1799 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1800 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1801 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1802 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1803 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1804 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1805 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1809 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
1810 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
1811 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
1812 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
1813 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
1815 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
1816 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
1818 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
1819 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
1820 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
1821 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
1822 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
1823 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
1825 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
1826 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
1827 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
1828 case Mode.U2_CH: /* nothing */ break;
1830 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
1831 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
1832 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
1833 case Mode.I4_U4: /* nothing */ break;
1834 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
1835 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
1836 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
1838 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
1839 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
1840 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
1841 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
1842 case Mode.U4_I4: /* nothing */ break;
1843 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
1845 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
1846 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
1847 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
1848 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
1849 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
1850 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
1851 case Mode.I8_U8: /* nothing */ break;
1852 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
1854 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
1855 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
1856 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
1857 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
1858 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
1859 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
1860 case Mode.U8_I8: /* nothing */ break;
1861 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
1863 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
1864 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
1865 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
1867 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
1868 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
1869 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
1870 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
1871 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
1872 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
1873 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
1874 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
1875 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
1877 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
1878 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
1879 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
1880 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
1881 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
1882 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
1883 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
1884 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
1885 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
1886 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1892 public class OpcodeCast : EmptyCast {
1896 public OpcodeCast (Expression child, Type return_type, OpCode op)
1897 : base (child, return_type)
1901 second_valid = false;
1904 public OpcodeCast (Expression child, Type return_type, OpCode op, OpCode op2)
1905 : base (child, return_type)
1910 second_valid = true;
1913 public override Expression DoResolve (EmitContext ec)
1915 // This should never be invoked, we are born in fully
1916 // initialized state.
1921 public override void Emit (EmitContext ec)
1932 /// This kind of cast is used to encapsulate a child and cast it
1933 /// to the class requested
1935 public class ClassCast : EmptyCast {
1936 public ClassCast (Expression child, Type return_type)
1937 : base (child, return_type)
1942 public override Expression DoResolve (EmitContext ec)
1944 // This should never be invoked, we are born in fully
1945 // initialized state.
1950 public override void Emit (EmitContext ec)
1954 if (TypeManager.IsGenericParameter (child.Type))
1955 ec.ig.Emit (OpCodes.Box, child.Type);
1958 if (type.IsGenericParameter)
1959 ec.ig.Emit (OpCodes.Unbox_Any, type);
1962 ec.ig.Emit (OpCodes.Castclass, type);
1967 /// SimpleName expressions are formed of a single word and only happen at the beginning
1968 /// of a dotted-name.
1970 public class SimpleName : Expression {
1971 public readonly string Name;
1972 public readonly TypeArguments Arguments;
1975 public SimpleName (string name, Location l)
1981 public SimpleName (string name, TypeArguments args, Location l)
1988 public SimpleName (string name, TypeParameter[] type_params, Location l)
1993 Arguments = new TypeArguments (l);
1994 foreach (TypeParameter type_param in type_params)
1995 Arguments.Add (new TypeParameterExpr (type_param, l));
1998 public static string RemoveGenericArity (string name)
2001 StringBuilder sb = null;
2003 int pos = name.IndexOf ('`', start);
2008 sb.Append (name.Substring (start));
2013 sb = new StringBuilder ();
2014 sb.Append (name.Substring (start, pos-start));
2017 while ((pos < name.Length) && Char.IsNumber (name [pos]))
2021 } while (start < name.Length);
2023 return sb.ToString ();
2026 public SimpleName GetMethodGroup ()
2028 return new SimpleName (RemoveGenericArity (Name), Arguments, loc);
2031 public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
2033 if (ec.IsFieldInitializer)
2034 Report.Error (236, l,
2035 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2039 120, l, "`{0}': An object reference is required for the nonstatic field, method or property",
2043 public bool IdenticalNameAndTypeName (EmitContext ec, Expression resolved_to, Location loc)
2045 return resolved_to != null && resolved_to.Type != null &&
2046 resolved_to.Type.Name == Name &&
2047 (ec.DeclContainer.LookupNamespaceOrType (Name, loc, /* ignore_cs0104 = */ true) != null);
2050 public override Expression DoResolve (EmitContext ec)
2052 return SimpleNameResolve (ec, null, false);
2055 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
2057 return SimpleNameResolve (ec, right_side, false);
2061 public Expression DoResolve (EmitContext ec, bool intermediate)
2063 return SimpleNameResolve (ec, null, intermediate);
2066 private bool IsNestedChild (Type t, Type parent)
2071 while (parent != null) {
2072 parent = TypeManager.DropGenericTypeArguments (parent);
2073 if (TypeManager.IsNestedChildOf (t, parent))
2076 parent = parent.BaseType;
2082 FullNamedExpression ResolveNested (IResolveContext ec, Type t)
2084 if (!TypeManager.IsGenericTypeDefinition (t) && !TypeManager.IsGenericType (t))
2087 DeclSpace ds = ec.DeclContainer;
2088 while (ds != null) {
2089 if (IsNestedChild (t, ds.TypeBuilder))
2098 Type[] gen_params = TypeManager.GetTypeArguments (t);
2100 int arg_count = Arguments != null ? Arguments.Count : 0;
2102 for (; (ds != null) && ds.IsGeneric; ds = ds.Parent) {
2103 if (arg_count + ds.CountTypeParameters == gen_params.Length) {
2104 TypeArguments new_args = new TypeArguments (loc);
2105 foreach (TypeParameter param in ds.TypeParameters)
2106 new_args.Add (new TypeParameterExpr (param, loc));
2108 if (Arguments != null)
2109 new_args.Add (Arguments);
2111 return new ConstructedType (t, new_args, loc);
2118 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2120 FullNamedExpression fne = ec.GenericDeclContainer.LookupGeneric (Name, loc);
2122 return fne.ResolveAsTypeStep (ec, silent);
2124 int errors = Report.Errors;
2125 fne = ec.DeclContainer.LookupNamespaceOrType (Name, loc, /*ignore_cs0104=*/ false);
2128 if (fne.Type == null)
2131 FullNamedExpression nested = ResolveNested (ec, fne.Type);
2133 return nested.ResolveAsTypeStep (ec, false);
2135 if (Arguments != null) {
2136 ConstructedType ct = new ConstructedType (fne, Arguments, loc);
2137 return ct.ResolveAsTypeStep (ec, false);
2143 if (silent || errors != Report.Errors)
2146 Error_TypeOrNamespaceNotFound (ec);
2150 protected virtual void Error_TypeOrNamespaceNotFound (IResolveContext ec)
2152 MemberCore mc = ec.DeclContainer.GetDefinition (Name);
2154 Error_UnexpectedKind (ec.DeclContainer, "type", GetMemberType (mc), loc);
2158 string ns = ec.DeclContainer.NamespaceEntry.NS.Name;
2159 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2160 foreach (Assembly a in RootNamespace.Global.Assemblies) {
2161 Type type = a.GetType (fullname);
2163 Report.SymbolRelatedToPreviousError (type);
2164 Expression.ErrorIsInaccesible (loc, TypeManager.CSharpName (type));
2169 Type t = ec.DeclContainer.LookupAnyGeneric (Name);
2171 Namespace.Error_InvalidNumberOfTypeArguments (t, loc);
2175 if (Arguments != null) {
2176 FullNamedExpression retval = ec.DeclContainer.LookupNamespaceOrType (SimpleName.RemoveGenericArity (Name), loc, true);
2177 if (retval != null) {
2178 Namespace.Error_TypeArgumentsCannotBeUsed (retval.Type, loc, "type");
2183 NamespaceEntry.Error_NamespaceNotFound (loc, Name);
2186 // TODO: I am still not convinced about this. If someone else will need it
2187 // implement this as virtual property in MemberCore hierarchy
2188 public static string GetMemberType (MemberCore mc)
2194 if (mc is FieldBase)
2196 if (mc is MethodCore)
2198 if (mc is EnumMember)
2206 Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2212 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2218 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2225 /// 7.5.2: Simple Names.
2227 /// Local Variables and Parameters are handled at
2228 /// parse time, so they never occur as SimpleNames.
2230 /// The `intermediate' flag is used by MemberAccess only
2231 /// and it is used to inform us that it is ok for us to
2232 /// avoid the static check, because MemberAccess might end
2233 /// up resolving the Name as a Type name and the access as
2234 /// a static type access.
2236 /// ie: Type Type; .... { Type.GetType (""); }
2238 /// Type is both an instance variable and a Type; Type.GetType
2239 /// is the static method not an instance method of type.
2241 Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2243 Expression e = null;
2246 // Stage 1: Performed by the parser (binding to locals or parameters).
2248 Block current_block = ec.CurrentBlock;
2249 if (current_block != null){
2250 LocalInfo vi = current_block.GetLocalInfo (Name);
2252 if (Arguments != null) {
2253 Report.Error (307, loc,
2254 "The variable `{0}' cannot be used with type arguments",
2259 LocalVariableReference var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2260 if (right_side != null) {
2261 return var.ResolveLValue (ec, right_side, loc);
2263 ResolveFlags rf = ResolveFlags.VariableOrValue;
2265 rf |= ResolveFlags.DisableFlowAnalysis;
2266 return var.Resolve (ec, rf);
2270 ParameterReference pref = current_block.Toplevel.GetParameterReference (Name, loc);
2272 if (Arguments != null) {
2273 Report.Error (307, loc,
2274 "The variable `{0}' cannot be used with type arguments",
2279 if (right_side != null)
2280 return pref.ResolveLValue (ec, right_side, loc);
2282 return pref.Resolve (ec);
2287 // Stage 2: Lookup members
2290 DeclSpace lookup_ds = ec.DeclContainer;
2291 Type almost_matched_type = null;
2292 ArrayList almost_matched = null;
2294 if (lookup_ds.TypeBuilder == null)
2297 e = MemberLookup (ec.ContainerType, lookup_ds.TypeBuilder, Name, loc);
2301 if (almost_matched == null && almostMatchedMembers.Count > 0) {
2302 almost_matched_type = lookup_ds.TypeBuilder;
2303 almost_matched = (ArrayList) almostMatchedMembers.Clone ();
2306 lookup_ds =lookup_ds.Parent;
2307 } while (lookup_ds != null);
2309 if (e == null && ec.ContainerType != null)
2310 e = MemberLookup (ec.ContainerType, ec.ContainerType, Name, loc);
2313 if (almost_matched == null && almostMatchedMembers.Count > 0) {
2314 almost_matched_type = ec.ContainerType;
2315 almost_matched = (ArrayList) almostMatchedMembers.Clone ();
2317 e = ResolveAsTypeStep (ec, true);
2321 if (current_block != null) {
2322 IKnownVariable ikv = current_block.Explicit.GetKnownVariable (Name);
2324 LocalInfo li = ikv as LocalInfo;
2325 // Supress CS0219 warning
2329 Error_VariableIsUsedBeforeItIsDeclared (Name);
2334 if (almost_matched != null)
2335 almostMatchedMembers = almost_matched;
2336 if (almost_matched_type == null)
2337 almost_matched_type = ec.ContainerType;
2338 MemberLookupFailed (ec.ContainerType, null, almost_matched_type, Name, ec.DeclContainer.Name, true, loc);
2342 if (e is TypeExpr) {
2343 if (Arguments == null)
2346 ConstructedType ct = new ConstructedType (
2347 (FullNamedExpression) e, Arguments, loc);
2348 return ct.ResolveAsTypeStep (ec, false);
2351 if (e is MemberExpr) {
2352 MemberExpr me = (MemberExpr) e;
2355 if (me.IsInstance) {
2356 if (ec.IsStatic || ec.IsFieldInitializer) {
2358 // Note that an MemberExpr can be both IsInstance and IsStatic.
2359 // An unresolved MethodGroupExpr can contain both kinds of methods
2360 // and each predicate is true if the MethodGroupExpr contains
2361 // at least one of that kind of method.
2365 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2366 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2367 return EmptyExpression.Null;
2371 // Pass the buck to MemberAccess and Invocation.
2373 left = EmptyExpression.Null;
2375 left = ec.GetThis (loc);
2378 left = new TypeExpression (ec.ContainerType, loc);
2381 e = me.ResolveMemberAccess (ec, left, loc, null);
2385 me = e as MemberExpr;
2389 if (Arguments != null) {
2390 MethodGroupExpr mg = me as MethodGroupExpr;
2394 return mg.ResolveGeneric (ec, Arguments);
2397 if (!me.IsStatic && (me.InstanceExpression != null) &&
2398 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2399 me.InstanceExpression.Type != me.DeclaringType &&
2400 !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2401 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2402 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2403 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2407 return (right_side != null)
2408 ? me.DoResolveLValue (ec, right_side)
2409 : me.DoResolve (ec);
2415 public override void Emit (EmitContext ec)
2417 throw new InternalErrorException ("The resolve phase was not executed");
2420 public override string ToString ()
2425 public override string GetSignatureForError ()
2427 if (Arguments != null) {
2428 return TypeManager.RemoveGenericArity (Name) + "<" +
2429 Arguments.GetSignatureForError () + ">";
2435 protected override void CloneTo (CloneContext clonectx, Expression target)
2437 // CloneTo: Nothing, we do not keep any state on this expression
2442 /// Represents a namespace or a type. The name of the class was inspired by
2443 /// section 10.8.1 (Fully Qualified Names).
2445 public abstract class FullNamedExpression : Expression {
2446 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2451 public abstract string FullName {
2457 /// Expression that evaluates to a type
2459 public abstract class TypeExpr : FullNamedExpression {
2460 override public FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2462 TypeExpr t = DoResolveAsTypeStep (ec);
2466 eclass = ExprClass.Type;
2470 override public Expression DoResolve (EmitContext ec)
2472 return ResolveAsTypeTerminal (ec, false);
2475 override public void Emit (EmitContext ec)
2477 throw new Exception ("Should never be called");
2480 public virtual bool CheckAccessLevel (DeclSpace ds)
2482 return ds.CheckAccessLevel (Type);
2485 public virtual bool AsAccessible (DeclSpace ds, int flags)
2487 return ds.AsAccessible (Type, flags);
2490 public virtual bool IsClass {
2491 get { return Type.IsClass; }
2494 public virtual bool IsValueType {
2495 get { return Type.IsValueType; }
2498 public virtual bool IsInterface {
2499 get { return Type.IsInterface; }
2502 public virtual bool IsSealed {
2503 get { return Type.IsSealed; }
2506 public virtual bool CanInheritFrom ()
2508 if (Type == TypeManager.enum_type ||
2509 (Type == TypeManager.value_type && RootContext.StdLib) ||
2510 Type == TypeManager.multicast_delegate_type ||
2511 Type == TypeManager.delegate_type ||
2512 Type == TypeManager.array_type)
2518 protected abstract TypeExpr DoResolveAsTypeStep (IResolveContext ec);
2520 public abstract string Name {
2524 public override bool Equals (object obj)
2526 TypeExpr tobj = obj as TypeExpr;
2530 return Type == tobj.Type;
2533 public override int GetHashCode ()
2535 return Type.GetHashCode ();
2538 public override string ToString ()
2545 /// Fully resolved Expression that already evaluated to a type
2547 public class TypeExpression : TypeExpr {
2548 public TypeExpression (Type t, Location l)
2551 eclass = ExprClass.Type;
2555 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2560 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2565 public override string Name {
2566 get { return Type.ToString (); }
2569 public override string FullName {
2570 get { return Type.FullName; }
2575 /// Used to create types from a fully qualified name. These are just used
2576 /// by the parser to setup the core types. A TypeLookupExpression is always
2577 /// classified as a type.
2579 public sealed class TypeLookupExpression : TypeExpr {
2580 readonly string name;
2582 public TypeLookupExpression (string name)
2585 eclass = ExprClass.Type;
2588 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2590 // It's null for corlib compilation only
2592 return DoResolveAsTypeStep (ec);
2597 private class UnexpectedType
2601 // This performes recursive type lookup, providing support for generic types.
2602 // For example, given the type:
2604 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]]
2606 // The types will be checked in the following order:
2609 // System.Collections |
2610 // System.Collections.Generic |
2612 // System | recursive call 1 |
2613 // System.Int32 _| | main method call
2615 // System | recursive call 2 |
2616 // System.String _| |
2618 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]] _|
2620 private Type TypeLookup (IResolveContext ec, string name)
2625 FullNamedExpression resolved = null;
2627 Type recursive_type = null;
2628 while (index < name.Length) {
2629 if (name[index] == '[') {
2634 if (name[index] == '[')
2636 else if (name[index] == ']')
2638 } while (braces > 0);
2639 recursive_type = TypeLookup (ec, name.Substring (open + 1, index - open - 1));
2640 if (recursive_type == null || (recursive_type == typeof(UnexpectedType)))
2641 return recursive_type;
2644 if (name[index] == ',')
2646 else if ((name[index] == '.' && !done) || (index == name.Length && name[0] != '[')) {
2647 string substring = name.Substring(dot, index - dot);
2649 if (resolved == null)
2650 resolved = RootNamespace.Global.Lookup (ec.DeclContainer, substring, Location.Null);
2651 else if (resolved is Namespace)
2652 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
2653 else if (type != null)
2654 type = TypeManager.GetNestedType (type, substring);
2658 if (resolved == null)
2660 else if (type == null && resolved is TypeExpr)
2661 type = resolved.Type;
2668 if (name[0] != '[') {
2669 string substring = name.Substring(dot, index - dot);
2672 return TypeManager.GetNestedType (type, substring);
2674 if (resolved != null) {
2675 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
2676 if (resolved is TypeExpr)
2677 return resolved.Type;
2679 if (resolved == null)
2682 resolved.Error_UnexpectedKind (ec.DeclContainer, "type", loc);
2683 return typeof (UnexpectedType);
2689 return recursive_type;
2692 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2694 Type t = TypeLookup (ec, name);
2696 NamespaceEntry.Error_NamespaceNotFound (loc, name);
2699 if (t == typeof(UnexpectedType))
2705 public override string Name {
2706 get { return name; }
2709 public override string FullName {
2710 get { return name; }
2713 protected override void CloneTo (CloneContext clonectx, Expression target)
2715 // CloneTo: Nothing, we do not keep any state on this expression
2718 public override string GetSignatureForError ()
2721 return TypeManager.CSharpName (name);
2723 return base.GetSignatureForError ();
2728 /// Represents an "unbound generic type", ie. typeof (Foo<>).
2731 public class UnboundTypeExpression : TypeExpr
2735 public UnboundTypeExpression (MemberName name, Location l)
2741 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2744 if (name.Left != null) {
2745 Expression lexpr = name.Left.GetTypeExpression ();
2746 expr = new MemberAccess (lexpr, name.Basename);
2748 expr = new SimpleName (name.Basename, loc);
2751 FullNamedExpression fne = expr.ResolveAsTypeStep (ec, false);
2756 return new TypeExpression (type, loc);
2759 public override string Name {
2760 get { return name.FullName; }
2763 public override string FullName {
2764 get { return name.FullName; }
2768 public class TypeAliasExpression : TypeExpr {
2769 FullNamedExpression alias;
2774 public TypeAliasExpression (FullNamedExpression alias, TypeArguments args, Location l)
2780 eclass = ExprClass.Type;
2782 name = alias.FullName + "<" + args.ToString () + ">";
2784 name = alias.FullName;
2787 public override string Name {
2788 get { return alias.FullName; }
2791 public override string FullName {
2792 get { return name; }
2795 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2797 texpr = alias.ResolveAsTypeTerminal (ec, false);
2801 Type type = texpr.Type;
2802 int num_args = TypeManager.GetNumberOfTypeArguments (type);
2805 if (num_args == 0) {
2806 Report.Error (308, loc,
2807 "The non-generic type `{0}' cannot " +
2808 "be used with type arguments.",
2809 TypeManager.CSharpName (type));
2813 ConstructedType ctype = new ConstructedType (type, args, loc);
2814 return ctype.ResolveAsTypeTerminal (ec, false);
2815 } else if (num_args > 0) {
2816 Report.Error (305, loc,
2817 "Using the generic type `{0}' " +
2818 "requires {1} type arguments",
2819 TypeManager.CSharpName (type), num_args.ToString ());
2826 public override bool CheckAccessLevel (DeclSpace ds)
2828 return texpr.CheckAccessLevel (ds);
2831 public override bool AsAccessible (DeclSpace ds, int flags)
2833 return texpr.AsAccessible (ds, flags);
2836 public override bool IsClass {
2837 get { return texpr.IsClass; }
2840 public override bool IsValueType {
2841 get { return texpr.IsValueType; }
2844 public override bool IsInterface {
2845 get { return texpr.IsInterface; }
2848 public override bool IsSealed {
2849 get { return texpr.IsSealed; }
2854 /// This class denotes an expression which evaluates to a member
2855 /// of a struct or a class.
2857 public abstract class MemberExpr : Expression
2860 /// The name of this member.
2862 public abstract string Name {
2867 /// Whether this is an instance member.
2869 public abstract bool IsInstance {
2874 /// Whether this is a static member.
2876 public abstract bool IsStatic {
2881 /// The type which declares this member.
2883 public abstract Type DeclaringType {
2888 /// The instance expression associated with this member, if it's a
2889 /// non-static member.
2891 public Expression InstanceExpression;
2893 public static void error176 (Location loc, string name)
2895 Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
2896 "with an instance reference, qualify it with a type name instead", name);
2899 // TODO: possible optimalization
2900 // Cache resolved constant result in FieldBuilder <-> expression map
2901 public virtual Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
2902 SimpleName original)
2906 // original == null || original.Resolve (...) ==> left
2909 if (left is TypeExpr) {
2910 left = left.ResolveAsTypeTerminal (ec, true);
2915 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
2922 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
2925 error176 (loc, GetSignatureForError ());
2929 InstanceExpression = left;
2934 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
2939 if (InstanceExpression == EmptyExpression.Null) {
2940 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
2944 if (InstanceExpression.Type.IsValueType) {
2945 if (InstanceExpression is IMemoryLocation) {
2946 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
2948 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
2949 InstanceExpression.Emit (ec);
2951 t.AddressOf (ec, AddressOp.Store);
2954 InstanceExpression.Emit (ec);
2956 if (prepare_for_load)
2957 ec.ig.Emit (OpCodes.Dup);
2962 /// Represents group of extension methods
2964 public class ExtensionMethodGroupExpr : MethodGroupExpr
2966 readonly NamespaceEntry namespaceEntry;
2967 public Expression ExtensionExpression;
2969 public ExtensionMethodGroupExpr (ArrayList list, NamespaceEntry n, Type extensionType, Location l)
2972 this.namespaceEntry = n;
2973 this.type = extensionType;
2976 public override bool IsBase {
2977 get { return true; }
2980 public override bool IsStatic {
2981 get { return true; }
2984 public bool IsTopLevel {
2985 get { return namespaceEntry == null; }
2988 public override void EmitArguments (EmitContext ec, ArrayList arguments)
2990 if (arguments == null)
2991 arguments = new ArrayList (1);
2992 arguments.Insert (0, new Argument (ExtensionExpression));
2993 base.EmitArguments (ec, arguments);
2996 public override void EmitCall (EmitContext ec, ArrayList arguments)
2998 if (arguments == null)
2999 arguments = new ArrayList (1);
3000 arguments.Insert (0, new Argument (ExtensionExpression));
3001 base.EmitCall (ec, arguments);
3004 public override MethodGroupExpr OverloadResolve (EmitContext ec, ArrayList arguments, bool may_fail, Location loc)
3006 if ((ExtensionExpression.eclass & (ExprClass.Value | ExprClass.Variable)) == 0)
3007 return base.OverloadResolve (ec, arguments, may_fail, loc);
3009 if (arguments == null)
3010 arguments = new ArrayList (1);
3012 arguments.Insert (0, new Argument (ExtensionExpression));
3013 MethodGroupExpr mg = ResolveOverloadExtensions (ec, arguments, namespaceEntry, loc);
3015 // Restore original arguments
3016 arguments.RemoveAt (0);
3022 return base.OverloadResolve (ec, arguments, may_fail, loc);
3027 MethodGroupExpr ResolveOverloadExtensions (EmitContext ec, ArrayList arguments, NamespaceEntry ns, Location loc)
3029 // Use normal resolve rules
3030 MethodGroupExpr mg = base.OverloadResolve (ec, arguments, true, loc);
3038 ExtensionMethodGroupExpr e = ns.LookupExtensionMethod (type, null, Name);
3042 e.ExtensionExpression = ExtensionExpression;
3043 return e.ResolveOverloadExtensions (ec, arguments, e.namespaceEntry, loc);
3048 /// MethodGroupExpr represents a group of method candidates which
3049 /// can be resolved to the best method overload
3051 public class MethodGroupExpr : MemberExpr {
3052 public readonly MethodBase [] Methods;
3053 MethodBase best_candidate;
3054 bool has_type_arguments;
3055 bool identical_type_name;
3058 public MethodGroupExpr (MemberInfo [] mi, Location l)
3060 Methods = new MethodBase [mi.Length];
3061 mi.CopyTo (Methods, 0);
3062 eclass = ExprClass.MethodGroup;
3064 // Set the type to something that will never be useful, which will
3065 // trigger the proper conversions.
3066 type = typeof (MethodGroupExpr);
3070 public MethodGroupExpr (ArrayList list, Location l)
3073 Methods = (MethodBase[])list.ToArray (typeof (MethodBase));
3075 foreach (MemberInfo m in list){
3076 if (!(m is MethodBase)){
3077 Console.WriteLine ("Name " + m.Name);
3078 Console.WriteLine ("Found a: " + m.GetType ().FullName);
3085 eclass = ExprClass.MethodGroup;
3086 type = TypeManager.object_type;
3089 public override Type DeclaringType {
3092 // We assume that the top-level type is in the end
3094 return Methods [Methods.Length - 1].DeclaringType;
3095 //return Methods [0].DeclaringType;
3099 public bool HasTypeArguments {
3101 return has_type_arguments;
3105 has_type_arguments = value;
3109 public bool IdenticalTypeName {
3111 return identical_type_name;
3115 identical_type_name = value;
3119 public virtual bool IsBase {
3128 public override string GetSignatureForError ()
3130 if (best_candidate != null)
3131 return TypeManager.CSharpSignature (best_candidate);
3133 return TypeManager.CSharpSignature (Methods [0]);
3136 public override string Name {
3138 return Methods [0].Name;
3142 public override bool IsInstance {
3144 foreach (MethodBase mb in Methods)
3152 public override bool IsStatic {
3154 foreach (MethodBase mb in Methods)
3162 public static explicit operator ConstructorInfo (MethodGroupExpr mg)
3164 return (ConstructorInfo)mg.best_candidate;
3167 public static explicit operator MethodInfo (MethodGroupExpr mg)
3169 return (MethodInfo)mg.best_candidate;
3173 /// Determines "better conversion" as specified in 14.4.2.3
3175 /// Returns : p if a->p is better,
3176 /// q if a->q is better,
3177 /// null if neither is better
3179 static Type BetterConversion (EmitContext ec, Argument a, Type p, Type q)
3181 Type argument_type = TypeManager.TypeToCoreType (a.Type);
3182 Expression argument_expr = a.Expr;
3184 if (argument_type == null)
3185 throw new Exception ("Expression of type " + a.Expr +
3186 " does not resolve its type");
3188 if (p == null || q == null)
3189 throw new InternalErrorException ("BetterConversion Got a null conversion");
3194 if (argument_expr is NullLiteral)
3197 // If the argument is null and one of the types to compare is 'object' and
3198 // the other is a reference type, we prefer the other.
3200 // This follows from the usual rules:
3201 // * There is an implicit conversion from 'null' to type 'object'
3202 // * There is an implicit conversion from 'null' to any reference type
3203 // * There is an implicit conversion from any reference type to type 'object'
3204 // * There is no implicit conversion from type 'object' to other reference types
3205 // => Conversion of 'null' to a reference type is better than conversion to 'object'
3207 // FIXME: This probably isn't necessary, since the type of a NullLiteral is the
3208 // null type. I think it used to be 'object' and thus needed a special
3209 // case to avoid the immediately following two checks.
3211 if (!p.IsValueType && q == TypeManager.object_type)
3213 if (!q.IsValueType && p == TypeManager.object_type)
3217 if (argument_type == p)
3220 if (argument_type == q)
3223 Expression p_tmp = new EmptyExpression (p);
3224 Expression q_tmp = new EmptyExpression (q);
3226 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3227 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3229 if (p_to_q && !q_to_p)
3232 if (q_to_p && !p_to_q)
3235 if (p == TypeManager.sbyte_type)
3236 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3237 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3239 if (q == TypeManager.sbyte_type)
3240 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3241 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3244 if (p == TypeManager.short_type)
3245 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3246 q == TypeManager.uint64_type)
3248 if (q == TypeManager.short_type)
3249 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3250 p == TypeManager.uint64_type)
3253 if (p == TypeManager.int32_type)
3254 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3256 if (q == TypeManager.int32_type)
3257 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3260 if (p == TypeManager.int64_type)
3261 if (q == TypeManager.uint64_type)
3263 if (q == TypeManager.int64_type)
3264 if (p == TypeManager.uint64_type)
3271 /// Determines "Better function" between candidate
3272 /// and the current best match
3275 /// Returns a boolean indicating :
3276 /// false if candidate ain't better
3277 /// true if candidate is better than the current best match
3279 static bool BetterFunction (EmitContext ec, ArrayList args, int argument_count,
3280 MethodBase candidate, bool candidate_params,
3281 MethodBase best, bool best_params)
3283 ParameterData candidate_pd = TypeManager.GetParameterData (candidate);
3284 ParameterData best_pd = TypeManager.GetParameterData (best);
3286 bool better_at_least_one = false;
3288 for (int j = 0, c_idx = 0, b_idx = 0; j < argument_count; ++j, ++c_idx, ++b_idx)
3290 Argument a = (Argument) args [j];
3292 Type ct = TypeManager.TypeToCoreType (candidate_pd.ParameterType (c_idx));
3293 Type bt = TypeManager.TypeToCoreType (best_pd.ParameterType (b_idx));
3295 if (candidate_params && candidate_pd.ParameterModifier (c_idx) == Parameter.Modifier.PARAMS)
3297 ct = TypeManager.GetElementType (ct);
3301 if (best_params && best_pd.ParameterModifier (b_idx) == Parameter.Modifier.PARAMS)
3303 bt = TypeManager.GetElementType (bt);
3311 Type better = BetterConversion (ec, a, ct, bt);
3313 // for each argument, the conversion to 'ct' should be no worse than
3314 // the conversion to 'bt'.
3318 // for at least one argument, the conversion to 'ct' should be better than
3319 // the conversion to 'bt'.
3321 better_at_least_one = true;
3324 if (better_at_least_one)
3328 // This handles the case
3330 // Add (float f1, float f2, float f3);
3331 // Add (params decimal [] foo);
3333 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3334 // first candidate would've chosen as better.
3340 // The two methods have equal parameter types. Now apply tie-breaking rules
3342 if (TypeManager.IsGenericMethod (best) && !TypeManager.IsGenericMethod (candidate))
3344 if (!TypeManager.IsGenericMethod (best) && TypeManager.IsGenericMethod (candidate))
3348 // This handles the following cases:
3350 // Trim () is better than Trim (params char[] chars)
3351 // Concat (string s1, string s2, string s3) is better than
3352 // Concat (string s1, params string [] srest)
3353 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3355 if (!candidate_params && best_params)
3357 if (candidate_params && !best_params)
3360 int candidate_param_count = candidate_pd.Count;
3361 int best_param_count = best_pd.Count;
3363 if (candidate_param_count != best_param_count)
3364 // can only happen if (candidate_params && best_params)
3365 return candidate_param_count > best_param_count;
3368 // now, both methods have the same number of parameters, and the parameters have the same types
3369 // Pick the "more specific" signature
3372 MethodBase orig_candidate = TypeManager.DropGenericMethodArguments (candidate);
3373 MethodBase orig_best = TypeManager.DropGenericMethodArguments (best);
3375 ParameterData orig_candidate_pd = TypeManager.GetParameterData (orig_candidate);
3376 ParameterData orig_best_pd = TypeManager.GetParameterData (orig_best);
3378 bool specific_at_least_once = false;
3379 for (int j = 0; j < candidate_param_count; ++j)
3381 Type ct = TypeManager.TypeToCoreType (orig_candidate_pd.ParameterType (j));
3382 Type bt = TypeManager.TypeToCoreType (orig_best_pd.ParameterType (j));
3385 Type specific = MoreSpecific (ct, bt);
3389 specific_at_least_once = true;
3392 if (specific_at_least_once)
3395 // FIXME: handle lifted operators
3401 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3402 SimpleName original)
3404 if (!(left is TypeExpr) &&
3405 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3406 IdenticalTypeName = true;
3408 return base.ResolveMemberAccess (ec, left, loc, original);
3411 override public Expression DoResolve (EmitContext ec)
3413 if (InstanceExpression != null) {
3414 InstanceExpression = InstanceExpression.DoResolve (ec);
3415 if (InstanceExpression == null)
3422 public void ReportUsageError ()
3424 Report.Error (654, loc, "Method `" + DeclaringType + "." +
3425 Name + "()' is referenced without parentheses");
3428 override public void Emit (EmitContext ec)
3430 ReportUsageError ();
3433 public virtual void EmitArguments (EmitContext ec, ArrayList arguments)
3435 Invocation.EmitArguments (ec, best_candidate, arguments, false, null);
3438 public virtual void EmitCall (EmitContext ec, ArrayList arguments)
3440 Invocation.EmitCall (ec, IsBase, InstanceExpression, best_candidate, arguments, loc);
3443 public static bool IsAncestralType (Type first_type, Type second_type)
3445 return first_type != second_type &&
3446 (TypeManager.IsSubclassOf (second_type, first_type) ||
3447 TypeManager.ImplementsInterface (second_type, first_type));
3450 public static bool IsOverride (MethodBase cand_method, MethodBase base_method)
3452 if (!IsAncestralType (base_method.DeclaringType, cand_method.DeclaringType))
3455 ParameterData cand_pd = TypeManager.GetParameterData (cand_method);
3456 ParameterData base_pd = TypeManager.GetParameterData (base_method);
3458 if (cand_pd.Count != base_pd.Count)
3461 for (int j = 0; j < cand_pd.Count; ++j)
3463 Parameter.Modifier cm = cand_pd.ParameterModifier (j);
3464 Parameter.Modifier bm = base_pd.ParameterModifier (j);
3465 Type ct = TypeManager.TypeToCoreType (cand_pd.ParameterType (j));
3466 Type bt = TypeManager.TypeToCoreType (base_pd.ParameterType (j));
3468 if (cm != bm || ct != bt)
3475 public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2, Location loc)
3477 MemberInfo [] miset;
3478 MethodGroupExpr union;
3483 return (MethodGroupExpr) mg2;
3486 return (MethodGroupExpr) mg1;
3489 MethodGroupExpr left_set = null, right_set = null;
3490 int length1 = 0, length2 = 0;
3492 left_set = (MethodGroupExpr) mg1;
3493 length1 = left_set.Methods.Length;
3495 right_set = (MethodGroupExpr) mg2;
3496 length2 = right_set.Methods.Length;
3498 ArrayList common = new ArrayList ();
3500 foreach (MethodBase r in right_set.Methods){
3501 if (TypeManager.ArrayContainsMethod (left_set.Methods, r))
3505 miset = new MemberInfo [length1 + length2 - common.Count];
3506 left_set.Methods.CopyTo (miset, 0);
3510 foreach (MethodBase r in right_set.Methods) {
3511 if (!common.Contains (r))
3515 union = new MethodGroupExpr (miset, loc);
3520 static Type MoreSpecific (Type p, Type q)
3522 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
3524 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
3527 if (TypeManager.HasElementType (p))
3529 Type pe = TypeManager.GetElementType (p);
3530 Type qe = TypeManager.GetElementType (q);
3531 Type specific = MoreSpecific (pe, qe);
3537 else if (TypeManager.IsGenericType (p))
3539 Type[] pargs = TypeManager.GetTypeArguments (p);
3540 Type[] qargs = TypeManager.GetTypeArguments (q);
3542 bool p_specific_at_least_once = false;
3543 bool q_specific_at_least_once = false;
3545 for (int i = 0; i < pargs.Length; i++)
3547 Type specific = MoreSpecific (pargs [i], qargs [i]);
3548 if (specific == pargs [i])
3549 p_specific_at_least_once = true;
3550 if (specific == qargs [i])
3551 q_specific_at_least_once = true;
3554 if (p_specific_at_least_once && !q_specific_at_least_once)
3556 if (!p_specific_at_least_once && q_specific_at_least_once)
3564 /// Find the Applicable Function Members (7.4.2.1)
3566 /// me: Method Group expression with the members to select.
3567 /// it might contain constructors or methods (or anything
3568 /// that maps to a method).
3570 /// Arguments: ArrayList containing resolved Argument objects.
3572 /// loc: The location if we want an error to be reported, or a Null
3573 /// location for "probing" purposes.
3575 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3576 /// that is the best match of me on Arguments.
3579 public virtual MethodGroupExpr OverloadResolve (EmitContext ec, ArrayList Arguments,
3580 bool may_fail, Location loc)
3582 bool method_params = false;
3583 Type applicable_type = null;
3585 ArrayList candidates = new ArrayList (2);
3586 ArrayList candidate_overrides = null;
3589 // Used to keep a map between the candidate
3590 // and whether it is being considered in its
3591 // normal or expanded form
3593 // false is normal form, true is expanded form
3595 Hashtable candidate_to_form = null;
3597 if (Arguments != null)
3598 arg_count = Arguments.Count;
3600 if (RootContext.Version == LanguageVersion.ISO_1 && Name == "Invoke" && TypeManager.IsDelegateType (DeclaringType)) {
3602 Report.Error (1533, loc, "Invoke cannot be called directly on a delegate");
3606 int nmethods = Methods.Length;
3610 // Methods marked 'override' don't take part in 'applicable_type'
3611 // computation, nor in the actual overload resolution.
3612 // However, they still need to be emitted instead of a base virtual method.
3613 // So, we salt them away into the 'candidate_overrides' array.
3615 // In case of reflected methods, we replace each overriding method with
3616 // its corresponding base virtual method. This is to improve compatibility
3617 // with non-C# libraries which change the visibility of overrides (#75636)
3620 for (int i = 0; i < Methods.Length; ++i) {
3621 MethodBase m = Methods [i];
3623 Type [] gen_args = null;
3624 if (m.IsGenericMethod && !m.IsGenericMethodDefinition)
3625 gen_args = m.GetGenericArguments ();
3627 if (TypeManager.IsOverride (m)) {
3628 if (candidate_overrides == null)
3629 candidate_overrides = new ArrayList ();
3630 candidate_overrides.Add (m);
3631 m = TypeManager.TryGetBaseDefinition (m);
3633 if (m != null && gen_args != null) {
3634 if (!m.IsGenericMethodDefinition)
3635 throw new InternalErrorException ("GetBaseDefinition didn't return a GenericMethodDefinition");
3636 m = ((MethodInfo) m).MakeGenericMethod (gen_args);
3646 int applicable_errors = Report.Errors;
3649 // First we construct the set of applicable methods
3651 bool is_sorted = true;
3652 for (int i = 0; i < nmethods; i++) {
3653 Type decl_type = Methods [i].DeclaringType;
3656 // If we have already found an applicable method
3657 // we eliminate all base types (Section 14.5.5.1)
3659 if (applicable_type != null && IsAncestralType (decl_type, applicable_type))
3663 // Check if candidate is applicable (section 14.4.2.1)
3664 // Is candidate applicable in normal form?
3666 bool is_applicable = Invocation.IsApplicable (ec, this, Arguments, arg_count, ref Methods [i]);
3668 if (!is_applicable && Invocation.IsParamsMethodApplicable (ec, this, Arguments, arg_count, ref Methods [i])) {
3669 MethodBase candidate = Methods [i];
3670 if (candidate_to_form == null)
3671 candidate_to_form = new PtrHashtable ();
3672 candidate_to_form [candidate] = candidate;
3673 // Candidate is applicable in expanded form
3674 is_applicable = true;
3680 candidates.Add (Methods [i]);
3682 if (applicable_type == null)
3683 applicable_type = decl_type;
3684 else if (applicable_type != decl_type) {
3686 if (IsAncestralType (applicable_type, decl_type))
3687 applicable_type = decl_type;
3691 if (applicable_errors != Report.Errors)
3694 int candidate_top = candidates.Count;
3696 if (applicable_type == null) {
3697 if (ec.IsInProbingMode)
3701 // Okay so we have failed to find anything so we
3702 // return by providing info about the closest match
3704 int errors = Report.Errors;
3705 for (int i = 0; i < nmethods; ++i) {
3706 MethodBase c = Methods [i];
3707 ParameterData pd = TypeManager.GetParameterData (c);
3709 if (pd.Count != arg_count)
3713 if (!TypeManager.InferTypeArguments (ec, Arguments, ref c))
3715 if (TypeManager.IsGenericMethodDefinition (c))
3719 Invocation.VerifyArgumentsCompat (ec, Arguments, arg_count,
3720 c, false, null, may_fail, loc);
3722 if (!may_fail && errors == Report.Errors){
3724 throw new InternalErrorException (
3725 "VerifyArgumentsCompat and IsApplicable do not agree; " +
3726 "likely reason: ImplicitConversion and ImplicitConversionExists have gone out of sync");
3732 if (!may_fail && errors == Report.Errors) {
3733 string report_name = Name;
3734 if (report_name == ".ctor")
3735 report_name = TypeManager.CSharpName (DeclaringType);
3741 for (int i = 0; i < Methods.Length; ++i) {
3742 MethodBase c = Methods [i];
3743 ParameterData pd = TypeManager.GetParameterData (c);
3745 if (pd.Count != arg_count)
3748 if (TypeManager.InferTypeArguments (ec, Arguments, ref c))
3752 411, loc, "The type arguments for " +
3753 "method `{0}' cannot be inferred from " +
3754 "the usage. Try specifying the type " +
3755 "arguments explicitly", TypeManager.CSharpSignature (c));
3760 Invocation.Error_WrongNumArguments (loc, report_name, arg_count);
3768 // At this point, applicable_type is _one_ of the most derived types
3769 // in the set of types containing the methods in this MethodGroup.
3770 // Filter the candidates so that they only contain methods from the
3771 // most derived types.
3774 int finalized = 0; // Number of finalized candidates
3777 // Invariant: applicable_type is a most derived type
3779 // We'll try to complete Section 14.5.5.1 for 'applicable_type' by
3780 // eliminating all it's base types. At the same time, we'll also move
3781 // every unrelated type to the end of the array, and pick the next
3782 // 'applicable_type'.
3784 Type next_applicable_type = null;
3785 int j = finalized; // where to put the next finalized candidate
3786 int k = finalized; // where to put the next undiscarded candidate
3787 for (int i = finalized; i < candidate_top; ++i) {
3788 MethodBase candidate = (MethodBase) candidates [i];
3789 Type decl_type = candidate.DeclaringType;
3791 if (decl_type == applicable_type) {
3792 candidates [k++] = candidates [j];
3793 candidates [j++] = candidates [i];
3797 if (IsAncestralType (decl_type, applicable_type))
3800 if (next_applicable_type != null &&
3801 IsAncestralType (decl_type, next_applicable_type))
3804 candidates [k++] = candidates [i];
3806 if (next_applicable_type == null ||
3807 IsAncestralType (next_applicable_type, decl_type))
3808 next_applicable_type = decl_type;
3811 applicable_type = next_applicable_type;
3814 } while (applicable_type != null);
3818 // Now we actually find the best method
3821 best_candidate = (MethodBase) candidates [0];
3822 method_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
3823 for (int ix = 1; ix < candidate_top; ix++) {
3824 MethodBase candidate = (MethodBase) candidates [ix];
3826 if (candidate == best_candidate)
3829 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
3831 if (BetterFunction (ec, Arguments, arg_count,
3832 candidate, cand_params,
3833 best_candidate, method_params)) {
3834 best_candidate = candidate;
3835 method_params = cand_params;
3839 // Now check that there are no ambiguities i.e the selected method
3840 // should be better than all the others
3842 MethodBase ambiguous = null;
3843 for (int ix = 0; ix < candidate_top; ix++) {
3844 MethodBase candidate = (MethodBase) candidates [ix];
3846 if (candidate == best_candidate)
3849 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
3850 if (!BetterFunction (ec, Arguments, arg_count,
3851 best_candidate, method_params,
3852 candidate, cand_params))
3855 Report.SymbolRelatedToPreviousError (candidate);
3856 ambiguous = candidate;
3860 if (ambiguous != null) {
3861 Report.SymbolRelatedToPreviousError (best_candidate);
3862 Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
3863 TypeManager.CSharpSignature (ambiguous), TypeManager.CSharpSignature (best_candidate));
3868 // If the method is a virtual function, pick an override closer to the LHS type.
3870 if (!IsBase && best_candidate.IsVirtual) {
3871 if (TypeManager.IsOverride (best_candidate))
3872 throw new InternalErrorException (
3873 "Should not happen. An 'override' method took part in overload resolution: " + best_candidate);
3875 if (candidate_overrides != null)
3876 foreach (MethodBase candidate in candidate_overrides) {
3877 if (IsOverride (candidate, best_candidate))
3878 best_candidate = candidate;
3882 // We can stop here when probing is on
3883 if (ec.IsInProbingMode)
3887 // And now check if the arguments are all
3888 // compatible, perform conversions if
3889 // necessary etc. and return if everything is
3892 if (!Invocation.VerifyArgumentsCompat (ec, Arguments, arg_count, best_candidate,
3893 method_params, null, may_fail, loc))
3896 if (best_candidate == null)
3899 MethodBase the_method = TypeManager.DropGenericMethodArguments (best_candidate);
3901 if (the_method.IsGenericMethodDefinition &&
3902 !ConstraintChecker.CheckConstraints (ec, the_method, best_candidate, loc))
3906 IMethodData data = TypeManager.GetMethod (the_method);
3908 data.SetMemberIsUsed ();
3913 public Expression ResolveGeneric (EmitContext ec, TypeArguments args)
3916 if (!args.Resolve (ec))
3919 Type[] atypes = args.Arguments;
3921 int first_count = 0;
3922 MethodInfo first = null;
3924 ArrayList list = new ArrayList ();
3925 foreach (MethodBase mb in Methods) {
3926 MethodInfo mi = mb as MethodInfo;
3927 if ((mi == null) || !mb.IsGenericMethod)
3930 Type[] gen_params = mb.GetGenericArguments ();
3932 if (first == null) {
3934 first_count = gen_params.Length;
3937 if (gen_params.Length != atypes.Length)
3940 mi = mi.MakeGenericMethod (atypes);
3944 // MS implementation throws NotSupportedException for GetParameters
3945 // on unbaked generic method
3946 Parameters p = TypeManager.GetParameterData (mi) as Parameters;
3949 p.InflateTypes (gen_params, atypes);
3950 TypeManager.RegisterMethod (mi, p);
3955 if (list.Count > 0) {
3956 MethodGroupExpr new_mg = new MethodGroupExpr (list, Location);
3957 new_mg.InstanceExpression = InstanceExpression;
3958 new_mg.HasTypeArguments = true;
3959 new_mg.IsBase = IsBase;
3963 if (first != null) {
3964 Report.SymbolRelatedToPreviousError (first);
3966 305, loc, "Using the generic method `{0}' requires `{1}' type arguments",
3967 TypeManager.CSharpSignature (first), first_count.ToString ());
3970 308, loc, "The non-generic method `{0}' " +
3971 "cannot be used with type arguments", Name);
3975 throw new NotImplementedException ();
3981 /// Fully resolved expression that evaluates to a Field
3983 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariable {
3984 public readonly FieldInfo FieldInfo;
3985 VariableInfo variable_info;
3987 LocalTemporary temp;
3989 bool in_initializer;
3991 public FieldExpr (FieldInfo fi, Location l, bool in_initializer):
3994 this.in_initializer = in_initializer;
3997 public FieldExpr (FieldInfo fi, Location l)
4000 eclass = ExprClass.Variable;
4001 type = TypeManager.TypeToCoreType (fi.FieldType);
4005 public override string Name {
4007 return FieldInfo.Name;
4011 public override bool IsInstance {
4013 return !FieldInfo.IsStatic;
4017 public override bool IsStatic {
4019 return FieldInfo.IsStatic;
4023 public override Type DeclaringType {
4025 return FieldInfo.DeclaringType;
4029 public override string GetSignatureForError ()
4031 return TypeManager.GetFullNameSignature (FieldInfo);
4034 public VariableInfo VariableInfo {
4036 return variable_info;
4040 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
4041 SimpleName original)
4043 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
4045 Type t = fi.FieldType;
4047 if (fi.IsLiteral || (fi.IsInitOnly && t == TypeManager.decimal_type)) {
4048 IConstant ic = TypeManager.GetConstant (fi);
4051 ic = new ExternalConstant (fi);
4053 ic = ExternalConstant.CreateDecimal (fi);
4055 return base.ResolveMemberAccess (ec, left, loc, original);
4058 TypeManager.RegisterConstant (fi, ic);
4061 bool left_is_type = left is TypeExpr;
4062 if (!left_is_type && (original == null || !original.IdenticalNameAndTypeName (ec, left, loc))) {
4063 Report.SymbolRelatedToPreviousError (FieldInfo);
4064 error176 (loc, TypeManager.GetFullNameSignature (FieldInfo));
4068 if (ic.ResolveValue ()) {
4069 if (!ec.IsInObsoleteScope)
4070 ic.CheckObsoleteness (loc);
4073 return ic.CreateConstantReference (loc);
4076 if (t.IsPointer && !ec.InUnsafe) {
4080 return base.ResolveMemberAccess (ec, left, loc, original);
4083 override public Expression DoResolve (EmitContext ec)
4085 return DoResolve (ec, false, false);
4088 Expression DoResolve (EmitContext ec, bool lvalue_instance, bool out_access)
4090 if (!FieldInfo.IsStatic){
4091 if (InstanceExpression == null){
4093 // This can happen when referencing an instance field using
4094 // a fully qualified type expression: TypeName.InstanceField = xxx
4096 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4100 // Resolve the field's instance expression while flow analysis is turned
4101 // off: when accessing a field "a.b", we must check whether the field
4102 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4104 if (lvalue_instance) {
4105 using (ec.With (EmitContext.Flags.DoFlowAnalysis, false)) {
4106 Expression right_side =
4107 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4108 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side, loc);
4111 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
4112 InstanceExpression = InstanceExpression.Resolve (ec, rf);
4115 if (InstanceExpression == null)
4118 InstanceExpression.CheckMarshalByRefAccess ();
4121 if (!in_initializer && !ec.IsFieldInitializer) {
4122 ObsoleteAttribute oa;
4123 FieldBase f = TypeManager.GetField (FieldInfo);
4125 if (!ec.IsInObsoleteScope)
4126 f.CheckObsoleteness (loc);
4128 // To be sure that type is external because we do not register generated fields
4129 } else if (!(FieldInfo.DeclaringType is TypeBuilder)) {
4130 oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
4132 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
4136 AnonymousContainer am = ec.CurrentAnonymousMethod;
4138 if (!FieldInfo.IsStatic){
4139 if (!am.IsIterator && (ec.TypeContainer is Struct)){
4140 Report.Error (1673, loc,
4141 "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",
4148 IFixedBuffer fb = AttributeTester.GetFixedBuffer (FieldInfo);
4150 if (!ec.InFixedInitializer && ec.ContainerType.IsValueType) {
4151 Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4154 if (!(InstanceExpression is LocalVariableReference) &&
4155 !(InstanceExpression is This)) {
4156 Report.SymbolRelatedToPreviousError (FieldInfo);
4157 Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4158 TypeManager.GetFullNameSignature (FieldInfo));
4161 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4164 // If the instance expression is a local variable or parameter.
4165 IVariable var = InstanceExpression as IVariable;
4166 if ((var == null) || (var.VariableInfo == null))
4169 VariableInfo vi = var.VariableInfo;
4170 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
4173 variable_info = vi.GetSubStruct (FieldInfo.Name);
4177 static readonly int [] codes = {
4178 191, // instance, write access
4179 192, // instance, out access
4180 198, // static, write access
4181 199, // static, out access
4182 1648, // member of value instance, write access
4183 1649, // member of value instance, out access
4184 1650, // member of value static, write access
4185 1651 // member of value static, out access
4188 static readonly string [] msgs = {
4189 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4190 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4191 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4192 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4193 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4194 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4195 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4196 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4199 // The return value is always null. Returning a value simplifies calling code.
4200 Expression Report_AssignToReadonly (Expression right_side)
4203 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4207 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4209 Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4214 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4216 IVariable var = InstanceExpression as IVariable;
4217 if ((var != null) && (var.VariableInfo != null))
4218 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
4220 bool lvalue_instance = !FieldInfo.IsStatic && FieldInfo.DeclaringType.IsValueType;
4221 bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
4223 Expression e = DoResolve (ec, lvalue_instance, out_access);
4228 FieldBase fb = TypeManager.GetField (FieldInfo);
4232 if (FieldInfo.IsInitOnly) {
4233 // InitOnly fields can only be assigned in constructors or initializers
4234 if (!ec.IsFieldInitializer && !ec.IsConstructor)
4235 return Report_AssignToReadonly (right_side);
4237 if (ec.IsConstructor) {
4238 Type ctype = ec.TypeContainer.CurrentType;
4240 ctype = ec.ContainerType;
4242 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4243 if (!TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
4244 return Report_AssignToReadonly (right_side);
4245 // static InitOnly fields cannot be assigned-to in an instance constructor
4246 if (IsStatic && !ec.IsStatic)
4247 return Report_AssignToReadonly (right_side);
4248 // instance constructors can't modify InitOnly fields of other instances of the same type
4249 if (!IsStatic && !(InstanceExpression is This))
4250 return Report_AssignToReadonly (right_side);
4254 if (right_side == EmptyExpression.OutAccess &&
4255 !IsStatic && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
4256 Report.SymbolRelatedToPreviousError (DeclaringType);
4257 Report.Warning (197, 1, loc,
4258 "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",
4259 GetSignatureForError ());
4265 public override void CheckMarshalByRefAccess ()
4267 if (!IsStatic && Type.IsValueType && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
4268 Report.SymbolRelatedToPreviousError (DeclaringType);
4269 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",
4270 GetSignatureForError ());
4274 public bool VerifyFixed ()
4276 IVariable variable = InstanceExpression as IVariable;
4277 // A variable of the form V.I is fixed when V is a fixed variable of a struct type.
4278 // We defer the InstanceExpression check after the variable check to avoid a
4279 // separate null check on InstanceExpression.
4280 return variable != null && InstanceExpression.Type.IsValueType && variable.VerifyFixed ();
4283 public override int GetHashCode ()
4285 return FieldInfo.GetHashCode ();
4288 public override bool Equals (object obj)
4290 FieldExpr fe = obj as FieldExpr;
4294 if (FieldInfo != fe.FieldInfo)
4297 if (InstanceExpression == null || fe.InstanceExpression == null)
4300 return InstanceExpression.Equals (fe.InstanceExpression);
4303 public void Emit (EmitContext ec, bool leave_copy)
4305 ILGenerator ig = ec.ig;
4306 bool is_volatile = false;
4308 FieldBase f = TypeManager.GetField (FieldInfo);
4310 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4313 f.SetMemberIsUsed ();
4316 if (FieldInfo.IsStatic){
4318 ig.Emit (OpCodes.Volatile);
4320 ig.Emit (OpCodes.Ldsfld, FieldInfo);
4323 EmitInstance (ec, false);
4325 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
4327 ig.Emit (OpCodes.Ldflda, FieldInfo);
4328 ig.Emit (OpCodes.Ldflda, ff.Element);
4331 ig.Emit (OpCodes.Volatile);
4333 ig.Emit (OpCodes.Ldfld, FieldInfo);
4338 ec.ig.Emit (OpCodes.Dup);
4339 if (!FieldInfo.IsStatic) {
4340 temp = new LocalTemporary (this.Type);
4346 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4348 FieldAttributes fa = FieldInfo.Attributes;
4349 bool is_static = (fa & FieldAttributes.Static) != 0;
4350 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
4351 ILGenerator ig = ec.ig;
4352 prepared = prepare_for_load;
4354 if (is_readonly && !ec.IsConstructor){
4355 Report_AssignToReadonly (source);
4359 EmitInstance (ec, prepare_for_load);
4363 ec.ig.Emit (OpCodes.Dup);
4364 if (!FieldInfo.IsStatic) {
4365 temp = new LocalTemporary (this.Type);
4370 FieldBase f = TypeManager.GetField (FieldInfo);
4372 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4373 ig.Emit (OpCodes.Volatile);
4379 ig.Emit (OpCodes.Stsfld, FieldInfo);
4381 ig.Emit (OpCodes.Stfld, FieldInfo);
4389 public override void Emit (EmitContext ec)
4394 public void AddressOf (EmitContext ec, AddressOp mode)
4396 ILGenerator ig = ec.ig;
4398 FieldBase f = TypeManager.GetField (FieldInfo);
4400 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
4401 Report.Warning (420, 1, loc, "`{0}': A volatile field references will not be treated as volatile",
4402 f.GetSignatureForError ());
4405 if ((mode & AddressOp.Store) != 0)
4407 if ((mode & AddressOp.Load) != 0)
4408 f.SetMemberIsUsed ();
4412 // Handle initonly fields specially: make a copy and then
4413 // get the address of the copy.
4416 if (FieldInfo.IsInitOnly){
4418 if (ec.IsConstructor){
4419 if (FieldInfo.IsStatic){
4431 local = ig.DeclareLocal (type);
4432 ig.Emit (OpCodes.Stloc, local);
4433 ig.Emit (OpCodes.Ldloca, local);
4438 if (FieldInfo.IsStatic){
4439 ig.Emit (OpCodes.Ldsflda, FieldInfo);
4442 EmitInstance (ec, false);
4443 ig.Emit (OpCodes.Ldflda, FieldInfo);
4449 // A FieldExpr whose address can not be taken
4451 public class FieldExprNoAddress : FieldExpr, IMemoryLocation {
4452 public FieldExprNoAddress (FieldInfo fi, Location loc) : base (fi, loc)
4456 public new void AddressOf (EmitContext ec, AddressOp mode)
4458 Report.Error (-215, "Report this: Taking the address of a remapped parameter not supported");
4463 /// Expression that evaluates to a Property. The Assign class
4464 /// might set the `Value' expression if we are in an assignment.
4466 /// This is not an LValue because we need to re-write the expression, we
4467 /// can not take data from the stack and store it.
4469 public class PropertyExpr : MemberExpr, IAssignMethod {
4470 public readonly PropertyInfo PropertyInfo;
4473 // This is set externally by the `BaseAccess' class
4476 MethodInfo getter, setter;
4481 LocalTemporary temp;
4484 public PropertyExpr (Type containerType, PropertyInfo pi, Location l)
4487 eclass = ExprClass.PropertyAccess;
4491 type = TypeManager.TypeToCoreType (pi.PropertyType);
4493 ResolveAccessors (containerType);
4496 public override string Name {
4498 return PropertyInfo.Name;
4502 public override bool IsInstance {
4508 public override bool IsStatic {
4514 public override Type DeclaringType {
4516 return PropertyInfo.DeclaringType;
4520 public override string GetSignatureForError ()
4522 return TypeManager.GetFullNameSignature (PropertyInfo);
4525 void FindAccessors (Type invocation_type)
4527 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
4528 BindingFlags.Static | BindingFlags.Instance |
4529 BindingFlags.DeclaredOnly;
4531 Type current = PropertyInfo.DeclaringType;
4532 for (; current != null; current = current.BaseType) {
4533 MemberInfo[] group = TypeManager.MemberLookup (
4534 invocation_type, invocation_type, current,
4535 MemberTypes.Property, flags, PropertyInfo.Name, null);
4540 if (group.Length != 1)
4541 // Oooops, can this ever happen ?
4544 PropertyInfo pi = (PropertyInfo) group [0];
4547 getter = pi.GetGetMethod (true);
4550 setter = pi.GetSetMethod (true);
4552 MethodInfo accessor = getter != null ? getter : setter;
4554 if (!accessor.IsVirtual)
4560 // We also perform the permission checking here, as the PropertyInfo does not
4561 // hold the information for the accessibility of its setter/getter
4563 // TODO: Refactor to use some kind of cache together with GetPropertyFromAccessor
4564 void ResolveAccessors (Type containerType)
4566 FindAccessors (containerType);
4568 if (getter != null) {
4569 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
4570 IMethodData md = TypeManager.GetMethod (the_getter);
4572 md.SetMemberIsUsed ();
4574 is_static = getter.IsStatic;
4577 if (setter != null) {
4578 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
4579 IMethodData md = TypeManager.GetMethod (the_setter);
4581 md.SetMemberIsUsed ();
4583 is_static = setter.IsStatic;
4587 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
4590 InstanceExpression = null;
4594 if (InstanceExpression == null) {
4595 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4599 InstanceExpression = InstanceExpression.DoResolve (ec);
4600 if (lvalue_instance && InstanceExpression != null)
4601 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
4603 if (InstanceExpression == null)
4606 InstanceExpression.CheckMarshalByRefAccess ();
4608 if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) &&
4609 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
4610 !TypeManager.IsNestedChildOf (ec.ContainerType, InstanceExpression.Type) &&
4611 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.ContainerType)) {
4612 Report.SymbolRelatedToPreviousError (PropertyInfo);
4613 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
4620 void Error_PropertyNotFound (MethodInfo mi, bool getter)
4622 // TODO: correctly we should compare arguments but it will lead to bigger changes
4623 if (mi is MethodBuilder) {
4624 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
4628 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
4630 ParameterData iparams = TypeManager.GetParameterData (mi);
4631 sig.Append (getter ? "get_" : "set_");
4633 sig.Append (iparams.GetSignatureForError ());
4635 Report.SymbolRelatedToPreviousError (mi);
4636 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
4637 Name, sig.ToString ());
4640 override public Expression DoResolve (EmitContext ec)
4645 if (getter != null){
4646 if (TypeManager.GetParameterData (getter).Count != 0){
4647 Error_PropertyNotFound (getter, true);
4652 if (getter == null){
4654 // The following condition happens if the PropertyExpr was
4655 // created, but is invalid (ie, the property is inaccessible),
4656 // and we did not want to embed the knowledge about this in
4657 // the caller routine. This only avoids double error reporting.
4662 if (InstanceExpression != EmptyExpression.Null) {
4663 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
4664 TypeManager.GetFullNameSignature (PropertyInfo));
4669 bool must_do_cs1540_check = false;
4670 if (getter != null &&
4671 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
4672 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
4673 if (pm != null && pm.HasCustomAccessModifier) {
4674 Report.SymbolRelatedToPreviousError (pm);
4675 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
4676 TypeManager.CSharpSignature (getter));
4679 Report.SymbolRelatedToPreviousError (getter);
4680 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
4685 if (!InstanceResolve (ec, false, must_do_cs1540_check))
4689 // Only base will allow this invocation to happen.
4691 if (IsBase && getter.IsAbstract) {
4692 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
4696 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
4706 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4708 if (right_side == EmptyExpression.OutAccess) {
4709 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
4710 GetSignatureForError ());
4714 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
4715 Report.Error (1612, loc, "Cannot modify the return value of `{0}' because it is not a variable",
4716 GetSignatureForError ());
4720 if (setter == null){
4722 // The following condition happens if the PropertyExpr was
4723 // created, but is invalid (ie, the property is inaccessible),
4724 // and we did not want to embed the knowledge about this in
4725 // the caller routine. This only avoids double error reporting.
4729 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
4730 GetSignatureForError ());
4734 if (TypeManager.GetParameterData (setter).Count != 1){
4735 Error_PropertyNotFound (setter, false);
4739 bool must_do_cs1540_check;
4740 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
4741 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
4742 if (pm != null && pm.HasCustomAccessModifier) {
4743 Report.SymbolRelatedToPreviousError (pm);
4744 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
4745 TypeManager.CSharpSignature (setter));
4748 Report.SymbolRelatedToPreviousError (setter);
4749 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
4754 if (!InstanceResolve (ec, PropertyInfo.DeclaringType.IsValueType, must_do_cs1540_check))
4758 // Only base will allow this invocation to happen.
4760 if (IsBase && setter.IsAbstract){
4761 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
4768 public override void Emit (EmitContext ec)
4773 public void Emit (EmitContext ec, bool leave_copy)
4776 // Special case: length of single dimension array property is turned into ldlen
4778 if ((getter == TypeManager.system_int_array_get_length) ||
4779 (getter == TypeManager.int_array_get_length)){
4780 Type iet = InstanceExpression.Type;
4783 // System.Array.Length can be called, but the Type does not
4784 // support invoking GetArrayRank, so test for that case first
4786 if (iet != TypeManager.array_type && (iet.GetArrayRank () == 1)) {
4788 EmitInstance (ec, false);
4789 ec.ig.Emit (OpCodes.Ldlen);
4790 ec.ig.Emit (OpCodes.Conv_I4);
4795 Invocation.EmitCall (ec, IsBase, InstanceExpression, getter, null, loc, prepared, false);
4798 ec.ig.Emit (OpCodes.Dup);
4800 temp = new LocalTemporary (this.Type);
4807 // Implements the IAssignMethod interface for assignments
4809 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4811 Expression my_source = source;
4813 prepared = prepare_for_load;
4818 ec.ig.Emit (OpCodes.Dup);
4820 temp = new LocalTemporary (this.Type);
4824 } else if (leave_copy) {
4827 temp = new LocalTemporary (this.Type);
4833 ArrayList args = new ArrayList (1);
4834 args.Add (new Argument (my_source, Argument.AType.Expression));
4836 Invocation.EmitCall (ec, IsBase, InstanceExpression, setter, args, loc, false, prepared);
4846 /// Fully resolved expression that evaluates to an Event
4848 public class EventExpr : MemberExpr {
4849 public readonly EventInfo EventInfo;
4853 MethodInfo add_accessor, remove_accessor;
4855 public EventExpr (EventInfo ei, Location loc)
4859 eclass = ExprClass.EventAccess;
4861 add_accessor = TypeManager.GetAddMethod (ei);
4862 remove_accessor = TypeManager.GetRemoveMethod (ei);
4863 if (add_accessor.IsStatic || remove_accessor.IsStatic)
4866 if (EventInfo is MyEventBuilder){
4867 MyEventBuilder eb = (MyEventBuilder) EventInfo;
4868 type = eb.EventType;
4871 type = EventInfo.EventHandlerType;
4874 public override string Name {
4876 return EventInfo.Name;
4880 public override bool IsInstance {
4886 public override bool IsStatic {
4892 public override Type DeclaringType {
4894 return EventInfo.DeclaringType;
4898 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
4899 SimpleName original)
4902 // If the event is local to this class, we transform ourselves into a FieldExpr
4905 if (EventInfo.DeclaringType == ec.ContainerType ||
4906 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
4907 EventField mi = TypeManager.GetEventField (EventInfo);
4910 if (!ec.IsInObsoleteScope)
4911 mi.CheckObsoleteness (loc);
4913 FieldExpr ml = new FieldExpr (mi.FieldBuilder, loc);
4915 InstanceExpression = null;
4917 return ml.ResolveMemberAccess (ec, left, loc, original);
4921 return base.ResolveMemberAccess (ec, left, loc, original);
4925 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
4928 InstanceExpression = null;
4932 if (InstanceExpression == null) {
4933 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4937 InstanceExpression = InstanceExpression.DoResolve (ec);
4938 if (InstanceExpression == null)
4941 if (IsBase && add_accessor.IsAbstract) {
4942 Error_CannotCallAbstractBase(TypeManager.CSharpSignature(add_accessor));
4947 // This is using the same mechanism as the CS1540 check in PropertyExpr.
4948 // However, in the Event case, we reported a CS0122 instead.
4950 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
4951 InstanceExpression.Type != ec.ContainerType &&
4952 ec.ContainerType.IsSubclassOf (InstanceExpression.Type)) {
4953 Report.SymbolRelatedToPreviousError (EventInfo);
4954 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
4961 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
4963 return DoResolve (ec);
4966 public override Expression DoResolve (EmitContext ec)
4968 bool must_do_cs1540_check;
4969 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
4970 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
4971 Report.SymbolRelatedToPreviousError (EventInfo);
4972 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
4976 if (!InstanceResolve (ec, must_do_cs1540_check))
4982 public override void Emit (EmitContext ec)
4984 if (InstanceExpression is This)
4985 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of += or -=", GetSignatureForError ());
4987 Report.Error (70, loc, "The event `{0}' can only appear on the left hand side of += or -= "+
4988 "(except on the defining type)", Name);
4991 public override string GetSignatureForError ()
4993 return TypeManager.CSharpSignature (EventInfo);
4996 public void EmitAddOrRemove (EmitContext ec, Expression source)
4998 BinaryDelegate source_del = source as BinaryDelegate;
4999 if (source_del == null) {
5003 Expression handler = source_del.Right;
5005 Argument arg = new Argument (handler, Argument.AType.Expression);
5006 ArrayList args = new ArrayList ();
5010 if (source_del.IsAddition)
5011 Invocation.EmitCall (
5012 ec, IsBase, InstanceExpression, add_accessor, args, loc);
5014 Invocation.EmitCall (
5015 ec, IsBase, InstanceExpression, remove_accessor, args, loc);
5019 public class TemporaryVariable : Expression, IMemoryLocation
5024 public TemporaryVariable (Type type, Location loc)
5028 eclass = ExprClass.Value;
5031 public override Expression DoResolve (EmitContext ec)
5036 TypeExpr te = new TypeExpression (type, loc);
5037 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
5038 if (!li.Resolve (ec))
5041 if (ec.MustCaptureVariable (li)) {
5042 ScopeInfo scope = li.Block.CreateScopeInfo ();
5043 var = scope.AddLocal (li);
5050 public Variable Variable {
5051 get { return var != null ? var : li.Variable; }
5054 public override void Emit (EmitContext ec)
5056 Variable.EmitInstance (ec);
5060 public void EmitLoadAddress (EmitContext ec)
5062 Variable.EmitInstance (ec);
5063 Variable.EmitAddressOf (ec);
5066 public void Store (EmitContext ec, Expression right_side)
5068 Variable.EmitInstance (ec);
5069 right_side.Emit (ec);
5070 Variable.EmitAssign (ec);
5073 public void EmitThis (EmitContext ec)
5075 Variable.EmitInstance (ec);
5078 public void EmitStore (EmitContext ec)
5080 Variable.EmitAssign (ec);
5083 public void AddressOf (EmitContext ec, AddressOp mode)
5085 EmitLoadAddress (ec);
5090 /// Handles `var' contextual keyword; var becomes a keyword only
5091 /// if no type called var exists in a variable scope
5093 public class VarExpr : SimpleName
5095 // Used for error reporting only
5096 ArrayList initializer;
5098 public VarExpr (string name, Location loc)
5103 public ArrayList VariableInitializer {
5105 this.initializer = value;
5109 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5112 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
5114 type = right_side.Type;
5115 if (type == TypeManager.null_type || type == TypeManager.void_type || type == TypeManager.anonymous_method_type) {
5116 Report.Error (815, loc, "An implicitly typed local variable declaration cannot be initialized with `{0}'",
5117 right_side.GetSignatureForError ());
5121 eclass = ExprClass.Variable;
5125 protected override void Error_TypeOrNamespaceNotFound (IResolveContext ec)
5127 if (ec is FieldBase) {
5128 Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");
5132 base.Error_TypeOrNamespaceNotFound (ec);
5135 public override TypeExpr ResolveAsContextualType (IResolveContext rc, bool silent)
5137 TypeExpr te = base.ResolveAsContextualType (rc, true);
5141 if (initializer == null)
5144 // TODO: refactor, the error is reported too many times
5145 if (initializer.Count > 1) {
5146 Location loc = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [1]).Location;
5147 Report.Error (819, loc, "An implicitly typed local variable declaration cannot include multiple declarators");
5151 Expression variable_initializer = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [0]).expression_or_array_initializer;
5152 if (variable_initializer == null) {
5153 Report.Error (818, loc, "An implicitly typed local variable declarator must include an initializer");