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, fullname);
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
2720 /// Represents an "unbound generic type", ie. typeof (Foo<>).
2723 public class UnboundTypeExpression : TypeExpr
2727 public UnboundTypeExpression (MemberName name, Location l)
2733 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2736 if (name.Left != null) {
2737 Expression lexpr = name.Left.GetTypeExpression ();
2738 expr = new MemberAccess (lexpr, name.Basename);
2740 expr = new SimpleName (name.Basename, loc);
2743 FullNamedExpression fne = expr.ResolveAsTypeStep (ec, false);
2748 return new TypeExpression (type, loc);
2751 public override string Name {
2752 get { return name.FullName; }
2755 public override string FullName {
2756 get { return name.FullName; }
2760 public class TypeAliasExpression : TypeExpr {
2761 FullNamedExpression alias;
2766 public TypeAliasExpression (FullNamedExpression alias, TypeArguments args, Location l)
2772 eclass = ExprClass.Type;
2774 name = alias.FullName + "<" + args.ToString () + ">";
2776 name = alias.FullName;
2779 public override string Name {
2780 get { return alias.FullName; }
2783 public override string FullName {
2784 get { return name; }
2787 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2789 texpr = alias.ResolveAsTypeTerminal (ec, false);
2793 Type type = texpr.Type;
2794 int num_args = TypeManager.GetNumberOfTypeArguments (type);
2797 if (num_args == 0) {
2798 Report.Error (308, loc,
2799 "The non-generic type `{0}' cannot " +
2800 "be used with type arguments.",
2801 TypeManager.CSharpName (type));
2805 ConstructedType ctype = new ConstructedType (type, args, loc);
2806 return ctype.ResolveAsTypeTerminal (ec, false);
2807 } else if (num_args > 0) {
2808 Report.Error (305, loc,
2809 "Using the generic type `{0}' " +
2810 "requires {1} type arguments",
2811 TypeManager.CSharpName (type), num_args.ToString ());
2818 public override bool CheckAccessLevel (DeclSpace ds)
2820 return texpr.CheckAccessLevel (ds);
2823 public override bool AsAccessible (DeclSpace ds, int flags)
2825 return texpr.AsAccessible (ds, flags);
2828 public override bool IsClass {
2829 get { return texpr.IsClass; }
2832 public override bool IsValueType {
2833 get { return texpr.IsValueType; }
2836 public override bool IsInterface {
2837 get { return texpr.IsInterface; }
2840 public override bool IsSealed {
2841 get { return texpr.IsSealed; }
2846 /// This class denotes an expression which evaluates to a member
2847 /// of a struct or a class.
2849 public abstract class MemberExpr : Expression
2852 /// The name of this member.
2854 public abstract string Name {
2859 /// Whether this is an instance member.
2861 public abstract bool IsInstance {
2866 /// Whether this is a static member.
2868 public abstract bool IsStatic {
2873 /// The type which declares this member.
2875 public abstract Type DeclaringType {
2880 /// The instance expression associated with this member, if it's a
2881 /// non-static member.
2883 public Expression InstanceExpression;
2885 public static void error176 (Location loc, string name)
2887 Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
2888 "with an instance reference, qualify it with a type name instead", name);
2891 // TODO: possible optimalization
2892 // Cache resolved constant result in FieldBuilder <-> expression map
2893 public virtual Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
2894 SimpleName original)
2898 // original == null || original.Resolve (...) ==> left
2901 if (left is TypeExpr) {
2902 left = left.ResolveAsTypeTerminal (ec, true);
2907 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
2914 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
2917 error176 (loc, GetSignatureForError ());
2921 InstanceExpression = left;
2926 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
2931 if (InstanceExpression == EmptyExpression.Null) {
2932 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
2936 if (InstanceExpression.Type.IsValueType) {
2937 if (InstanceExpression is IMemoryLocation) {
2938 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
2940 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
2941 InstanceExpression.Emit (ec);
2943 t.AddressOf (ec, AddressOp.Store);
2946 InstanceExpression.Emit (ec);
2948 if (prepare_for_load)
2949 ec.ig.Emit (OpCodes.Dup);
2954 /// Represents group of extension methods
2956 public class ExtensionMethodGroupExpr : MethodGroupExpr
2958 readonly NamespaceEntry namespaceEntry;
2959 public Expression ExtensionExpression;
2961 public ExtensionMethodGroupExpr (ArrayList list, NamespaceEntry n, Type extensionType, Location l)
2964 this.namespaceEntry = n;
2965 this.type = extensionType;
2968 public override bool IsBase {
2969 get { return true; }
2972 public override bool IsStatic {
2973 get { return true; }
2976 public bool IsTopLevel {
2977 get { return namespaceEntry == null; }
2980 public override void EmitArguments (EmitContext ec, ArrayList arguments)
2982 if (arguments == null)
2983 arguments = new ArrayList (1);
2984 arguments.Insert (0, new Argument (ExtensionExpression));
2985 base.EmitArguments (ec, arguments);
2988 public override void EmitCall (EmitContext ec, ArrayList arguments)
2990 if (arguments == null)
2991 arguments = new ArrayList (1);
2992 arguments.Insert (0, new Argument (ExtensionExpression));
2993 base.EmitCall (ec, arguments);
2996 public override MethodGroupExpr OverloadResolve (EmitContext ec, ArrayList arguments, bool may_fail, Location loc)
2998 if ((ExtensionExpression.eclass & (ExprClass.Value | ExprClass.Variable)) == 0)
2999 return base.OverloadResolve (ec, arguments, may_fail, loc);
3001 if (arguments == null)
3002 arguments = new ArrayList (1);
3004 arguments.Insert (0, new Argument (ExtensionExpression));
3005 MethodGroupExpr mg = ResolveOverloadExtensions (ec, arguments, namespaceEntry, loc);
3007 // Restore original arguments
3008 arguments.RemoveAt (0);
3014 return base.OverloadResolve (ec, arguments, may_fail, loc);
3019 MethodGroupExpr ResolveOverloadExtensions (EmitContext ec, ArrayList arguments, NamespaceEntry ns, Location loc)
3021 // Use normal resolve rules
3022 MethodGroupExpr mg = base.OverloadResolve (ec, arguments, true, loc);
3027 ExtensionMethodGroupExpr e = ns.LookupExtensionMethod (type, null, Name);
3031 e.ExtensionExpression = ExtensionExpression;
3032 return e.ResolveOverloadExtensions (ec, arguments, e.namespaceEntry, loc);
3037 /// MethodGroupExpr represents a group of method candidates which
3038 /// can be resolved to the best method overload
3040 public class MethodGroupExpr : MemberExpr {
3041 public readonly MethodBase [] Methods;
3042 MethodBase best_candidate;
3043 bool has_type_arguments;
3044 bool identical_type_name;
3047 public MethodGroupExpr (MemberInfo [] mi, Location l)
3049 Methods = new MethodBase [mi.Length];
3050 mi.CopyTo (Methods, 0);
3051 eclass = ExprClass.MethodGroup;
3053 // Set the type to something that will never be useful, which will
3054 // trigger the proper conversions.
3055 type = typeof (MethodGroupExpr);
3059 public MethodGroupExpr (ArrayList list, Location l)
3062 Methods = (MethodBase[])list.ToArray (typeof (MethodBase));
3064 foreach (MemberInfo m in list){
3065 if (!(m is MethodBase)){
3066 Console.WriteLine ("Name " + m.Name);
3067 Console.WriteLine ("Found a: " + m.GetType ().FullName);
3074 eclass = ExprClass.MethodGroup;
3075 type = TypeManager.object_type;
3078 public override Type DeclaringType {
3081 // We assume that the top-level type is in the end
3083 return Methods [Methods.Length - 1].DeclaringType;
3084 //return Methods [0].DeclaringType;
3088 public bool HasTypeArguments {
3090 return has_type_arguments;
3094 has_type_arguments = value;
3098 public bool IdenticalTypeName {
3100 return identical_type_name;
3104 identical_type_name = value;
3108 public virtual bool IsBase {
3117 public override string GetSignatureForError ()
3119 if (best_candidate != null)
3120 return TypeManager.CSharpSignature (best_candidate);
3122 return TypeManager.CSharpSignature (Methods [0]);
3125 public override string Name {
3127 return Methods [0].Name;
3131 public override bool IsInstance {
3133 foreach (MethodBase mb in Methods)
3141 public override bool IsStatic {
3143 foreach (MethodBase mb in Methods)
3151 public static explicit operator ConstructorInfo (MethodGroupExpr mg)
3153 return (ConstructorInfo)mg.best_candidate;
3156 public static explicit operator MethodInfo (MethodGroupExpr mg)
3158 return (MethodInfo)mg.best_candidate;
3162 /// Determines "better conversion" as specified in 14.4.2.3
3164 /// Returns : p if a->p is better,
3165 /// q if a->q is better,
3166 /// null if neither is better
3168 static Type BetterConversion (EmitContext ec, Argument a, Type p, Type q)
3170 Type argument_type = TypeManager.TypeToCoreType (a.Type);
3171 Expression argument_expr = a.Expr;
3173 if (argument_type == null)
3174 throw new Exception ("Expression of type " + a.Expr +
3175 " does not resolve its type");
3177 if (p == null || q == null)
3178 throw new InternalErrorException ("BetterConversion Got a null conversion");
3183 if (argument_expr is NullLiteral)
3186 // If the argument is null and one of the types to compare is 'object' and
3187 // the other is a reference type, we prefer the other.
3189 // This follows from the usual rules:
3190 // * There is an implicit conversion from 'null' to type 'object'
3191 // * There is an implicit conversion from 'null' to any reference type
3192 // * There is an implicit conversion from any reference type to type 'object'
3193 // * There is no implicit conversion from type 'object' to other reference types
3194 // => Conversion of 'null' to a reference type is better than conversion to 'object'
3196 // FIXME: This probably isn't necessary, since the type of a NullLiteral is the
3197 // null type. I think it used to be 'object' and thus needed a special
3198 // case to avoid the immediately following two checks.
3200 if (!p.IsValueType && q == TypeManager.object_type)
3202 if (!q.IsValueType && p == TypeManager.object_type)
3206 if (argument_type == p)
3209 if (argument_type == q)
3212 Expression p_tmp = new EmptyExpression (p);
3213 Expression q_tmp = new EmptyExpression (q);
3215 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3216 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3218 if (p_to_q && !q_to_p)
3221 if (q_to_p && !p_to_q)
3224 if (p == TypeManager.sbyte_type)
3225 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3226 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3228 if (q == TypeManager.sbyte_type)
3229 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3230 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3233 if (p == TypeManager.short_type)
3234 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3235 q == TypeManager.uint64_type)
3237 if (q == TypeManager.short_type)
3238 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3239 p == TypeManager.uint64_type)
3242 if (p == TypeManager.int32_type)
3243 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3245 if (q == TypeManager.int32_type)
3246 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3249 if (p == TypeManager.int64_type)
3250 if (q == TypeManager.uint64_type)
3252 if (q == TypeManager.int64_type)
3253 if (p == TypeManager.uint64_type)
3260 /// Determines "Better function" between candidate
3261 /// and the current best match
3264 /// Returns a boolean indicating :
3265 /// false if candidate ain't better
3266 /// true if candidate is better than the current best match
3268 static bool BetterFunction (EmitContext ec, ArrayList args, int argument_count,
3269 MethodBase candidate, bool candidate_params,
3270 MethodBase best, bool best_params)
3272 ParameterData candidate_pd = TypeManager.GetParameterData (candidate);
3273 ParameterData best_pd = TypeManager.GetParameterData (best);
3275 bool better_at_least_one = false;
3277 for (int j = 0, c_idx = 0, b_idx = 0; j < argument_count; ++j, ++c_idx, ++b_idx)
3279 Argument a = (Argument) args [j];
3281 Type ct = TypeManager.TypeToCoreType (candidate_pd.ParameterType (c_idx));
3282 Type bt = TypeManager.TypeToCoreType (best_pd.ParameterType (b_idx));
3284 if (candidate_params && candidate_pd.ParameterModifier (c_idx) == Parameter.Modifier.PARAMS)
3286 ct = TypeManager.GetElementType (ct);
3290 if (best_params && best_pd.ParameterModifier (b_idx) == Parameter.Modifier.PARAMS)
3292 bt = TypeManager.GetElementType (bt);
3300 Type better = BetterConversion (ec, a, ct, bt);
3302 // for each argument, the conversion to 'ct' should be no worse than
3303 // the conversion to 'bt'.
3307 // for at least one argument, the conversion to 'ct' should be better than
3308 // the conversion to 'bt'.
3310 better_at_least_one = true;
3313 if (better_at_least_one)
3317 // This handles the case
3319 // Add (float f1, float f2, float f3);
3320 // Add (params decimal [] foo);
3322 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3323 // first candidate would've chosen as better.
3329 // The two methods have equal parameter types. Now apply tie-breaking rules
3331 if (TypeManager.IsGenericMethod (best) && !TypeManager.IsGenericMethod (candidate))
3333 if (!TypeManager.IsGenericMethod (best) && TypeManager.IsGenericMethod (candidate))
3337 // This handles the following cases:
3339 // Trim () is better than Trim (params char[] chars)
3340 // Concat (string s1, string s2, string s3) is better than
3341 // Concat (string s1, params string [] srest)
3342 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3344 if (!candidate_params && best_params)
3346 if (candidate_params && !best_params)
3349 int candidate_param_count = candidate_pd.Count;
3350 int best_param_count = best_pd.Count;
3352 if (candidate_param_count != best_param_count)
3353 // can only happen if (candidate_params && best_params)
3354 return candidate_param_count > best_param_count;
3357 // now, both methods have the same number of parameters, and the parameters have the same types
3358 // Pick the "more specific" signature
3361 MethodBase orig_candidate = TypeManager.DropGenericMethodArguments (candidate);
3362 MethodBase orig_best = TypeManager.DropGenericMethodArguments (best);
3364 ParameterData orig_candidate_pd = TypeManager.GetParameterData (orig_candidate);
3365 ParameterData orig_best_pd = TypeManager.GetParameterData (orig_best);
3367 bool specific_at_least_once = false;
3368 for (int j = 0; j < candidate_param_count; ++j)
3370 Type ct = TypeManager.TypeToCoreType (orig_candidate_pd.ParameterType (j));
3371 Type bt = TypeManager.TypeToCoreType (orig_best_pd.ParameterType (j));
3374 Type specific = MoreSpecific (ct, bt);
3378 specific_at_least_once = true;
3381 if (specific_at_least_once)
3384 // FIXME: handle lifted operators
3390 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3391 SimpleName original)
3393 if (!(left is TypeExpr) &&
3394 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3395 IdenticalTypeName = true;
3397 return base.ResolveMemberAccess (ec, left, loc, original);
3400 override public Expression DoResolve (EmitContext ec)
3402 if (InstanceExpression != null) {
3403 InstanceExpression = InstanceExpression.DoResolve (ec);
3404 if (InstanceExpression == null)
3411 public void ReportUsageError ()
3413 Report.Error (654, loc, "Method `" + DeclaringType + "." +
3414 Name + "()' is referenced without parentheses");
3417 override public void Emit (EmitContext ec)
3419 ReportUsageError ();
3422 public virtual void EmitArguments (EmitContext ec, ArrayList arguments)
3424 Invocation.EmitArguments (ec, best_candidate, arguments, false, null);
3427 public virtual void EmitCall (EmitContext ec, ArrayList arguments)
3429 Invocation.EmitCall (ec, IsBase, InstanceExpression, best_candidate, arguments, loc);
3432 public static bool IsAncestralType (Type first_type, Type second_type)
3434 return first_type != second_type &&
3435 (TypeManager.IsSubclassOf (second_type, first_type) ||
3436 TypeManager.ImplementsInterface (second_type, first_type));
3439 public static bool IsOverride (MethodBase cand_method, MethodBase base_method)
3441 if (!IsAncestralType (base_method.DeclaringType, cand_method.DeclaringType))
3444 ParameterData cand_pd = TypeManager.GetParameterData (cand_method);
3445 ParameterData base_pd = TypeManager.GetParameterData (base_method);
3447 if (cand_pd.Count != base_pd.Count)
3450 for (int j = 0; j < cand_pd.Count; ++j)
3452 Parameter.Modifier cm = cand_pd.ParameterModifier (j);
3453 Parameter.Modifier bm = base_pd.ParameterModifier (j);
3454 Type ct = TypeManager.TypeToCoreType (cand_pd.ParameterType (j));
3455 Type bt = TypeManager.TypeToCoreType (base_pd.ParameterType (j));
3457 if (cm != bm || ct != bt)
3464 public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2, Location loc)
3466 MemberInfo [] miset;
3467 MethodGroupExpr union;
3472 return (MethodGroupExpr) mg2;
3475 return (MethodGroupExpr) mg1;
3478 MethodGroupExpr left_set = null, right_set = null;
3479 int length1 = 0, length2 = 0;
3481 left_set = (MethodGroupExpr) mg1;
3482 length1 = left_set.Methods.Length;
3484 right_set = (MethodGroupExpr) mg2;
3485 length2 = right_set.Methods.Length;
3487 ArrayList common = new ArrayList ();
3489 foreach (MethodBase r in right_set.Methods){
3490 if (TypeManager.ArrayContainsMethod (left_set.Methods, r))
3494 miset = new MemberInfo [length1 + length2 - common.Count];
3495 left_set.Methods.CopyTo (miset, 0);
3499 foreach (MethodBase r in right_set.Methods) {
3500 if (!common.Contains (r))
3504 union = new MethodGroupExpr (miset, loc);
3509 static Type MoreSpecific (Type p, Type q)
3511 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
3513 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
3516 if (TypeManager.HasElementType (p))
3518 Type pe = TypeManager.GetElementType (p);
3519 Type qe = TypeManager.GetElementType (q);
3520 Type specific = MoreSpecific (pe, qe);
3526 else if (TypeManager.IsGenericType (p))
3528 Type[] pargs = TypeManager.GetTypeArguments (p);
3529 Type[] qargs = TypeManager.GetTypeArguments (q);
3531 bool p_specific_at_least_once = false;
3532 bool q_specific_at_least_once = false;
3534 for (int i = 0; i < pargs.Length; i++)
3536 Type specific = MoreSpecific (pargs [i], qargs [i]);
3537 if (specific == pargs [i])
3538 p_specific_at_least_once = true;
3539 if (specific == qargs [i])
3540 q_specific_at_least_once = true;
3543 if (p_specific_at_least_once && !q_specific_at_least_once)
3545 if (!p_specific_at_least_once && q_specific_at_least_once)
3553 /// Find the Applicable Function Members (7.4.2.1)
3555 /// me: Method Group expression with the members to select.
3556 /// it might contain constructors or methods (or anything
3557 /// that maps to a method).
3559 /// Arguments: ArrayList containing resolved Argument objects.
3561 /// loc: The location if we want an error to be reported, or a Null
3562 /// location for "probing" purposes.
3564 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3565 /// that is the best match of me on Arguments.
3568 public virtual MethodGroupExpr OverloadResolve (EmitContext ec, ArrayList Arguments,
3569 bool may_fail, Location loc)
3571 bool method_params = false;
3572 Type applicable_type = null;
3574 ArrayList candidates = new ArrayList (2);
3575 ArrayList candidate_overrides = null;
3578 // Used to keep a map between the candidate
3579 // and whether it is being considered in its
3580 // normal or expanded form
3582 // false is normal form, true is expanded form
3584 Hashtable candidate_to_form = null;
3586 if (Arguments != null)
3587 arg_count = Arguments.Count;
3589 if (RootContext.Version == LanguageVersion.ISO_1 && Name == "Invoke" && TypeManager.IsDelegateType (DeclaringType)) {
3591 Report.Error (1533, loc, "Invoke cannot be called directly on a delegate");
3595 int nmethods = Methods.Length;
3599 // Methods marked 'override' don't take part in 'applicable_type'
3600 // computation, nor in the actual overload resolution.
3601 // However, they still need to be emitted instead of a base virtual method.
3602 // So, we salt them away into the 'candidate_overrides' array.
3604 // In case of reflected methods, we replace each overriding method with
3605 // its corresponding base virtual method. This is to improve compatibility
3606 // with non-C# libraries which change the visibility of overrides (#75636)
3609 for (int i = 0; i < Methods.Length; ++i) {
3610 MethodBase m = Methods [i];
3612 Type [] gen_args = null;
3613 if (m.IsGenericMethod && !m.IsGenericMethodDefinition)
3614 gen_args = m.GetGenericArguments ();
3616 if (TypeManager.IsOverride (m)) {
3617 if (candidate_overrides == null)
3618 candidate_overrides = new ArrayList ();
3619 candidate_overrides.Add (m);
3620 m = TypeManager.TryGetBaseDefinition (m);
3622 if (m != null && gen_args != null) {
3623 if (!m.IsGenericMethodDefinition)
3624 throw new InternalErrorException ("GetBaseDefinition didn't return a GenericMethodDefinition");
3625 m = ((MethodInfo) m).MakeGenericMethod (gen_args);
3635 int applicable_errors = Report.Errors;
3638 // First we construct the set of applicable methods
3640 bool is_sorted = true;
3641 for (int i = 0; i < nmethods; i++) {
3642 Type decl_type = Methods [i].DeclaringType;
3645 // If we have already found an applicable method
3646 // we eliminate all base types (Section 14.5.5.1)
3648 if (applicable_type != null && IsAncestralType (decl_type, applicable_type))
3652 // Check if candidate is applicable (section 14.4.2.1)
3653 // Is candidate applicable in normal form?
3655 bool is_applicable = Invocation.IsApplicable (ec, this, Arguments, arg_count, ref Methods [i]);
3657 if (!is_applicable && Invocation.IsParamsMethodApplicable (ec, this, Arguments, arg_count, ref Methods [i])) {
3658 MethodBase candidate = Methods [i];
3659 if (candidate_to_form == null)
3660 candidate_to_form = new PtrHashtable ();
3661 candidate_to_form [candidate] = candidate;
3662 // Candidate is applicable in expanded form
3663 is_applicable = true;
3669 candidates.Add (Methods [i]);
3671 if (applicable_type == null)
3672 applicable_type = decl_type;
3673 else if (applicable_type != decl_type) {
3675 if (IsAncestralType (applicable_type, decl_type))
3676 applicable_type = decl_type;
3680 if (applicable_errors != Report.Errors)
3683 int candidate_top = candidates.Count;
3685 if (applicable_type == null) {
3686 if (ec.IsInProbingMode)
3690 // Okay so we have failed to find anything so we
3691 // return by providing info about the closest match
3693 int errors = Report.Errors;
3694 for (int i = 0; i < nmethods; ++i) {
3695 MethodBase c = Methods [i];
3696 ParameterData pd = TypeManager.GetParameterData (c);
3698 if (pd.Count != arg_count)
3702 if (!TypeManager.InferTypeArguments (ec, Arguments, ref c))
3704 if (TypeManager.IsGenericMethodDefinition (c))
3708 Invocation.VerifyArgumentsCompat (ec, Arguments, arg_count,
3709 c, false, null, may_fail, loc);
3711 if (!may_fail && errors == Report.Errors){
3713 throw new InternalErrorException (
3714 "VerifyArgumentsCompat and IsApplicable do not agree; " +
3715 "likely reason: ImplicitConversion and ImplicitConversionExists have gone out of sync");
3721 if (!may_fail && errors == Report.Errors) {
3722 string report_name = Name;
3723 if (report_name == ".ctor")
3724 report_name = TypeManager.CSharpName (DeclaringType);
3730 for (int i = 0; i < Methods.Length; ++i) {
3731 MethodBase c = Methods [i];
3732 ParameterData pd = TypeManager.GetParameterData (c);
3734 if (pd.Count != arg_count)
3737 if (TypeManager.InferTypeArguments (ec, Arguments, ref c))
3741 411, loc, "The type arguments for " +
3742 "method `{0}' cannot be inferred from " +
3743 "the usage. Try specifying the type " +
3744 "arguments explicitly", TypeManager.CSharpSignature (c));
3749 Invocation.Error_WrongNumArguments (loc, report_name, arg_count);
3757 // At this point, applicable_type is _one_ of the most derived types
3758 // in the set of types containing the methods in this MethodGroup.
3759 // Filter the candidates so that they only contain methods from the
3760 // most derived types.
3763 int finalized = 0; // Number of finalized candidates
3766 // Invariant: applicable_type is a most derived type
3768 // We'll try to complete Section 14.5.5.1 for 'applicable_type' by
3769 // eliminating all it's base types. At the same time, we'll also move
3770 // every unrelated type to the end of the array, and pick the next
3771 // 'applicable_type'.
3773 Type next_applicable_type = null;
3774 int j = finalized; // where to put the next finalized candidate
3775 int k = finalized; // where to put the next undiscarded candidate
3776 for (int i = finalized; i < candidate_top; ++i) {
3777 MethodBase candidate = (MethodBase) candidates [i];
3778 Type decl_type = candidate.DeclaringType;
3780 if (decl_type == applicable_type) {
3781 candidates [k++] = candidates [j];
3782 candidates [j++] = candidates [i];
3786 if (IsAncestralType (decl_type, applicable_type))
3789 if (next_applicable_type != null &&
3790 IsAncestralType (decl_type, next_applicable_type))
3793 candidates [k++] = candidates [i];
3795 if (next_applicable_type == null ||
3796 IsAncestralType (next_applicable_type, decl_type))
3797 next_applicable_type = decl_type;
3800 applicable_type = next_applicable_type;
3803 } while (applicable_type != null);
3807 // Now we actually find the best method
3810 best_candidate = (MethodBase) candidates [0];
3811 method_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
3812 for (int ix = 1; ix < candidate_top; ix++) {
3813 MethodBase candidate = (MethodBase) candidates [ix];
3815 if (candidate == best_candidate)
3818 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
3820 if (BetterFunction (ec, Arguments, arg_count,
3821 candidate, cand_params,
3822 best_candidate, method_params)) {
3823 best_candidate = candidate;
3824 method_params = cand_params;
3828 // Now check that there are no ambiguities i.e the selected method
3829 // should be better than all the others
3831 MethodBase ambiguous = null;
3832 for (int ix = 0; ix < candidate_top; ix++) {
3833 MethodBase candidate = (MethodBase) candidates [ix];
3835 if (candidate == best_candidate)
3838 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
3839 if (!BetterFunction (ec, Arguments, arg_count,
3840 best_candidate, method_params,
3841 candidate, cand_params))
3844 Report.SymbolRelatedToPreviousError (candidate);
3845 ambiguous = candidate;
3849 if (ambiguous != null) {
3850 Report.SymbolRelatedToPreviousError (best_candidate);
3851 Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
3852 TypeManager.CSharpSignature (ambiguous), TypeManager.CSharpSignature (best_candidate));
3857 // If the method is a virtual function, pick an override closer to the LHS type.
3859 if (!IsBase && best_candidate.IsVirtual) {
3860 if (TypeManager.IsOverride (best_candidate))
3861 throw new InternalErrorException (
3862 "Should not happen. An 'override' method took part in overload resolution: " + best_candidate);
3864 if (candidate_overrides != null)
3865 foreach (MethodBase candidate in candidate_overrides) {
3866 if (IsOverride (candidate, best_candidate))
3867 best_candidate = candidate;
3872 // And now check if the arguments are all
3873 // compatible, perform conversions if
3874 // necessary etc. and return if everything is
3877 if (!Invocation.VerifyArgumentsCompat (ec, Arguments, arg_count, best_candidate,
3878 method_params, null, may_fail, loc))
3881 if (best_candidate == null)
3884 MethodBase the_method = TypeManager.DropGenericMethodArguments (best_candidate);
3886 if (the_method.IsGenericMethodDefinition &&
3887 !ConstraintChecker.CheckConstraints (ec, the_method, best_candidate, loc))
3891 IMethodData data = TypeManager.GetMethod (the_method);
3893 data.SetMemberIsUsed ();
3898 public Expression ResolveGeneric (EmitContext ec, TypeArguments args)
3901 if (!args.Resolve (ec))
3904 Type[] atypes = args.Arguments;
3906 int first_count = 0;
3907 MethodInfo first = null;
3909 ArrayList list = new ArrayList ();
3910 foreach (MethodBase mb in Methods) {
3911 MethodInfo mi = mb as MethodInfo;
3912 if ((mi == null) || !mb.IsGenericMethod)
3915 Type[] gen_params = mb.GetGenericArguments ();
3917 if (first == null) {
3919 first_count = gen_params.Length;
3922 if (gen_params.Length != atypes.Length)
3925 mi = mi.MakeGenericMethod (atypes);
3929 // MS implementation throws NotSupportedException for GetParameters
3930 // on unbaked generic method
3931 Parameters p = TypeManager.GetParameterData (mi) as Parameters;
3934 p.InflateTypes (gen_params, atypes);
3935 TypeManager.RegisterMethod (mi, p);
3940 if (list.Count > 0) {
3941 MethodGroupExpr new_mg = new MethodGroupExpr (list, Location);
3942 new_mg.InstanceExpression = InstanceExpression;
3943 new_mg.HasTypeArguments = true;
3944 new_mg.IsBase = IsBase;
3948 if (first != null) {
3949 Report.SymbolRelatedToPreviousError (first);
3951 305, loc, "Using the generic method `{0}' requires `{1}' type arguments",
3952 TypeManager.CSharpSignature (first), first_count.ToString ());
3955 308, loc, "The non-generic method `{0}' " +
3956 "cannot be used with type arguments", Name);
3960 throw new NotImplementedException ();
3966 /// Fully resolved expression that evaluates to a Field
3968 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariable {
3969 public readonly FieldInfo FieldInfo;
3970 VariableInfo variable_info;
3972 LocalTemporary temp;
3974 bool in_initializer;
3976 public FieldExpr (FieldInfo fi, Location l, bool in_initializer):
3979 this.in_initializer = in_initializer;
3982 public FieldExpr (FieldInfo fi, Location l)
3985 eclass = ExprClass.Variable;
3986 type = TypeManager.TypeToCoreType (fi.FieldType);
3990 public override string Name {
3992 return FieldInfo.Name;
3996 public override bool IsInstance {
3998 return !FieldInfo.IsStatic;
4002 public override bool IsStatic {
4004 return FieldInfo.IsStatic;
4008 public override Type DeclaringType {
4010 return FieldInfo.DeclaringType;
4014 public override string GetSignatureForError ()
4016 return TypeManager.GetFullNameSignature (FieldInfo);
4019 public VariableInfo VariableInfo {
4021 return variable_info;
4025 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
4026 SimpleName original)
4028 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
4030 Type t = fi.FieldType;
4032 if (fi.IsLiteral || (fi.IsInitOnly && t == TypeManager.decimal_type)) {
4033 IConstant ic = TypeManager.GetConstant (fi);
4036 ic = new ExternalConstant (fi);
4038 ic = ExternalConstant.CreateDecimal (fi);
4040 return base.ResolveMemberAccess (ec, left, loc, original);
4043 TypeManager.RegisterConstant (fi, ic);
4046 bool left_is_type = left is TypeExpr;
4047 if (!left_is_type && (original == null || !original.IdenticalNameAndTypeName (ec, left, loc))) {
4048 Report.SymbolRelatedToPreviousError (FieldInfo);
4049 error176 (loc, TypeManager.GetFullNameSignature (FieldInfo));
4053 if (ic.ResolveValue ()) {
4054 if (!ec.IsInObsoleteScope)
4055 ic.CheckObsoleteness (loc);
4058 return ic.CreateConstantReference (loc);
4061 if (t.IsPointer && !ec.InUnsafe) {
4065 return base.ResolveMemberAccess (ec, left, loc, original);
4068 override public Expression DoResolve (EmitContext ec)
4070 return DoResolve (ec, false, false);
4073 Expression DoResolve (EmitContext ec, bool lvalue_instance, bool out_access)
4075 if (!FieldInfo.IsStatic){
4076 if (InstanceExpression == null){
4078 // This can happen when referencing an instance field using
4079 // a fully qualified type expression: TypeName.InstanceField = xxx
4081 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4085 // Resolve the field's instance expression while flow analysis is turned
4086 // off: when accessing a field "a.b", we must check whether the field
4087 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4089 if (lvalue_instance) {
4090 using (ec.With (EmitContext.Flags.DoFlowAnalysis, false)) {
4091 Expression right_side =
4092 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4093 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side, loc);
4096 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
4097 InstanceExpression = InstanceExpression.Resolve (ec, rf);
4100 if (InstanceExpression == null)
4103 InstanceExpression.CheckMarshalByRefAccess ();
4106 if (!in_initializer && !ec.IsFieldInitializer) {
4107 ObsoleteAttribute oa;
4108 FieldBase f = TypeManager.GetField (FieldInfo);
4110 if (!ec.IsInObsoleteScope)
4111 f.CheckObsoleteness (loc);
4113 // To be sure that type is external because we do not register generated fields
4114 } else if (!(FieldInfo.DeclaringType is TypeBuilder)) {
4115 oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
4117 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
4121 AnonymousContainer am = ec.CurrentAnonymousMethod;
4123 if (!FieldInfo.IsStatic){
4124 if (!am.IsIterator && (ec.TypeContainer is Struct)){
4125 Report.Error (1673, loc,
4126 "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",
4133 IFixedBuffer fb = AttributeTester.GetFixedBuffer (FieldInfo);
4135 if (!ec.InFixedInitializer && ec.ContainerType.IsValueType) {
4136 Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4139 if (!(InstanceExpression is LocalVariableReference) &&
4140 !(InstanceExpression is This)) {
4141 Report.SymbolRelatedToPreviousError (FieldInfo);
4142 Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4143 TypeManager.GetFullNameSignature (FieldInfo));
4146 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4149 // If the instance expression is a local variable or parameter.
4150 IVariable var = InstanceExpression as IVariable;
4151 if ((var == null) || (var.VariableInfo == null))
4154 VariableInfo vi = var.VariableInfo;
4155 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
4158 variable_info = vi.GetSubStruct (FieldInfo.Name);
4162 static readonly int [] codes = {
4163 191, // instance, write access
4164 192, // instance, out access
4165 198, // static, write access
4166 199, // static, out access
4167 1648, // member of value instance, write access
4168 1649, // member of value instance, out access
4169 1650, // member of value static, write access
4170 1651 // member of value static, out access
4173 static readonly string [] msgs = {
4174 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4175 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4176 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4177 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4178 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4179 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4180 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4181 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4184 // The return value is always null. Returning a value simplifies calling code.
4185 Expression Report_AssignToReadonly (Expression right_side)
4188 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4192 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4194 Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4199 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4201 IVariable var = InstanceExpression as IVariable;
4202 if ((var != null) && (var.VariableInfo != null))
4203 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
4205 bool lvalue_instance = !FieldInfo.IsStatic && FieldInfo.DeclaringType.IsValueType;
4206 bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
4208 Expression e = DoResolve (ec, lvalue_instance, out_access);
4213 FieldBase fb = TypeManager.GetField (FieldInfo);
4217 if (FieldInfo.IsInitOnly) {
4218 // InitOnly fields can only be assigned in constructors or initializers
4219 if (!ec.IsFieldInitializer && !ec.IsConstructor)
4220 return Report_AssignToReadonly (right_side);
4222 if (ec.IsConstructor) {
4223 Type ctype = ec.TypeContainer.CurrentType;
4225 ctype = ec.ContainerType;
4227 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4228 if (!TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
4229 return Report_AssignToReadonly (right_side);
4230 // static InitOnly fields cannot be assigned-to in an instance constructor
4231 if (IsStatic && !ec.IsStatic)
4232 return Report_AssignToReadonly (right_side);
4233 // instance constructors can't modify InitOnly fields of other instances of the same type
4234 if (!IsStatic && !(InstanceExpression is This))
4235 return Report_AssignToReadonly (right_side);
4239 if (right_side == EmptyExpression.OutAccess &&
4240 !IsStatic && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
4241 Report.SymbolRelatedToPreviousError (DeclaringType);
4242 Report.Warning (197, 1, loc,
4243 "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",
4244 GetSignatureForError ());
4250 public override void CheckMarshalByRefAccess ()
4252 if (!IsStatic && Type.IsValueType && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
4253 Report.SymbolRelatedToPreviousError (DeclaringType);
4254 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",
4255 GetSignatureForError ());
4259 public bool VerifyFixed ()
4261 IVariable variable = InstanceExpression as IVariable;
4262 // A variable of the form V.I is fixed when V is a fixed variable of a struct type.
4263 // We defer the InstanceExpression check after the variable check to avoid a
4264 // separate null check on InstanceExpression.
4265 return variable != null && InstanceExpression.Type.IsValueType && variable.VerifyFixed ();
4268 public override int GetHashCode ()
4270 return FieldInfo.GetHashCode ();
4273 public override bool Equals (object obj)
4275 FieldExpr fe = obj as FieldExpr;
4279 if (FieldInfo != fe.FieldInfo)
4282 if (InstanceExpression == null || fe.InstanceExpression == null)
4285 return InstanceExpression.Equals (fe.InstanceExpression);
4288 public void Emit (EmitContext ec, bool leave_copy)
4290 ILGenerator ig = ec.ig;
4291 bool is_volatile = false;
4293 FieldBase f = TypeManager.GetField (FieldInfo);
4295 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4298 f.SetMemberIsUsed ();
4301 if (FieldInfo.IsStatic){
4303 ig.Emit (OpCodes.Volatile);
4305 ig.Emit (OpCodes.Ldsfld, FieldInfo);
4308 EmitInstance (ec, false);
4310 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
4312 ig.Emit (OpCodes.Ldflda, FieldInfo);
4313 ig.Emit (OpCodes.Ldflda, ff.Element);
4316 ig.Emit (OpCodes.Volatile);
4318 ig.Emit (OpCodes.Ldfld, FieldInfo);
4323 ec.ig.Emit (OpCodes.Dup);
4324 if (!FieldInfo.IsStatic) {
4325 temp = new LocalTemporary (this.Type);
4331 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4333 FieldAttributes fa = FieldInfo.Attributes;
4334 bool is_static = (fa & FieldAttributes.Static) != 0;
4335 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
4336 ILGenerator ig = ec.ig;
4337 prepared = prepare_for_load;
4339 if (is_readonly && !ec.IsConstructor){
4340 Report_AssignToReadonly (source);
4344 EmitInstance (ec, prepare_for_load);
4348 ec.ig.Emit (OpCodes.Dup);
4349 if (!FieldInfo.IsStatic) {
4350 temp = new LocalTemporary (this.Type);
4355 FieldBase f = TypeManager.GetField (FieldInfo);
4357 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4358 ig.Emit (OpCodes.Volatile);
4364 ig.Emit (OpCodes.Stsfld, FieldInfo);
4366 ig.Emit (OpCodes.Stfld, FieldInfo);
4374 public override void Emit (EmitContext ec)
4379 public void AddressOf (EmitContext ec, AddressOp mode)
4381 ILGenerator ig = ec.ig;
4383 FieldBase f = TypeManager.GetField (FieldInfo);
4385 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
4386 Report.Warning (420, 1, loc, "`{0}': A volatile field references will not be treated as volatile",
4387 f.GetSignatureForError ());
4390 if ((mode & AddressOp.Store) != 0)
4392 if ((mode & AddressOp.Load) != 0)
4393 f.SetMemberIsUsed ();
4397 // Handle initonly fields specially: make a copy and then
4398 // get the address of the copy.
4401 if (FieldInfo.IsInitOnly){
4403 if (ec.IsConstructor){
4404 if (FieldInfo.IsStatic){
4416 local = ig.DeclareLocal (type);
4417 ig.Emit (OpCodes.Stloc, local);
4418 ig.Emit (OpCodes.Ldloca, local);
4423 if (FieldInfo.IsStatic){
4424 ig.Emit (OpCodes.Ldsflda, FieldInfo);
4427 EmitInstance (ec, false);
4428 ig.Emit (OpCodes.Ldflda, FieldInfo);
4434 // A FieldExpr whose address can not be taken
4436 public class FieldExprNoAddress : FieldExpr, IMemoryLocation {
4437 public FieldExprNoAddress (FieldInfo fi, Location loc) : base (fi, loc)
4441 public new void AddressOf (EmitContext ec, AddressOp mode)
4443 Report.Error (-215, "Report this: Taking the address of a remapped parameter not supported");
4448 /// Expression that evaluates to a Property. The Assign class
4449 /// might set the `Value' expression if we are in an assignment.
4451 /// This is not an LValue because we need to re-write the expression, we
4452 /// can not take data from the stack and store it.
4454 public class PropertyExpr : MemberExpr, IAssignMethod {
4455 public readonly PropertyInfo PropertyInfo;
4458 // This is set externally by the `BaseAccess' class
4461 MethodInfo getter, setter;
4466 LocalTemporary temp;
4469 public PropertyExpr (Type containerType, PropertyInfo pi, Location l)
4472 eclass = ExprClass.PropertyAccess;
4476 type = TypeManager.TypeToCoreType (pi.PropertyType);
4478 ResolveAccessors (containerType);
4481 public override string Name {
4483 return PropertyInfo.Name;
4487 public override bool IsInstance {
4493 public override bool IsStatic {
4499 public override Type DeclaringType {
4501 return PropertyInfo.DeclaringType;
4505 public override string GetSignatureForError ()
4507 return TypeManager.GetFullNameSignature (PropertyInfo);
4510 void FindAccessors (Type invocation_type)
4512 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
4513 BindingFlags.Static | BindingFlags.Instance |
4514 BindingFlags.DeclaredOnly;
4516 Type current = PropertyInfo.DeclaringType;
4517 for (; current != null; current = current.BaseType) {
4518 MemberInfo[] group = TypeManager.MemberLookup (
4519 invocation_type, invocation_type, current,
4520 MemberTypes.Property, flags, PropertyInfo.Name, null);
4525 if (group.Length != 1)
4526 // Oooops, can this ever happen ?
4529 PropertyInfo pi = (PropertyInfo) group [0];
4532 getter = pi.GetGetMethod (true);
4535 setter = pi.GetSetMethod (true);
4537 MethodInfo accessor = getter != null ? getter : setter;
4539 if (!accessor.IsVirtual)
4545 // We also perform the permission checking here, as the PropertyInfo does not
4546 // hold the information for the accessibility of its setter/getter
4548 // TODO: Refactor to use some kind of cache together with GetPropertyFromAccessor
4549 void ResolveAccessors (Type containerType)
4551 FindAccessors (containerType);
4553 if (getter != null) {
4554 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
4555 IMethodData md = TypeManager.GetMethod (the_getter);
4557 md.SetMemberIsUsed ();
4559 is_static = getter.IsStatic;
4562 if (setter != null) {
4563 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
4564 IMethodData md = TypeManager.GetMethod (the_setter);
4566 md.SetMemberIsUsed ();
4568 is_static = setter.IsStatic;
4572 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
4575 InstanceExpression = null;
4579 if (InstanceExpression == null) {
4580 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4584 InstanceExpression = InstanceExpression.DoResolve (ec);
4585 if (lvalue_instance && InstanceExpression != null)
4586 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
4588 if (InstanceExpression == null)
4591 InstanceExpression.CheckMarshalByRefAccess ();
4593 if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) &&
4594 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
4595 !TypeManager.IsNestedChildOf (ec.ContainerType, InstanceExpression.Type) &&
4596 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.ContainerType)) {
4597 Report.SymbolRelatedToPreviousError (PropertyInfo);
4598 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
4605 void Error_PropertyNotFound (MethodInfo mi, bool getter)
4607 // TODO: correctly we should compare arguments but it will lead to bigger changes
4608 if (mi is MethodBuilder) {
4609 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
4613 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
4615 ParameterData iparams = TypeManager.GetParameterData (mi);
4616 sig.Append (getter ? "get_" : "set_");
4618 sig.Append (iparams.GetSignatureForError ());
4620 Report.SymbolRelatedToPreviousError (mi);
4621 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
4622 Name, sig.ToString ());
4625 override public Expression DoResolve (EmitContext ec)
4630 if (getter != null){
4631 if (TypeManager.GetParameterData (getter).Count != 0){
4632 Error_PropertyNotFound (getter, true);
4637 if (getter == null){
4639 // The following condition happens if the PropertyExpr was
4640 // created, but is invalid (ie, the property is inaccessible),
4641 // and we did not want to embed the knowledge about this in
4642 // the caller routine. This only avoids double error reporting.
4647 if (InstanceExpression != EmptyExpression.Null) {
4648 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
4649 TypeManager.GetFullNameSignature (PropertyInfo));
4654 bool must_do_cs1540_check = false;
4655 if (getter != null &&
4656 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
4657 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
4658 if (pm != null && pm.HasCustomAccessModifier) {
4659 Report.SymbolRelatedToPreviousError (pm);
4660 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
4661 TypeManager.CSharpSignature (getter));
4664 Report.SymbolRelatedToPreviousError (getter);
4665 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
4670 if (!InstanceResolve (ec, false, must_do_cs1540_check))
4674 // Only base will allow this invocation to happen.
4676 if (IsBase && getter.IsAbstract) {
4677 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
4681 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
4691 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4693 if (right_side == EmptyExpression.OutAccess) {
4694 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
4695 GetSignatureForError ());
4699 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
4700 Report.Error (1612, loc, "Cannot modify the return value of `{0}' because it is not a variable",
4701 GetSignatureForError ());
4705 if (setter == null){
4707 // The following condition happens if the PropertyExpr was
4708 // created, but is invalid (ie, the property is inaccessible),
4709 // and we did not want to embed the knowledge about this in
4710 // the caller routine. This only avoids double error reporting.
4714 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
4715 GetSignatureForError ());
4719 if (TypeManager.GetParameterData (setter).Count != 1){
4720 Error_PropertyNotFound (setter, false);
4724 bool must_do_cs1540_check;
4725 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
4726 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
4727 if (pm != null && pm.HasCustomAccessModifier) {
4728 Report.SymbolRelatedToPreviousError (pm);
4729 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
4730 TypeManager.CSharpSignature (setter));
4733 Report.SymbolRelatedToPreviousError (setter);
4734 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
4739 if (!InstanceResolve (ec, PropertyInfo.DeclaringType.IsValueType, must_do_cs1540_check))
4743 // Only base will allow this invocation to happen.
4745 if (IsBase && setter.IsAbstract){
4746 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
4753 public override void Emit (EmitContext ec)
4758 public void Emit (EmitContext ec, bool leave_copy)
4761 // Special case: length of single dimension array property is turned into ldlen
4763 if ((getter == TypeManager.system_int_array_get_length) ||
4764 (getter == TypeManager.int_array_get_length)){
4765 Type iet = InstanceExpression.Type;
4768 // System.Array.Length can be called, but the Type does not
4769 // support invoking GetArrayRank, so test for that case first
4771 if (iet != TypeManager.array_type && (iet.GetArrayRank () == 1)) {
4773 EmitInstance (ec, false);
4774 ec.ig.Emit (OpCodes.Ldlen);
4775 ec.ig.Emit (OpCodes.Conv_I4);
4780 Invocation.EmitCall (ec, IsBase, InstanceExpression, getter, null, loc, prepared, false);
4783 ec.ig.Emit (OpCodes.Dup);
4785 temp = new LocalTemporary (this.Type);
4792 // Implements the IAssignMethod interface for assignments
4794 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4796 Expression my_source = source;
4798 prepared = prepare_for_load;
4803 ec.ig.Emit (OpCodes.Dup);
4805 temp = new LocalTemporary (this.Type);
4809 } else if (leave_copy) {
4812 temp = new LocalTemporary (this.Type);
4818 ArrayList args = new ArrayList (1);
4819 args.Add (new Argument (my_source, Argument.AType.Expression));
4821 Invocation.EmitCall (ec, IsBase, InstanceExpression, setter, args, loc, false, prepared);
4831 /// Fully resolved expression that evaluates to an Event
4833 public class EventExpr : MemberExpr {
4834 public readonly EventInfo EventInfo;
4837 MethodInfo add_accessor, remove_accessor;
4839 public EventExpr (EventInfo ei, Location loc)
4843 eclass = ExprClass.EventAccess;
4845 add_accessor = TypeManager.GetAddMethod (ei);
4846 remove_accessor = TypeManager.GetRemoveMethod (ei);
4847 if (add_accessor.IsStatic || remove_accessor.IsStatic)
4850 if (EventInfo is MyEventBuilder){
4851 MyEventBuilder eb = (MyEventBuilder) EventInfo;
4852 type = eb.EventType;
4855 type = EventInfo.EventHandlerType;
4858 public override string Name {
4860 return EventInfo.Name;
4864 public override bool IsInstance {
4870 public override bool IsStatic {
4876 public override Type DeclaringType {
4878 return EventInfo.DeclaringType;
4882 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
4883 SimpleName original)
4886 // If the event is local to this class, we transform ourselves into a FieldExpr
4889 if (EventInfo.DeclaringType == ec.ContainerType ||
4890 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
4891 EventField mi = TypeManager.GetEventField (EventInfo);
4894 if (!ec.IsInObsoleteScope)
4895 mi.CheckObsoleteness (loc);
4897 FieldExpr ml = new FieldExpr (mi.FieldBuilder, loc);
4899 InstanceExpression = null;
4901 return ml.ResolveMemberAccess (ec, left, loc, original);
4905 return base.ResolveMemberAccess (ec, left, loc, original);
4909 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
4912 InstanceExpression = null;
4916 if (InstanceExpression == null) {
4917 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4921 InstanceExpression = InstanceExpression.DoResolve (ec);
4922 if (InstanceExpression == null)
4926 // This is using the same mechanism as the CS1540 check in PropertyExpr.
4927 // However, in the Event case, we reported a CS0122 instead.
4929 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
4930 InstanceExpression.Type != ec.ContainerType &&
4931 ec.ContainerType.IsSubclassOf (InstanceExpression.Type)) {
4932 Report.SymbolRelatedToPreviousError (EventInfo);
4933 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
4940 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
4942 return DoResolve (ec);
4945 public override Expression DoResolve (EmitContext ec)
4947 bool must_do_cs1540_check;
4948 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
4949 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
4950 Report.SymbolRelatedToPreviousError (EventInfo);
4951 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
4955 if (!InstanceResolve (ec, must_do_cs1540_check))
4961 public override void Emit (EmitContext ec)
4963 if (InstanceExpression is This)
4964 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of += or -=", GetSignatureForError ());
4966 Report.Error (70, loc, "The event `{0}' can only appear on the left hand side of += or -= "+
4967 "(except on the defining type)", Name);
4970 public override string GetSignatureForError ()
4972 return TypeManager.CSharpSignature (EventInfo);
4975 public void EmitAddOrRemove (EmitContext ec, Expression source)
4977 BinaryDelegate source_del = source as BinaryDelegate;
4978 if (source_del == null) {
4982 Expression handler = source_del.Right;
4984 Argument arg = new Argument (handler, Argument.AType.Expression);
4985 ArrayList args = new ArrayList ();
4989 if (source_del.IsAddition)
4990 Invocation.EmitCall (
4991 ec, false, InstanceExpression, add_accessor, args, loc);
4993 Invocation.EmitCall (
4994 ec, false, InstanceExpression, remove_accessor, args, loc);
4998 public class TemporaryVariable : Expression, IMemoryLocation
5003 public TemporaryVariable (Type type, Location loc)
5007 eclass = ExprClass.Value;
5010 public override Expression DoResolve (EmitContext ec)
5015 TypeExpr te = new TypeExpression (type, loc);
5016 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
5017 if (!li.Resolve (ec))
5020 if (ec.MustCaptureVariable (li)) {
5021 ScopeInfo scope = li.Block.CreateScopeInfo ();
5022 var = scope.AddLocal (li);
5029 public Variable Variable {
5030 get { return var != null ? var : li.Variable; }
5033 public override void Emit (EmitContext ec)
5035 Variable.EmitInstance (ec);
5039 public void EmitLoadAddress (EmitContext ec)
5041 Variable.EmitInstance (ec);
5042 Variable.EmitAddressOf (ec);
5045 public void Store (EmitContext ec, Expression right_side)
5047 Variable.EmitInstance (ec);
5048 right_side.Emit (ec);
5049 Variable.EmitAssign (ec);
5052 public void EmitThis (EmitContext ec)
5054 Variable.EmitInstance (ec);
5057 public void EmitStore (EmitContext ec)
5059 Variable.EmitAssign (ec);
5062 public void AddressOf (EmitContext ec, AddressOp mode)
5064 EmitLoadAddress (ec);
5069 /// Handles `var' contextual keyword; var becomes a keyword only
5070 /// if no type called var exists in a variable scope
5072 public class VarExpr : SimpleName
5074 // Used for error reporting only
5075 ArrayList initializer;
5077 public VarExpr (string name, Location loc)
5082 public ArrayList VariableInitializer {
5084 this.initializer = value;
5088 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5091 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
5093 type = right_side.Type;
5094 if (type == TypeManager.null_type || type == TypeManager.void_type || type == TypeManager.anonymous_method_type) {
5095 Report.Error (815, loc, "An implicitly typed local variable declaration cannot be initialized with `{0}'",
5096 right_side.GetSignatureForError ());
5100 eclass = ExprClass.Variable;
5104 protected override void Error_TypeOrNamespaceNotFound (IResolveContext ec)
5106 if (ec is FieldBase) {
5107 Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");
5111 base.Error_TypeOrNamespaceNotFound (ec);
5114 public override TypeExpr ResolveAsContextualType (IResolveContext rc, bool silent)
5116 TypeExpr te = base.ResolveAsContextualType (rc, true);
5120 if (initializer == null)
5123 // TODO: refactor, the error is reported too many times
5124 if (initializer.Count > 1) {
5125 Location loc = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [1]).Location;
5126 Report.Error (819, loc, "An implicitly typed local variable declaration cannot include multiple declarators");
5130 Expression variable_initializer = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [0]).expression_or_array_initializer;
5131 if (variable_initializer == null) {
5132 Report.Error (818, loc, "An implicitly typed local variable declarator must include an initializer");