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 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
13 namespace Mono.CSharp {
15 using System.Collections;
16 using System.Diagnostics;
17 using System.Reflection;
18 using System.Reflection.Emit;
22 /// The ExprClass class contains the is used to pass the
23 /// classification of an expression (value, variable, namespace,
24 /// type, method group, property access, event access, indexer access,
27 public enum ExprClass : byte {
42 /// This is used to tell Resolve in which types of expressions we're
46 public enum ResolveFlags {
47 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
50 // Returns a type expression.
53 // Returns a method group.
56 // Mask of all the expression class flags.
59 // Disable control flow analysis while resolving the expression.
60 // This is used when resolving the instance expression of a field expression.
61 DisableFlowAnalysis = 8,
63 // Set if this is resolving the first part of a MemberAccess.
66 // Disable control flow analysis _of struct_ while resolving the expression.
67 // This is used when resolving the instance expression of a field expression.
68 DisableStructFlowAnalysis = 32,
73 // This is just as a hint to AddressOf of what will be done with the
76 public enum AddressOp {
83 /// This interface is implemented by variables
85 public interface IMemoryLocation {
87 /// The AddressOf method should generate code that loads
88 /// the address of the object and leaves it on the stack.
90 /// The `mode' argument is used to notify the expression
91 /// of whether this will be used to read from the address or
92 /// write to the address.
94 /// This is just a hint that can be used to provide good error
95 /// reporting, and should have no other side effects.
97 void AddressOf (EmitContext ec, AddressOp mode);
101 /// This interface is implemented by variables
103 public interface IVariable {
104 VariableInfo VariableInfo {
112 /// Base class for expressions
114 public abstract class Expression {
115 public ExprClass eclass;
117 protected Location loc;
121 set { type = value; }
124 public virtual Location Location {
129 /// Utility wrapper routine for Error, just to beautify the code
131 public void Error (int error, string s)
133 Report.Error (error, loc, s);
136 // Not nice but we have broken hierarchy.
137 public virtual void CheckMarshalByRefAccess (EmitContext ec)
141 public virtual bool GetAttributableValue (Type value_type, out object value)
143 Attribute.Error_AttributeArgumentNotValid (loc);
148 public virtual string GetSignatureForError ()
150 return TypeManager.CSharpName (type);
153 public static bool IsAccessorAccessible (Type invocation_type, MethodInfo mi, out bool must_do_cs1540_check)
155 MethodAttributes ma = mi.Attributes & MethodAttributes.MemberAccessMask;
157 must_do_cs1540_check = false; // by default we do not check for this
159 if (ma == MethodAttributes.Public)
163 // If only accessible to the current class or children
165 if (ma == MethodAttributes.Private)
166 return TypeManager.IsPrivateAccessible (invocation_type, mi.DeclaringType) ||
167 TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType);
169 if (TypeManager.IsThisOrFriendAssembly (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;
188 public virtual bool IsNull {
195 /// Performs semantic analysis on the Expression
199 /// The Resolve method is invoked to perform the semantic analysis
202 /// The return value is an expression (it can be the
203 /// same expression in some cases) or a new
204 /// expression that better represents this node.
206 /// For example, optimizations of Unary (LiteralInt)
207 /// would return a new LiteralInt with a negated
210 /// If there is an error during semantic analysis,
211 /// then an error should be reported (using Report)
212 /// and a null value should be returned.
214 /// There are two side effects expected from calling
215 /// Resolve(): the the field variable "eclass" should
216 /// be set to any value of the enumeration
217 /// `ExprClass' and the type variable should be set
218 /// to a valid type (this is the type of the
221 public abstract Expression DoResolve (EmitContext ec);
223 public virtual Expression DoResolveLValue (EmitContext ec, Expression right_side)
229 // This is used if the expression should be resolved as a type or namespace name.
230 // the default implementation fails.
232 public virtual FullNamedExpression ResolveAsTypeStep (IResolveContext rc, bool silent)
236 EmitContext ec = rc as EmitContext;
240 e.Error_UnexpectedKind (ResolveFlags.Type, loc);
246 // C# 3.0 introduced contextual keywords (var) which behaves like a type if type with
247 // same name exists or as a keyword when no type was found
249 public virtual TypeExpr ResolveAsContextualType (IResolveContext rc, bool silent)
251 return ResolveAsTypeTerminal (rc, silent);
255 // This is used to resolve the expression as a type, a null
256 // value will be returned if the expression is not a type
259 public virtual TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
261 TypeExpr te = ResolveAsBaseTerminal (ec, silent);
265 if (!silent) { // && !(te is TypeParameterExpr)) {
266 ObsoleteAttribute obsolete_attr = AttributeTester.GetObsoleteAttribute (te.Type);
267 if (obsolete_attr != null && !ec.IsInObsoleteScope) {
268 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location);
272 // Constrains don't need to be checked for overrides
273 GenericMethod gm = ec.GenericDeclContainer as GenericMethod;
274 if (gm != null && (gm.ModFlags & Modifiers.OVERRIDE) != 0) {
279 ConstructedType ct = te as ConstructedType;
280 if ((ct != null) && !ct.CheckConstraints (ec))
286 public TypeExpr ResolveAsBaseTerminal (IResolveContext ec, bool silent)
288 int errors = Report.Errors;
290 FullNamedExpression fne = ResolveAsTypeStep (ec, silent);
295 if (fne.eclass != ExprClass.Type) {
296 if (!silent && errors == Report.Errors)
297 fne.Error_UnexpectedKind (null, "type", loc);
301 TypeExpr te = fne as TypeExpr;
303 if (!te.CheckAccessLevel (ec.DeclContainer)) {
304 Report.SymbolRelatedToPreviousError (te.Type);
305 ErrorIsInaccesible (loc, TypeManager.CSharpName (te.Type));
313 public static void ErrorIsInaccesible (Location loc, string name)
315 Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", name);
318 protected static void Error_CannotAccessProtected (Location loc, MemberInfo m, Type qualifier, Type container)
320 Report.Error (1540, loc, "Cannot access protected member `{0}' via a qualifier of type `{1}'."
321 + " The qualifier must be of type `{2}' or derived from it",
322 TypeManager.GetFullNameSignature (m),
323 TypeManager.CSharpName (qualifier),
324 TypeManager.CSharpName (container));
328 public static void Error_InvalidExpressionStatement (Location loc)
330 Report.Error (201, loc, "Only assignment, call, increment, decrement, and new object " +
331 "expressions can be used as a statement");
334 public void Error_InvalidExpressionStatement ()
336 Error_InvalidExpressionStatement (loc);
339 protected void Error_CannotAssign (string to, string roContext)
341 Report.Error (1656, loc, "Cannot assign to `{0}' because it is a `{1}'",
345 public static void Error_VoidInvalidInTheContext (Location loc)
347 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
350 public virtual void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl)
352 // The error was already reported as CS1660
353 if (type == TypeManager.anonymous_method_type)
356 if (TypeManager.IsGenericParameter (Type) && TypeManager.IsGenericParameter (target) && type.Name == target.Name) {
358 string sig1 = type.DeclaringMethod == null ?
359 TypeManager.CSharpName (type.DeclaringType) :
360 TypeManager.CSharpSignature (type.DeclaringMethod);
361 string sig2 = target.DeclaringMethod == null ?
362 TypeManager.CSharpName (target.DeclaringType) :
363 TypeManager.CSharpSignature (target.DeclaringMethod);
364 Report.ExtraInformation (loc,
366 "The generic parameter `{0}' of `{1}' cannot be converted to the generic parameter `{0}' of `{2}' (in the previous ",
367 Type.Name, sig1, sig2));
369 } else if (Type.FullName == target.FullName){
370 Report.ExtraInformation (loc,
372 "The type `{0}' has two conflicting definitions, one comes from `{1}' and the other from `{2}' (in the previous ",
373 Type.FullName, Type.Assembly.FullName, target.Assembly.FullName));
377 Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
378 TypeManager.CSharpName (type), TypeManager.CSharpName (target));
382 Expression e = (this is EnumConstant) ? ((EnumConstant)this).Child : this;
383 bool b = Convert.ExplicitNumericConversion (e, target) != null;
386 Convert.ExplicitReferenceConversionExists (Type, target) ||
387 Convert.ExplicitUnsafe (e, target) != null ||
388 (ec != null && Convert.ExplicitUserConversion (ec, this, target, Location.Null) != null))
390 Report.Error (266, loc, "Cannot implicitly convert type `{0}' to `{1}'. " +
391 "An explicit conversion exists (are you missing a cast?)",
392 TypeManager.CSharpName (Type), TypeManager.CSharpName (target));
396 if (Type != TypeManager.string_type && this is Constant && !(this is EmptyConstantCast)) {
397 Report.Error (31, loc, "Constant value `{0}' cannot be converted to a `{1}'",
398 ((Constant)(this)).GetValue ().ToString (), TypeManager.CSharpName (target));
402 Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
403 TypeManager.CSharpName (type),
404 TypeManager.CSharpName (target));
407 protected void Error_VariableIsUsedBeforeItIsDeclared (string name)
409 Report.Error (841, loc, "The variable `{0}' cannot be used before it is declared",
413 protected virtual void Error_TypeDoesNotContainDefinition (Type type, string name)
415 Error_TypeDoesNotContainDefinition (loc, type, name);
418 public static void Error_TypeDoesNotContainDefinition (Location loc, Type type, string name)
420 Report.SymbolRelatedToPreviousError (type);
421 Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
422 TypeManager.CSharpName (type), name);
425 protected static void Error_ValueAssignment (Location loc)
427 Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
430 ResolveFlags ExprClassToResolveFlags
435 case ExprClass.Namespace:
436 return ResolveFlags.Type;
438 case ExprClass.MethodGroup:
439 return ResolveFlags.MethodGroup;
441 case ExprClass.Value:
442 case ExprClass.Variable:
443 case ExprClass.PropertyAccess:
444 case ExprClass.EventAccess:
445 case ExprClass.IndexerAccess:
446 return ResolveFlags.VariableOrValue;
449 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
455 /// Resolves an expression and performs semantic analysis on it.
459 /// Currently Resolve wraps DoResolve to perform sanity
460 /// checking and assertion checking on what we expect from Resolve.
462 public Expression Resolve (EmitContext ec, ResolveFlags flags)
464 if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type)
465 return ResolveAsTypeStep (ec, false);
467 bool do_flow_analysis = ec.DoFlowAnalysis;
468 bool omit_struct_analysis = ec.OmitStructFlowAnalysis;
469 if ((flags & ResolveFlags.DisableFlowAnalysis) != 0)
470 do_flow_analysis = false;
471 if ((flags & ResolveFlags.DisableStructFlowAnalysis) != 0)
472 omit_struct_analysis = true;
475 using (ec.WithFlowAnalysis (do_flow_analysis, omit_struct_analysis)) {
476 if (this is SimpleName) {
477 bool intermediate = (flags & ResolveFlags.Intermediate) == ResolveFlags.Intermediate;
478 e = ((SimpleName) this).DoResolve (ec, intermediate);
487 if ((flags & e.ExprClassToResolveFlags) == 0) {
488 e.Error_UnexpectedKind (flags, loc);
492 if (e.type == null && !(e is Namespace)) {
493 throw new Exception (
494 "Expression " + e.GetType () +
495 " did not set its type after Resolve\n" +
496 "called from: " + this.GetType ());
503 /// Resolves an expression and performs semantic analysis on it.
505 public Expression Resolve (EmitContext ec)
507 Expression e = Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
509 if (e != null && e.eclass == ExprClass.MethodGroup && RootContext.Version == LanguageVersion.ISO_1) {
510 ((MethodGroupExpr) e).ReportUsageError ();
516 public Constant ResolveAsConstant (EmitContext ec, MemberCore mc)
518 Expression e = Resolve (ec);
522 Constant c = e as Constant;
526 Const.Error_ExpressionMustBeConstant (loc, mc.GetSignatureForError ());
531 /// Resolves an expression for LValue assignment
535 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
536 /// checking and assertion checking on what we expect from Resolve
538 public Expression ResolveLValue (EmitContext ec, Expression right_side, Location loc)
540 int errors = Report.Errors;
541 bool out_access = right_side == EmptyExpression.OutAccess;
543 Expression e = DoResolveLValue (ec, right_side);
545 if (e != null && out_access && !(e is IMemoryLocation)) {
546 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
547 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
549 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
550 // e.GetType () + " " + e.GetSignatureForError ());
555 if (errors == Report.Errors) {
557 Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
559 Error_ValueAssignment (loc);
564 if (e.eclass == ExprClass.Invalid)
565 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
567 if (e.eclass == ExprClass.MethodGroup) {
568 ((MethodGroupExpr) e).ReportUsageError ();
572 if ((e.type == null) && !(e is ConstructedType))
573 throw new Exception ("Expression " + e + " did not set its type after Resolve");
579 /// Emits the code for the expression
583 /// The Emit method is invoked to generate the code
584 /// for the expression.
586 public abstract void Emit (EmitContext ec);
588 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
591 ec.ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
594 public virtual void EmitSideEffect (EmitContext ec)
597 ec.ig.Emit (OpCodes.Pop);
601 /// Protected constructor. Only derivate types should
602 /// be able to be created
605 protected Expression ()
607 eclass = ExprClass.Invalid;
612 /// Returns a fully formed expression after a MemberLookup
615 public static Expression ExprClassFromMemberInfo (Type container_type, MemberInfo mi, Location loc)
618 return new EventExpr ((EventInfo) mi, loc);
619 else if (mi is FieldInfo) {
620 FieldInfo fi = (FieldInfo) mi;
621 if (fi.IsLiteral || (fi.IsInitOnly && fi.FieldType == TypeManager.decimal_type))
622 return new ConstantExpr (fi, loc);
623 return new FieldExpr (fi, loc);
624 } else if (mi is PropertyInfo)
625 return new PropertyExpr (container_type, (PropertyInfo) mi, loc);
626 else if (mi is Type) {
627 return new TypeExpression ((System.Type) mi, loc);
633 protected static ArrayList almost_matched_members = new ArrayList (4);
636 // FIXME: Probably implement a cache for (t,name,current_access_set)?
638 // This code could use some optimizations, but we need to do some
639 // measurements. For example, we could use a delegate to `flag' when
640 // something can not any longer be a method-group (because it is something
644 // If the return value is an Array, then it is an array of
647 // If the return value is an MemberInfo, it is anything, but a Method
651 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
652 // the arguments here and have MemberLookup return only the methods that
653 // match the argument count/type, unlike we are doing now (we delay this
656 // This is so we can catch correctly attempts to invoke instance methods
657 // from a static body (scan for error 120 in ResolveSimpleName).
660 // FIXME: Potential optimization, have a static ArrayList
663 public static Expression MemberLookup (Type container_type, Type queried_type, string name,
664 MemberTypes mt, BindingFlags bf, Location loc)
666 return MemberLookup (container_type, null, queried_type, name, mt, bf, loc);
670 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
671 // `qualifier_type' or null to lookup members in the current class.
674 public static Expression MemberLookup (Type container_type,
675 Type qualifier_type, Type queried_type,
676 string name, MemberTypes mt,
677 BindingFlags bf, Location loc)
679 almost_matched_members.Clear ();
681 MemberInfo [] mi = TypeManager.MemberLookup (container_type, qualifier_type,
682 queried_type, mt, bf, name, almost_matched_members);
688 bool is_interface = qualifier_type != null && qualifier_type.IsInterface;
689 ArrayList methods = new ArrayList (2);
690 ArrayList non_methods = null;
692 foreach (MemberInfo m in mi) {
693 if (m is MethodBase) {
698 if (non_methods == null) {
699 non_methods = new ArrayList (2);
704 foreach (MemberInfo n_m in non_methods) {
705 if (m.DeclaringType.IsInterface && TypeManager.ImplementsInterface (m.DeclaringType, n_m.DeclaringType))
708 Report.SymbolRelatedToPreviousError (m);
709 Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
710 TypeManager.GetFullNameSignature (m), TypeManager.GetFullNameSignature (n_m));
715 if (methods.Count == 0)
716 return ExprClassFromMemberInfo (container_type, (MemberInfo)non_methods [0], loc);
718 if (non_methods != null) {
719 MethodBase method = (MethodBase) methods [0];
720 MemberInfo non_method = (MemberInfo) non_methods [0];
721 if (method.DeclaringType == non_method.DeclaringType) {
722 // Cannot happen with C# code, but is valid in IL
723 Report.SymbolRelatedToPreviousError (method);
724 Report.SymbolRelatedToPreviousError (non_method);
725 Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
726 TypeManager.GetFullNameSignature (non_method),
727 TypeManager.CSharpSignature (method));
732 Report.SymbolRelatedToPreviousError (method);
733 Report.SymbolRelatedToPreviousError (non_method);
734 Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and non-method `{1}'. Using method `{0}'",
735 TypeManager.CSharpSignature (method), TypeManager.GetFullNameSignature (non_method));
739 return new MethodGroupExpr (methods, queried_type, loc);
742 if (mi [0] is MethodBase)
743 return new MethodGroupExpr (mi, queried_type, loc);
745 return ExprClassFromMemberInfo (container_type, mi [0], loc);
748 public const MemberTypes AllMemberTypes =
749 MemberTypes.Constructor |
753 MemberTypes.NestedType |
754 MemberTypes.Property;
756 public const BindingFlags AllBindingFlags =
757 BindingFlags.Public |
758 BindingFlags.Static |
759 BindingFlags.Instance;
761 public static Expression MemberLookup (Type container_type, Type queried_type,
762 string name, Location loc)
764 return MemberLookup (container_type, null, queried_type, name,
765 AllMemberTypes, AllBindingFlags, loc);
768 public static Expression MemberLookup (Type container_type, Type qualifier_type,
769 Type queried_type, string name, Location loc)
771 return MemberLookup (container_type, qualifier_type, queried_type,
772 name, AllMemberTypes, AllBindingFlags, loc);
775 public static MethodGroupExpr MethodLookup (Type container_type, Type queried_type,
776 string name, Location loc)
778 return (MethodGroupExpr)MemberLookup (container_type, null, queried_type, name,
779 MemberTypes.Method, AllBindingFlags, loc);
783 /// This is a wrapper for MemberLookup that is not used to "probe", but
784 /// to find a final definition. If the final definition is not found, we
785 /// look for private members and display a useful debugging message if we
788 protected Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
789 Type queried_type, string name,
790 MemberTypes mt, BindingFlags bf,
795 int errors = Report.Errors;
797 e = MemberLookup (ec.ContainerType, qualifier_type, queried_type, name, mt, bf, loc);
799 if (e != null || errors != Report.Errors)
802 // No errors were reported by MemberLookup, but there was an error.
803 return Error_MemberLookupFailed (ec.ContainerType, qualifier_type, queried_type,
807 protected virtual Expression Error_MemberLookupFailed (Type container_type, Type qualifier_type,
808 Type queried_type, string name, string class_name,
809 MemberTypes mt, BindingFlags bf)
811 if (almost_matched_members.Count != 0) {
812 for (int i = 0; i < almost_matched_members.Count; ++i) {
813 MemberInfo m = (MemberInfo) almost_matched_members [i];
814 for (int j = 0; j < i; ++j) {
815 if (m == almost_matched_members [j]) {
823 Type declaring_type = m.DeclaringType;
825 Report.SymbolRelatedToPreviousError (m);
826 if (qualifier_type == null) {
827 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
828 TypeManager.CSharpName (m.DeclaringType),
829 TypeManager.CSharpName (container_type));
831 } else if (qualifier_type != container_type &&
832 TypeManager.IsNestedFamilyAccessible (container_type, declaring_type)) {
833 // Although a derived class can access protected members of
834 // its base class it cannot do so through an instance of the
835 // base class (CS1540). If the qualifier_type is a base of the
836 // ec.ContainerType and the lookup succeeds with the latter one,
837 // then we are in this situation.
838 Error_CannotAccessProtected (loc, m, qualifier_type, container_type);
840 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (m));
843 almost_matched_members.Clear ();
847 MemberInfo[] lookup = null;
848 if (queried_type == null) {
849 class_name = "global::";
851 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
852 mt, (bf & ~BindingFlags.Public) | BindingFlags.NonPublic,
855 if (lookup != null) {
856 Report.SymbolRelatedToPreviousError (lookup [0]);
857 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (lookup [0]));
858 return Error_MemberLookupFailed (lookup);
861 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
862 AllMemberTypes, AllBindingFlags | BindingFlags.NonPublic,
866 if (lookup == null) {
867 if (class_name != null) {
868 Report.Error (103, loc, "The name `{0}' does not exist in the current context",
871 Error_TypeDoesNotContainDefinition (queried_type, name);
876 if (TypeManager.MemberLookup (queried_type, null, queried_type,
877 AllMemberTypes, AllBindingFlags |
878 BindingFlags.NonPublic, name, null) == null) {
879 if ((lookup.Length == 1) && (lookup [0] is Type)) {
880 Type t = (Type) lookup [0];
882 Report.Error (305, loc,
883 "Using the generic type `{0}' " +
884 "requires {1} type arguments",
885 TypeManager.CSharpName (t),
886 TypeManager.GetNumberOfTypeArguments (t).ToString ());
891 return Error_MemberLookupFailed (lookup);
894 protected virtual Expression Error_MemberLookupFailed (MemberInfo[] members)
896 for (int i = 0; i < members.Length; ++i) {
897 if (!(members [i] is MethodBase))
901 // By default propagate the closest candidates upwards
902 return new MethodGroupExpr (members, type, loc);
905 protected virtual void Error_NegativeArrayIndex (Location loc)
907 throw new NotImplementedException ();
911 /// Returns an expression that can be used to invoke operator true
912 /// on the expression if it exists.
914 static public Expression GetOperatorTrue (EmitContext ec, Expression e, Location loc)
916 return GetOperatorTrueOrFalse (ec, e, true, loc);
920 /// Returns an expression that can be used to invoke operator false
921 /// on the expression if it exists.
923 static public Expression GetOperatorFalse (EmitContext ec, Expression e, Location loc)
925 return GetOperatorTrueOrFalse (ec, e, false, loc);
928 static Expression GetOperatorTrueOrFalse (EmitContext ec, Expression e, bool is_true, Location loc)
930 MethodGroupExpr operator_group;
931 operator_group = MethodLookup (ec.ContainerType, e.Type, is_true ? "op_True" : "op_False", loc) as MethodGroupExpr;
932 if (operator_group == null)
935 ArrayList arguments = new ArrayList (1);
936 arguments.Add (new Argument (e, Argument.AType.Expression));
937 operator_group = operator_group.OverloadResolve (
938 ec, ref arguments, false, loc);
940 if (operator_group == null)
943 return new UserOperatorCall (operator_group, arguments, null, loc);
947 /// Resolves the expression `e' into a boolean expression: either through
948 /// an implicit conversion, or through an `operator true' invocation
950 public static Expression ResolveBoolean (EmitContext ec, Expression e, Location loc)
956 if (e.Type == TypeManager.bool_type)
959 Expression converted = Convert.ImplicitConversion (ec, e, TypeManager.bool_type, Location.Null);
961 if (converted != null)
965 // If no implicit conversion to bool exists, try using `operator true'
967 converted = Expression.GetOperatorTrue (ec, e, loc);
968 if (converted == null){
969 e.Error_ValueCannotBeConverted (ec, loc, TypeManager.bool_type, false);
975 public virtual string ExprClassName
979 case ExprClass.Invalid:
981 case ExprClass.Value:
983 case ExprClass.Variable:
985 case ExprClass.Namespace:
989 case ExprClass.MethodGroup:
990 return "method group";
991 case ExprClass.PropertyAccess:
992 return "property access";
993 case ExprClass.EventAccess:
994 return "event access";
995 case ExprClass.IndexerAccess:
996 return "indexer access";
997 case ExprClass.Nothing:
1000 throw new Exception ("Should not happen");
1005 /// Reports that we were expecting `expr' to be of class `expected'
1007 public void Error_UnexpectedKind (DeclSpace ds, string expected, Location loc)
1009 Error_UnexpectedKind (ds, expected, ExprClassName, loc);
1012 public void Error_UnexpectedKind (DeclSpace ds, string expected, string was, Location loc)
1014 string name = GetSignatureForError ();
1016 name = ds.GetSignatureForError () + '.' + name;
1018 Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
1019 name, was, expected);
1022 public void Error_UnexpectedKind (ResolveFlags flags, Location loc)
1024 string [] valid = new string [4];
1027 if ((flags & ResolveFlags.VariableOrValue) != 0) {
1028 valid [count++] = "variable";
1029 valid [count++] = "value";
1032 if ((flags & ResolveFlags.Type) != 0)
1033 valid [count++] = "type";
1035 if ((flags & ResolveFlags.MethodGroup) != 0)
1036 valid [count++] = "method group";
1039 valid [count++] = "unknown";
1041 StringBuilder sb = new StringBuilder (valid [0]);
1042 for (int i = 1; i < count - 1; i++) {
1044 sb.Append (valid [i]);
1047 sb.Append ("' or `");
1048 sb.Append (valid [count - 1]);
1051 Report.Error (119, loc,
1052 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1055 public static void UnsafeError (Location loc)
1057 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1061 // Load the object from the pointer.
1063 public static void LoadFromPtr (ILGenerator ig, Type t)
1065 if (t == TypeManager.int32_type)
1066 ig.Emit (OpCodes.Ldind_I4);
1067 else if (t == TypeManager.uint32_type)
1068 ig.Emit (OpCodes.Ldind_U4);
1069 else if (t == TypeManager.short_type)
1070 ig.Emit (OpCodes.Ldind_I2);
1071 else if (t == TypeManager.ushort_type)
1072 ig.Emit (OpCodes.Ldind_U2);
1073 else if (t == TypeManager.char_type)
1074 ig.Emit (OpCodes.Ldind_U2);
1075 else if (t == TypeManager.byte_type)
1076 ig.Emit (OpCodes.Ldind_U1);
1077 else if (t == TypeManager.sbyte_type)
1078 ig.Emit (OpCodes.Ldind_I1);
1079 else if (t == TypeManager.uint64_type)
1080 ig.Emit (OpCodes.Ldind_I8);
1081 else if (t == TypeManager.int64_type)
1082 ig.Emit (OpCodes.Ldind_I8);
1083 else if (t == TypeManager.float_type)
1084 ig.Emit (OpCodes.Ldind_R4);
1085 else if (t == TypeManager.double_type)
1086 ig.Emit (OpCodes.Ldind_R8);
1087 else if (t == TypeManager.bool_type)
1088 ig.Emit (OpCodes.Ldind_I1);
1089 else if (t == TypeManager.intptr_type)
1090 ig.Emit (OpCodes.Ldind_I);
1091 else if (TypeManager.IsEnumType (t)) {
1092 if (t == TypeManager.enum_type)
1093 ig.Emit (OpCodes.Ldind_Ref);
1095 LoadFromPtr (ig, TypeManager.GetEnumUnderlyingType (t));
1096 } else if (t.IsValueType || TypeManager.IsGenericParameter (t))
1097 ig.Emit (OpCodes.Ldobj, t);
1098 else if (t.IsPointer)
1099 ig.Emit (OpCodes.Ldind_I);
1101 ig.Emit (OpCodes.Ldind_Ref);
1105 // The stack contains the pointer and the value of type `type'
1107 public static void StoreFromPtr (ILGenerator ig, Type type)
1109 if (TypeManager.IsEnumType (type))
1110 type = TypeManager.GetEnumUnderlyingType (type);
1111 if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
1112 ig.Emit (OpCodes.Stind_I4);
1113 else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
1114 ig.Emit (OpCodes.Stind_I8);
1115 else if (type == TypeManager.char_type || type == TypeManager.short_type ||
1116 type == TypeManager.ushort_type)
1117 ig.Emit (OpCodes.Stind_I2);
1118 else if (type == TypeManager.float_type)
1119 ig.Emit (OpCodes.Stind_R4);
1120 else if (type == TypeManager.double_type)
1121 ig.Emit (OpCodes.Stind_R8);
1122 else if (type == TypeManager.byte_type || type == TypeManager.sbyte_type ||
1123 type == TypeManager.bool_type)
1124 ig.Emit (OpCodes.Stind_I1);
1125 else if (type == TypeManager.intptr_type)
1126 ig.Emit (OpCodes.Stind_I);
1127 else if (type.IsValueType || TypeManager.IsGenericParameter (type))
1128 ig.Emit (OpCodes.Stobj, type);
1130 ig.Emit (OpCodes.Stind_Ref);
1134 // Returns the size of type `t' if known, otherwise, 0
1136 public static int GetTypeSize (Type t)
1138 t = TypeManager.TypeToCoreType (t);
1139 if (t == TypeManager.int32_type ||
1140 t == TypeManager.uint32_type ||
1141 t == TypeManager.float_type)
1143 else if (t == TypeManager.int64_type ||
1144 t == TypeManager.uint64_type ||
1145 t == TypeManager.double_type)
1147 else if (t == TypeManager.byte_type ||
1148 t == TypeManager.sbyte_type ||
1149 t == TypeManager.bool_type)
1151 else if (t == TypeManager.short_type ||
1152 t == TypeManager.char_type ||
1153 t == TypeManager.ushort_type)
1155 else if (t == TypeManager.decimal_type)
1161 protected void Error_CannotCallAbstractBase (string name)
1163 Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
1166 protected void Error_CannotModifyIntermediateExpressionValue (EmitContext ec)
1168 Report.SymbolRelatedToPreviousError (type);
1169 if (ec.CurrentInitializerVariable != null) {
1170 Report.Error (1918, loc, "Members of a value type property `{0}' cannot be assigned with an object initializer",
1171 GetSignatureForError ());
1173 Report.Error (1612, loc, "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
1174 GetSignatureForError ());
1179 // Converts `source' to an int, uint, long or ulong.
1181 public Expression ConvertExpressionToArrayIndex (EmitContext ec, Expression source)
1183 Expression converted;
1185 using (ec.With (EmitContext.Flags.CheckState, true)) {
1186 converted = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, source.loc);
1187 if (converted == null)
1188 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, source.loc);
1189 if (converted == null)
1190 converted = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, source.loc);
1191 if (converted == null)
1192 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, source.loc);
1194 if (converted == null) {
1195 source.Error_ValueCannotBeConverted (ec, source.loc, TypeManager.int32_type, false);
1201 // Only positive constants are allowed at compile time
1203 Constant c = converted as Constant;
1206 Error_NegativeArrayIndex (source.loc);
1211 return new ArrayIndexCast (converted).Resolve (ec);
1215 // Derived classes implement this method by cloning the fields that
1216 // could become altered during the Resolve stage
1218 // Only expressions that are created for the parser need to implement
1221 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1223 throw new NotImplementedException (
1225 "CloneTo not implemented for expression {0}", this.GetType ()));
1229 // Clones an expression created by the parser.
1231 // We only support expressions created by the parser so far, not
1232 // expressions that have been resolved (many more classes would need
1233 // to implement CloneTo).
1235 // This infrastructure is here merely for Lambda expressions which
1236 // compile the same code using different type values for the same
1237 // arguments to find the correct overload
1239 public Expression Clone (CloneContext clonectx)
1241 Expression cloned = (Expression) MemberwiseClone ();
1242 CloneTo (clonectx, cloned);
1247 public virtual Expression CreateExpressionTree (EmitContext ec)
1249 throw new NotImplementedException (
1250 "Expression tree conversion not implemented for " + GetType ());
1253 protected Expression CreateExpressionFactoryCall (string name, ArrayList args)
1255 return CreateExpressionFactoryCall (name, null, args, loc);
1258 protected Expression CreateExpressionFactoryCall (string name, TypeArguments typeArguments, ArrayList args)
1260 return CreateExpressionFactoryCall (name, typeArguments, args, loc);
1263 public static Expression CreateExpressionFactoryCall (string name, TypeArguments typeArguments, ArrayList args, Location loc)
1265 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (loc), name, typeArguments, loc), args);
1268 protected static TypeExpr CreateExpressionTypeExpression (Location loc)
1270 TypeExpr texpr = TypeManager.expression_type_expr;
1271 if (texpr == null) {
1272 Type t = TypeManager.CoreLookupType ("System.Linq.Expressions", "Expression", Kind.Class, true);
1276 TypeManager.expression_type_expr = texpr = new TypeExpression (t, Location.Null);
1284 /// This is just a base class for expressions that can
1285 /// appear on statements (invocations, object creation,
1286 /// assignments, post/pre increment and decrement). The idea
1287 /// being that they would support an extra Emition interface that
1288 /// does not leave a result on the stack.
1290 public abstract class ExpressionStatement : Expression {
1292 public virtual ExpressionStatement ResolveStatement (EmitContext ec)
1294 Expression e = Resolve (ec);
1298 ExpressionStatement es = e as ExpressionStatement;
1300 Error_InvalidExpressionStatement ();
1306 /// Requests the expression to be emitted in a `statement'
1307 /// context. This means that no new value is left on the
1308 /// stack after invoking this method (constrasted with
1309 /// Emit that will always leave a value on the stack).
1311 public abstract void EmitStatement (EmitContext ec);
1313 public override void EmitSideEffect (EmitContext ec)
1320 /// This kind of cast is used to encapsulate the child
1321 /// whose type is child.Type into an expression that is
1322 /// reported to return "return_type". This is used to encapsulate
1323 /// expressions which have compatible types, but need to be dealt
1324 /// at higher levels with.
1326 /// For example, a "byte" expression could be encapsulated in one
1327 /// of these as an "unsigned int". The type for the expression
1328 /// would be "unsigned int".
1331 public abstract class TypeCast : Expression
1333 protected Expression child;
1335 protected TypeCast (Expression child, Type return_type)
1337 eclass = child.eclass;
1338 loc = child.Location;
1343 public override Expression CreateExpressionTree (EmitContext ec)
1345 ArrayList args = new ArrayList (2);
1346 args.Add (new Argument (child.CreateExpressionTree (ec)));
1347 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1348 return CreateExpressionFactoryCall (ec.CheckState ? "ConvertChecked" : "Convert", args);
1351 public override Expression DoResolve (EmitContext ec)
1353 // This should never be invoked, we are born in fully
1354 // initialized state.
1359 public override void Emit (EmitContext ec)
1364 public override bool GetAttributableValue (Type value_type, out object value)
1366 return child.GetAttributableValue (value_type, out value);
1369 protected override void CloneTo (CloneContext clonectx, Expression t)
1371 TypeCast target = (TypeCast) t;
1373 target.child = child.Clone (clonectx);
1377 public class EmptyCast : TypeCast {
1378 EmptyCast (Expression child, Type target_type)
1379 : base (child, target_type)
1383 public static Expression Create (Expression child, Type type)
1385 Constant c = child as Constant;
1387 return new EmptyConstantCast (c, type);
1389 return new EmptyCast (child, type);
1392 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1394 child.EmitBranchable (ec, label, on_true);
1397 public override void EmitSideEffect (EmitContext ec)
1399 child.EmitSideEffect (ec);
1405 /// Performs a cast using an operator (op_Explicit or op_Implicit)
1407 public class OperatorCast : TypeCast {
1408 MethodInfo conversion_operator;
1411 public OperatorCast (Expression child, Type target_type) : this (child, target_type, false) {}
1413 public OperatorCast (Expression child, Type target_type, bool find_explicit)
1414 : base (child, target_type)
1416 this.find_explicit = find_explicit;
1419 // Returns the implicit operator that converts from
1420 // 'child.Type' to our target type (type)
1421 MethodInfo GetConversionOperator (bool find_explicit)
1423 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1427 mi = TypeManager.MemberLookup (child.Type, child.Type, child.Type, MemberTypes.Method,
1428 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1431 mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1432 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1435 foreach (MethodInfo oper in mi) {
1436 ParameterData pd = TypeManager.GetParameterData (oper);
1438 if (pd.ParameterType (0) == child.Type && TypeManager.TypeToCoreType (oper.ReturnType) == type)
1446 public override void Emit (EmitContext ec)
1448 ILGenerator ig = ec.ig;
1451 conversion_operator = GetConversionOperator (find_explicit);
1453 if (conversion_operator == null)
1454 throw new InternalErrorException ("Outer conversion routine is out of sync");
1456 ig.Emit (OpCodes.Call, conversion_operator);
1462 /// This is a numeric cast to a Decimal
1464 public class CastToDecimal : TypeCast {
1465 MethodInfo conversion_operator;
1467 public CastToDecimal (Expression child)
1468 : this (child, false)
1472 public CastToDecimal (Expression child, bool find_explicit)
1473 : base (child, TypeManager.decimal_type)
1475 conversion_operator = GetConversionOperator (find_explicit);
1477 if (conversion_operator == null)
1478 throw new InternalErrorException ("Outer conversion routine is out of sync");
1481 // Returns the implicit operator that converts from
1482 // 'child.Type' to System.Decimal.
1483 MethodInfo GetConversionOperator (bool find_explicit)
1485 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1487 MemberInfo [] mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1488 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1490 foreach (MethodInfo oper in mi) {
1491 ParameterData pd = TypeManager.GetParameterData (oper);
1493 if (pd.ParameterType (0) == child.Type && TypeManager.TypeToCoreType (oper.ReturnType) == type)
1499 public override void Emit (EmitContext ec)
1501 ILGenerator ig = ec.ig;
1504 ig.Emit (OpCodes.Call, conversion_operator);
1509 /// This is an explicit numeric cast from a Decimal
1511 public class CastFromDecimal : TypeCast
1513 static IDictionary operators;
1515 public CastFromDecimal (Expression child, Type return_type)
1516 : base (child, return_type)
1518 if (child.Type != TypeManager.decimal_type)
1519 throw new InternalErrorException (
1520 "The expected type is Decimal, instead it is " + child.Type.FullName);
1523 // Returns the explicit operator that converts from an
1524 // express of type System.Decimal to 'type'.
1525 public Expression Resolve ()
1527 if (operators == null) {
1528 MemberInfo[] all_oper = TypeManager.MemberLookup (TypeManager.decimal_type,
1529 TypeManager.decimal_type, TypeManager.decimal_type, MemberTypes.Method,
1530 BindingFlags.Static | BindingFlags.Public, "op_Explicit", null);
1532 operators = new System.Collections.Specialized.HybridDictionary ();
1533 foreach (MethodInfo oper in all_oper) {
1534 ParameterData pd = TypeManager.GetParameterData (oper);
1535 if (pd.ParameterType (0) == TypeManager.decimal_type)
1536 operators.Add (TypeManager.TypeToCoreType (oper.ReturnType), oper);
1540 return operators.Contains (type) ? this : null;
1543 public override void Emit (EmitContext ec)
1545 ILGenerator ig = ec.ig;
1548 ig.Emit (OpCodes.Call, (MethodInfo)operators [type]);
1554 // Constant specialization of EmptyCast.
1555 // We need to special case this since an empty cast of
1556 // a constant is still a constant.
1558 public class EmptyConstantCast : Constant
1560 public readonly Constant child;
1562 public EmptyConstantCast(Constant child, Type type)
1563 : base (child.Location)
1565 eclass = child.eclass;
1570 public override string AsString ()
1572 return child.AsString ();
1575 public override object GetValue ()
1577 return child.GetValue ();
1580 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
1582 // FIXME: check that 'type' can be converted to 'target_type' first
1583 return child.ConvertExplicitly (in_checked_context, target_type);
1586 public override Expression CreateExpressionTree (EmitContext ec)
1588 ArrayList args = new ArrayList (2);
1589 args.Add (new Argument (child.CreateExpressionTree (ec)));
1590 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1591 return CreateExpressionFactoryCall ("Convert", args);
1594 public override Constant Increment ()
1596 return child.Increment ();
1599 public override bool IsDefaultValue {
1600 get { return child.IsDefaultValue; }
1603 public override bool IsNegative {
1604 get { return child.IsNegative; }
1607 public override bool IsNull {
1608 get { return child.IsNull; }
1611 public override bool IsZeroInteger {
1612 get { return child.IsZeroInteger; }
1615 public override void Emit (EmitContext ec)
1620 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1622 child.EmitBranchable (ec, label, on_true);
1625 public override void EmitSideEffect (EmitContext ec)
1627 child.EmitSideEffect (ec);
1630 public override Constant ConvertImplicitly (Type target_type)
1632 // FIXME: Do we need to check user conversions?
1633 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1635 return child.ConvertImplicitly (target_type);
1641 /// This class is used to wrap literals which belong inside Enums
1643 public class EnumConstant : Constant {
1644 public Constant Child;
1646 public EnumConstant (Constant child, Type enum_type):
1647 base (child.Location)
1649 eclass = child.eclass;
1654 public override Expression DoResolve (EmitContext ec)
1656 // This should never be invoked, we are born in fully
1657 // initialized state.
1662 public override void Emit (EmitContext ec)
1667 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1669 Child.EmitBranchable (ec, label, on_true);
1672 public override void EmitSideEffect (EmitContext ec)
1674 Child.EmitSideEffect (ec);
1677 public override bool GetAttributableValue (Type value_type, out object value)
1679 value = GetTypedValue ();
1683 public override string GetSignatureForError()
1685 return TypeManager.CSharpName (Type);
1688 public override object GetValue ()
1690 return Child.GetValue ();
1693 public override object GetTypedValue ()
1695 // FIXME: runtime is not ready to work with just emited enums
1696 if (!RootContext.StdLib) {
1697 return Child.GetValue ();
1700 return System.Enum.ToObject (type, Child.GetValue ());
1703 public override string AsString ()
1705 return TypeManager.CSharpEnumValue (type, Child.GetValue ());
1708 public override Constant Increment()
1710 return new EnumConstant (Child.Increment (), type);
1713 public override bool IsDefaultValue {
1715 return Child.IsDefaultValue;
1719 public override bool IsZeroInteger {
1720 get { return Child.IsZeroInteger; }
1723 public override bool IsNegative {
1725 return Child.IsNegative;
1729 public override Constant ConvertExplicitly(bool in_checked_context, Type target_type)
1731 if (Child.Type == target_type)
1734 return Child.ConvertExplicitly (in_checked_context, target_type);
1737 public override Constant ConvertImplicitly (Type type)
1739 Type this_type = TypeManager.DropGenericTypeArguments (Type);
1740 type = TypeManager.DropGenericTypeArguments (type);
1742 if (this_type == type) {
1743 // This is workaround of mono bug. It can be removed when the latest corlib spreads enough
1744 if (TypeManager.IsEnumType (type.UnderlyingSystemType))
1747 Type child_type = TypeManager.DropGenericTypeArguments (Child.Type);
1748 if (type.UnderlyingSystemType != child_type)
1749 Child = Child.ConvertImplicitly (type.UnderlyingSystemType);
1753 if (!Convert.ImplicitStandardConversionExists (this, type)){
1757 return Child.ConvertImplicitly(type);
1763 /// This kind of cast is used to encapsulate Value Types in objects.
1765 /// The effect of it is to box the value type emitted by the previous
1768 public class BoxedCast : TypeCast {
1770 public BoxedCast (Expression expr, Type target_type)
1771 : base (expr, target_type)
1773 eclass = ExprClass.Value;
1776 public override Expression DoResolve (EmitContext ec)
1778 // This should never be invoked, we are born in fully
1779 // initialized state.
1784 public override void Emit (EmitContext ec)
1788 ec.ig.Emit (OpCodes.Box, child.Type);
1791 public override void EmitSideEffect (EmitContext ec)
1793 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1794 // so, we need to emit the box+pop instructions in most cases
1795 if (child.Type.IsValueType &&
1796 (type == TypeManager.object_type || type == TypeManager.value_type))
1797 child.EmitSideEffect (ec);
1799 base.EmitSideEffect (ec);
1803 public class UnboxCast : TypeCast {
1804 public UnboxCast (Expression expr, Type return_type)
1805 : base (expr, return_type)
1809 public override Expression DoResolve (EmitContext ec)
1811 // This should never be invoked, we are born in fully
1812 // initialized state.
1817 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1819 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
1820 Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
1821 return base.DoResolveLValue (ec, right_side);
1824 public override void Emit (EmitContext ec)
1827 ILGenerator ig = ec.ig;
1831 if (t.IsGenericParameter || t.IsGenericType && t.IsValueType)
1832 ig.Emit (OpCodes.Unbox_Any, t);
1836 ig.Emit (OpCodes.Unbox, t);
1838 LoadFromPtr (ig, t);
1844 /// This is used to perform explicit numeric conversions.
1846 /// Explicit numeric conversions might trigger exceptions in a checked
1847 /// context, so they should generate the conv.ovf opcodes instead of
1850 public class ConvCast : TypeCast {
1851 public enum Mode : byte {
1852 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1854 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1855 U2_I1, U2_U1, U2_I2, U2_CH,
1856 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1857 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1858 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH,
1859 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH,
1860 CH_I1, CH_U1, CH_I2,
1861 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1862 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4
1867 public ConvCast (Expression child, Type return_type, Mode m)
1868 : base (child, return_type)
1873 public override Expression DoResolve (EmitContext ec)
1875 // This should never be invoked, we are born in fully
1876 // initialized state.
1881 public override string ToString ()
1883 return String.Format ("ConvCast ({0}, {1})", mode, child);
1886 public override void Emit (EmitContext ec)
1888 ILGenerator ig = ec.ig;
1894 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1895 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1896 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1897 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1898 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1900 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1901 case Mode.U1_CH: /* nothing */ break;
1903 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1904 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1905 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1906 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1907 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1908 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1910 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1911 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1912 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1913 case Mode.U2_CH: /* nothing */ break;
1915 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1916 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1917 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1918 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1919 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1920 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1921 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1923 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1924 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1925 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1926 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1927 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1928 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1930 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1931 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1932 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1933 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1934 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1935 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1936 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1937 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1939 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1940 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1941 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1942 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1943 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1944 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1945 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1946 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1948 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1949 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1950 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1952 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1953 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1954 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1955 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1956 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1957 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1958 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1959 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1960 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1962 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1963 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1964 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1965 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1966 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1967 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1968 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1969 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1970 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1971 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1975 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
1976 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
1977 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
1978 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
1979 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
1981 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
1982 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
1984 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
1985 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
1986 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
1987 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
1988 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
1989 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
1991 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
1992 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
1993 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
1994 case Mode.U2_CH: /* nothing */ break;
1996 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
1997 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
1998 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
1999 case Mode.I4_U4: /* nothing */ break;
2000 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
2001 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
2002 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
2004 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
2005 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
2006 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
2007 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
2008 case Mode.U4_I4: /* nothing */ break;
2009 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
2011 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
2012 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
2013 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
2014 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
2015 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
2016 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
2017 case Mode.I8_U8: /* nothing */ break;
2018 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
2020 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
2021 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
2022 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
2023 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
2024 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
2025 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
2026 case Mode.U8_I8: /* nothing */ break;
2027 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
2029 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
2030 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
2031 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
2033 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
2034 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
2035 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
2036 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
2037 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
2038 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
2039 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
2040 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
2041 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
2043 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
2044 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
2045 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
2046 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
2047 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
2048 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
2049 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
2050 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
2051 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
2052 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
2058 public class OpcodeCast : TypeCast {
2062 public OpcodeCast (Expression child, Type return_type, OpCode op)
2063 : base (child, return_type)
2067 second_valid = false;
2070 public OpcodeCast (Expression child, Type return_type, OpCode op, OpCode op2)
2071 : base (child, return_type)
2076 second_valid = true;
2079 public override Expression DoResolve (EmitContext ec)
2081 // This should never be invoked, we are born in fully
2082 // initialized state.
2087 public override void Emit (EmitContext ec)
2096 public Type UnderlyingType {
2097 get { return child.Type; }
2102 /// This kind of cast is used to encapsulate a child and cast it
2103 /// to the class requested
2105 public class ClassCast : TypeCast {
2106 public ClassCast (Expression child, Type return_type)
2107 : base (child, return_type)
2112 public override Expression DoResolve (EmitContext ec)
2114 // This should never be invoked, we are born in fully
2115 // initialized state.
2120 public override void Emit (EmitContext ec)
2124 if (TypeManager.IsGenericParameter (child.Type))
2125 ec.ig.Emit (OpCodes.Box, child.Type);
2128 if (type.IsGenericParameter)
2129 ec.ig.Emit (OpCodes.Unbox_Any, type);
2132 ec.ig.Emit (OpCodes.Castclass, type);
2137 // Used when resolved expression has different representations for
2138 // expression trees and emit phase
2140 public class ReducedExpression : Expression
2142 class ReducedConstantExpression : Constant
2144 readonly Constant expr;
2145 readonly Expression orig_expr;
2147 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2148 : base (expr.Location)
2151 this.orig_expr = orig_expr;
2152 eclass = expr.eclass;
2156 public override string AsString ()
2158 return expr.AsString ();
2161 public override Expression CreateExpressionTree (EmitContext ec)
2163 return orig_expr.CreateExpressionTree (ec);
2166 public override object GetValue ()
2168 return expr.GetValue ();
2171 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
2173 throw new NotImplementedException ();
2176 public override Expression DoResolve (EmitContext ec)
2181 public override Constant Increment ()
2183 throw new NotImplementedException ();
2186 public override bool IsDefaultValue {
2188 return expr.IsDefaultValue;
2192 public override bool IsNegative {
2194 return expr.IsNegative;
2198 public override void Emit (EmitContext ec)
2204 readonly Expression expr, orig_expr;
2206 private ReducedExpression (Expression expr, Expression orig_expr)
2209 this.orig_expr = orig_expr;
2210 this.loc = orig_expr.Location;
2213 public static Expression Create (Constant expr, Expression original_expr)
2215 return new ReducedConstantExpression (expr, original_expr);
2218 public static Expression Create (Expression expr, Expression original_expr)
2220 Constant c = expr as Constant;
2222 return Create (c, original_expr);
2224 return new ReducedExpression (expr, original_expr);
2227 public override Expression CreateExpressionTree (EmitContext ec)
2229 return orig_expr.CreateExpressionTree (ec);
2232 public override Expression DoResolve (EmitContext ec)
2234 eclass = expr.eclass;
2239 public override void Emit (EmitContext ec)
2244 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2246 expr.EmitBranchable (ec, target, on_true);
2251 // Unresolved type name expressions
2253 public abstract class ATypeNameExpression : FullNamedExpression
2255 public readonly string Name;
2256 protected TypeArguments targs;
2258 protected ATypeNameExpression (string name, Location l)
2264 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2271 public override string GetSignatureForError ()
2273 if (targs != null) {
2274 return TypeManager.RemoveGenericArity (Name) + "<" +
2275 targs.GetSignatureForError () + ">";
2283 /// SimpleName expressions are formed of a single word and only happen at the beginning
2284 /// of a dotted-name.
2286 public class SimpleName : ATypeNameExpression {
2289 public SimpleName (string name, Location l)
2294 public SimpleName (string name, TypeArguments args, Location l)
2295 : base (name, args, l)
2299 public SimpleName (string name, TypeParameter[] type_params, Location l)
2302 targs = new TypeArguments (l);
2303 foreach (TypeParameter type_param in type_params)
2304 targs.Add (new TypeParameterExpr (type_param, l));
2307 public static string RemoveGenericArity (string name)
2310 StringBuilder sb = null;
2312 int pos = name.IndexOf ('`', start);
2317 sb.Append (name.Substring (start));
2322 sb = new StringBuilder ();
2323 sb.Append (name.Substring (start, pos-start));
2326 while ((pos < name.Length) && Char.IsNumber (name [pos]))
2330 } while (start < name.Length);
2332 return sb.ToString ();
2335 public SimpleName GetMethodGroup ()
2337 return new SimpleName (RemoveGenericArity (Name), targs, loc);
2340 public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
2342 if (ec.IsInFieldInitializer)
2343 Report.Error (236, l,
2344 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2348 120, l, "`{0}': An object reference is required for the nonstatic field, method or property",
2352 public bool IdenticalNameAndTypeName (EmitContext ec, Expression resolved_to, Location loc)
2354 return resolved_to != null && resolved_to.Type != null &&
2355 resolved_to.Type.Name == Name &&
2356 (ec.DeclContainer.LookupNamespaceOrType (Name, loc, /* ignore_cs0104 = */ true) != null);
2359 public override Expression DoResolve (EmitContext ec)
2361 return SimpleNameResolve (ec, null, false);
2364 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
2366 return SimpleNameResolve (ec, right_side, false);
2370 public Expression DoResolve (EmitContext ec, bool intermediate)
2372 return SimpleNameResolve (ec, null, intermediate);
2375 static bool IsNestedChild (Type t, Type parent)
2377 while (parent != null) {
2378 if (TypeManager.IsNestedChildOf (t, TypeManager.DropGenericTypeArguments (parent)))
2381 parent = parent.BaseType;
2387 FullNamedExpression ResolveNested (IResolveContext ec, Type t)
2389 if (!TypeManager.IsGenericTypeDefinition (t) && !TypeManager.IsGenericType (t))
2392 DeclSpace ds = ec.DeclContainer;
2393 while (ds != null && !IsNestedChild (t, ds.TypeBuilder))
2399 Type[] gen_params = TypeManager.GetTypeArguments (t);
2401 int arg_count = targs != null ? targs.Count : 0;
2403 for (; (ds != null) && ds.IsGeneric; ds = ds.Parent) {
2404 if (arg_count + ds.CountTypeParameters == gen_params.Length) {
2405 TypeArguments new_args = new TypeArguments (loc);
2406 foreach (TypeParameter param in ds.TypeParameters)
2407 new_args.Add (new TypeParameterExpr (param, loc));
2410 new_args.Add (targs);
2412 return new ConstructedType (t, new_args, loc);
2419 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2421 FullNamedExpression fne = ec.GenericDeclContainer.LookupGeneric (Name, loc);
2423 return fne.ResolveAsTypeStep (ec, silent);
2425 int errors = Report.Errors;
2426 fne = ec.DeclContainer.LookupNamespaceOrType (Name, loc, /*ignore_cs0104=*/ false);
2429 if (fne.Type == null)
2432 FullNamedExpression nested = ResolveNested (ec, fne.Type);
2434 return nested.ResolveAsTypeStep (ec, false);
2436 if (targs != null) {
2437 ConstructedType ct = new ConstructedType (fne, targs, loc);
2438 return ct.ResolveAsTypeStep (ec, false);
2444 if (silent || errors != Report.Errors)
2447 Error_TypeOrNamespaceNotFound (ec);
2451 protected virtual void Error_TypeOrNamespaceNotFound (IResolveContext ec)
2453 MemberCore mc = ec.DeclContainer.GetDefinition (Name);
2455 Error_UnexpectedKind (ec.DeclContainer, "type", GetMemberType (mc), loc);
2459 string ns = ec.DeclContainer.NamespaceEntry.NS.Name;
2460 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2461 foreach (Assembly a in RootNamespace.Global.Assemblies) {
2462 Type type = a.GetType (fullname);
2464 Report.SymbolRelatedToPreviousError (type);
2465 Expression.ErrorIsInaccesible (loc, TypeManager.CSharpName (type));
2470 Type t = ec.DeclContainer.LookupAnyGeneric (Name);
2472 Namespace.Error_InvalidNumberOfTypeArguments (t, loc);
2476 if (targs != null) {
2477 FullNamedExpression retval = ec.DeclContainer.LookupNamespaceOrType (SimpleName.RemoveGenericArity (Name), loc, true);
2478 if (retval != null) {
2479 Namespace.Error_TypeArgumentsCannotBeUsed (retval.Type, loc);
2484 NamespaceEntry.Error_NamespaceNotFound (loc, Name);
2487 // TODO: I am still not convinced about this. If someone else will need it
2488 // implement this as virtual property in MemberCore hierarchy
2489 public static string GetMemberType (MemberCore mc)
2495 if (mc is FieldBase)
2497 if (mc is MethodCore)
2499 if (mc is EnumMember)
2507 Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2513 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2519 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2526 /// 7.5.2: Simple Names.
2528 /// Local Variables and Parameters are handled at
2529 /// parse time, so they never occur as SimpleNames.
2531 /// The `intermediate' flag is used by MemberAccess only
2532 /// and it is used to inform us that it is ok for us to
2533 /// avoid the static check, because MemberAccess might end
2534 /// up resolving the Name as a Type name and the access as
2535 /// a static type access.
2537 /// ie: Type Type; .... { Type.GetType (""); }
2539 /// Type is both an instance variable and a Type; Type.GetType
2540 /// is the static method not an instance method of type.
2542 Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2544 Expression e = null;
2547 // Stage 1: Performed by the parser (binding to locals or parameters).
2549 Block current_block = ec.CurrentBlock;
2550 if (current_block != null){
2551 LocalInfo vi = current_block.GetLocalInfo (Name);
2553 if (targs != null) {
2554 Report.Error (307, loc,
2555 "The variable `{0}' cannot be used with type arguments",
2560 LocalVariableReference var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2561 if (right_side != null) {
2562 return var.ResolveLValue (ec, right_side, loc);
2564 ResolveFlags rf = ResolveFlags.VariableOrValue;
2566 rf |= ResolveFlags.DisableFlowAnalysis;
2567 return var.Resolve (ec, rf);
2571 ParameterReference pref = current_block.Toplevel.GetParameterReference (Name, loc);
2573 if (targs != null) {
2574 Report.Error (307, loc,
2575 "The variable `{0}' cannot be used with type arguments",
2580 if (right_side != null)
2581 return pref.ResolveLValue (ec, right_side, loc);
2583 return pref.Resolve (ec);
2586 Expression expr = current_block.Toplevel.GetTransparentIdentifier (Name);
2588 if (right_side != null)
2589 return expr.ResolveLValue (ec, right_side, loc);
2590 return expr.Resolve (ec);
2595 // Stage 2: Lookup members
2598 Type almost_matched_type = null;
2599 ArrayList almost_matched = null;
2600 for (DeclSpace lookup_ds = ec.DeclContainer; lookup_ds != null; lookup_ds = lookup_ds.Parent) {
2601 // either RootDeclSpace or GenericMethod
2602 if (lookup_ds.TypeBuilder == null)
2605 e = MemberLookup (ec.ContainerType, lookup_ds.TypeBuilder, Name, loc);
2607 if (e is PropertyExpr) {
2608 // since TypeManager.MemberLookup doesn't know if we're doing a lvalue access or not,
2609 // it doesn't know which accessor to check permissions against
2610 if (((PropertyExpr) e).IsAccessibleFrom (ec.ContainerType, right_side != null))
2612 } else if (e is EventExpr) {
2613 if (((EventExpr) e).IsAccessibleFrom (ec.ContainerType))
2621 if (almost_matched == null && almost_matched_members.Count > 0) {
2622 almost_matched_type = lookup_ds.TypeBuilder;
2623 almost_matched = (ArrayList) almost_matched_members.Clone ();
2628 if (almost_matched == null && almost_matched_members.Count > 0) {
2629 almost_matched_type = ec.ContainerType;
2630 almost_matched = (ArrayList) almost_matched_members.Clone ();
2632 e = ResolveAsTypeStep (ec, true);
2636 if (current_block != null) {
2637 IKnownVariable ikv = current_block.Explicit.GetKnownVariable (Name);
2639 LocalInfo li = ikv as LocalInfo;
2640 // Supress CS0219 warning
2644 Error_VariableIsUsedBeforeItIsDeclared (Name);
2649 if (almost_matched != null)
2650 almost_matched_members = almost_matched;
2651 if (almost_matched_type == null)
2652 almost_matched_type = ec.ContainerType;
2653 Error_MemberLookupFailed (ec.ContainerType, null, almost_matched_type, Name,
2654 ec.DeclContainer.Name, AllMemberTypes, AllBindingFlags);
2658 if (e is TypeExpr) {
2662 ConstructedType ct = new ConstructedType (
2663 e.Type, targs, loc);
2664 return ct.ResolveAsTypeStep (ec, false);
2667 if (e is MemberExpr) {
2668 MemberExpr me = (MemberExpr) e;
2671 if (me.IsInstance) {
2672 if (ec.IsStatic || ec.IsInFieldInitializer) {
2674 // Note that an MemberExpr can be both IsInstance and IsStatic.
2675 // An unresolved MethodGroupExpr can contain both kinds of methods
2676 // and each predicate is true if the MethodGroupExpr contains
2677 // at least one of that kind of method.
2681 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2682 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2687 // Pass the buck to MemberAccess and Invocation.
2689 left = EmptyExpression.Null;
2691 left = ec.GetThis (loc);
2694 left = new TypeExpression (ec.ContainerType, loc);
2697 me = me.ResolveMemberAccess (ec, left, loc, null);
2701 if (targs != null) {
2703 me.SetTypeArguments (targs);
2706 if (!me.IsStatic && (me.InstanceExpression != null) &&
2707 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2708 me.InstanceExpression.Type != me.DeclaringType &&
2709 !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2710 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2711 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2712 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2716 return (right_side != null)
2717 ? me.DoResolveLValue (ec, right_side)
2718 : me.DoResolve (ec);
2724 protected override void CloneTo (CloneContext clonectx, Expression target)
2726 // CloneTo: Nothing, we do not keep any state on this expression
2731 /// Represents a namespace or a type. The name of the class was inspired by
2732 /// section 10.8.1 (Fully Qualified Names).
2734 public abstract class FullNamedExpression : Expression {
2735 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2740 public override void Emit (EmitContext ec)
2742 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2743 GetSignatureForError ());
2748 /// Expression that evaluates to a type
2750 public abstract class TypeExpr : FullNamedExpression {
2751 override public FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2753 TypeExpr t = DoResolveAsTypeStep (ec);
2757 eclass = ExprClass.Type;
2761 override public Expression DoResolve (EmitContext ec)
2763 return ResolveAsTypeTerminal (ec, false);
2766 public virtual bool CheckAccessLevel (DeclSpace ds)
2768 return ds.CheckAccessLevel (Type);
2771 public virtual bool AsAccessible (DeclSpace ds)
2773 return ds.IsAccessibleAs (Type);
2776 public virtual bool IsClass {
2777 get { return Type.IsClass; }
2780 public virtual bool IsValueType {
2781 get { return Type.IsValueType; }
2784 public virtual bool IsInterface {
2785 get { return Type.IsInterface; }
2788 public virtual bool IsSealed {
2789 get { return Type.IsSealed; }
2792 public virtual bool CanInheritFrom ()
2794 if (Type == TypeManager.enum_type ||
2795 (Type == TypeManager.value_type && RootContext.StdLib) ||
2796 Type == TypeManager.multicast_delegate_type ||
2797 Type == TypeManager.delegate_type ||
2798 Type == TypeManager.array_type)
2804 protected abstract TypeExpr DoResolveAsTypeStep (IResolveContext ec);
2806 public override bool Equals (object obj)
2808 TypeExpr tobj = obj as TypeExpr;
2812 return Type == tobj.Type;
2815 public override int GetHashCode ()
2817 return Type.GetHashCode ();
2822 /// Fully resolved Expression that already evaluated to a type
2824 public class TypeExpression : TypeExpr {
2825 public TypeExpression (Type t, Location l)
2828 eclass = ExprClass.Type;
2832 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2837 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2844 /// Used to create types from a fully qualified name. These are just used
2845 /// by the parser to setup the core types. A TypeLookupExpression is always
2846 /// classified as a type.
2848 public sealed class TypeLookupExpression : TypeExpr {
2849 readonly string name;
2851 public TypeLookupExpression (string name)
2854 eclass = ExprClass.Type;
2857 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2859 // It's null for corlib compilation only
2861 return DoResolveAsTypeStep (ec);
2866 private class UnexpectedType
2870 // This performes recursive type lookup, providing support for generic types.
2871 // For example, given the type:
2873 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]]
2875 // The types will be checked in the following order:
2878 // System.Collections |
2879 // System.Collections.Generic |
2881 // System | recursive call 1 |
2882 // System.Int32 _| | main method call
2884 // System | recursive call 2 |
2885 // System.String _| |
2887 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]] _|
2889 private Type TypeLookup (IResolveContext ec, string name)
2894 FullNamedExpression resolved = null;
2896 Type recursive_type = null;
2897 while (index < name.Length) {
2898 if (name[index] == '[') {
2903 if (name[index] == '[')
2905 else if (name[index] == ']')
2907 } while (braces > 0);
2908 recursive_type = TypeLookup (ec, name.Substring (open + 1, index - open - 1));
2909 if (recursive_type == null || (recursive_type == typeof(UnexpectedType)))
2910 return recursive_type;
2913 if (name[index] == ',')
2915 else if ((name[index] == '.' && !done) || (index == name.Length && name[0] != '[')) {
2916 string substring = name.Substring(dot, index - dot);
2918 if (resolved == null)
2919 resolved = RootNamespace.Global.Lookup (ec.DeclContainer, substring, Location.Null);
2920 else if (resolved is Namespace)
2921 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
2922 else if (type != null)
2923 type = TypeManager.GetNestedType (type, substring);
2927 if (resolved == null)
2929 else if (type == null && resolved is TypeExpr)
2930 type = resolved.Type;
2937 if (name[0] != '[') {
2938 string substring = name.Substring(dot, index - dot);
2941 return TypeManager.GetNestedType (type, substring);
2943 if (resolved != null) {
2944 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
2945 if (resolved is TypeExpr)
2946 return resolved.Type;
2948 if (resolved == null)
2951 resolved.Error_UnexpectedKind (ec.DeclContainer, "type", loc);
2952 return typeof (UnexpectedType);
2958 return recursive_type;
2961 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2963 Type t = TypeLookup (ec, name);
2965 NamespaceEntry.Error_NamespaceNotFound (loc, name);
2968 if (t == typeof(UnexpectedType))
2974 protected override void CloneTo (CloneContext clonectx, Expression target)
2976 // CloneTo: Nothing, we do not keep any state on this expression
2979 public override string GetSignatureForError ()
2982 return TypeManager.CSharpName (name);
2984 return base.GetSignatureForError ();
2989 /// Represents an "unbound generic type", ie. typeof (Foo<>).
2992 public class UnboundTypeExpression : TypeExpr
2996 public UnboundTypeExpression (MemberName name, Location l)
3002 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
3005 if (name.Left != null) {
3006 Expression lexpr = name.Left.GetTypeExpression ();
3007 expr = new MemberAccess (lexpr, name.Basename);
3009 expr = new SimpleName (name.Basename, loc);
3012 FullNamedExpression fne = expr.ResolveAsTypeStep (ec, false);
3017 return new TypeExpression (type, loc);
3021 public class TypeAliasExpression : TypeExpr {
3022 FullNamedExpression alias;
3026 public TypeAliasExpression (FullNamedExpression alias, TypeArguments args, Location l)
3032 eclass = ExprClass.Type;
3035 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
3037 texpr = alias.ResolveAsTypeTerminal (ec, false);
3041 Type type = texpr.Type;
3042 int num_args = TypeManager.GetNumberOfTypeArguments (type);
3045 if (num_args == 0) {
3046 Report.Error (308, loc,
3047 "The non-generic type `{0}' cannot " +
3048 "be used with type arguments.",
3049 TypeManager.CSharpName (type));
3053 ConstructedType ctype = new ConstructedType (type, args, loc);
3054 return ctype.ResolveAsTypeTerminal (ec, false);
3055 } else if (num_args > 0) {
3056 Report.Error (305, loc,
3057 "Using the generic type `{0}' " +
3058 "requires {1} type arguments",
3059 TypeManager.CSharpName (type), num_args.ToString ());
3066 public override bool CheckAccessLevel (DeclSpace ds)
3068 return texpr.CheckAccessLevel (ds);
3071 public override bool AsAccessible (DeclSpace ds)
3073 return texpr.AsAccessible (ds);
3076 public override bool IsClass {
3077 get { return texpr.IsClass; }
3080 public override bool IsValueType {
3081 get { return texpr.IsValueType; }
3084 public override bool IsInterface {
3085 get { return texpr.IsInterface; }
3088 public override bool IsSealed {
3089 get { return texpr.IsSealed; }
3094 /// This class denotes an expression which evaluates to a member
3095 /// of a struct or a class.
3097 public abstract class MemberExpr : Expression
3099 protected bool is_base;
3102 /// The name of this member.
3104 public abstract string Name {
3109 // When base.member is used
3111 public bool IsBase {
3112 get { return is_base; }
3113 set { is_base = value; }
3117 /// Whether this is an instance member.
3119 public abstract bool IsInstance {
3124 /// Whether this is a static member.
3126 public abstract bool IsStatic {
3131 /// The type which declares this member.
3133 public abstract Type DeclaringType {
3138 /// The instance expression associated with this member, if it's a
3139 /// non-static member.
3141 public Expression InstanceExpression;
3143 public static void error176 (Location loc, string name)
3145 Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
3146 "with an instance reference, qualify it with a type name instead", name);
3149 // TODO: possible optimalization
3150 // Cache resolved constant result in FieldBuilder <-> expression map
3151 public virtual MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3152 SimpleName original)
3156 // original == null || original.Resolve (...) ==> left
3159 if (left is TypeExpr) {
3160 left = left.ResolveAsTypeTerminal (ec, true);
3165 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3173 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3176 return ResolveExtensionMemberAccess (left);
3179 InstanceExpression = left;
3183 protected virtual MemberExpr ResolveExtensionMemberAccess (Expression left)
3185 error176 (loc, GetSignatureForError ());
3189 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3194 if (InstanceExpression == EmptyExpression.Null) {
3195 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3199 if (InstanceExpression.Type.IsValueType) {
3200 if (InstanceExpression is IMemoryLocation) {
3201 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
3203 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
3204 InstanceExpression.Emit (ec);
3206 t.AddressOf (ec, AddressOp.Store);
3209 InstanceExpression.Emit (ec);
3211 if (prepare_for_load)
3212 ec.ig.Emit (OpCodes.Dup);
3215 public virtual void SetTypeArguments (TypeArguments ta)
3217 // TODO: need to get correct member type
3218 Report.Error (307, loc, "The property `{0}' cannot be used with type arguments",
3219 GetSignatureForError ());
3224 /// Represents group of extension methods
3226 public class ExtensionMethodGroupExpr : MethodGroupExpr
3228 readonly NamespaceEntry namespace_entry;
3229 public Expression ExtensionExpression;
3230 Argument extension_argument;
3232 public ExtensionMethodGroupExpr (ArrayList list, NamespaceEntry n, Type extensionType, Location l)
3233 : base (list, extensionType, l)
3235 this.namespace_entry = n;
3238 public override bool IsStatic {
3239 get { return true; }
3242 public bool IsTopLevel {
3243 get { return namespace_entry == null; }
3246 public override void EmitArguments (EmitContext ec, ArrayList arguments)
3248 if (arguments == null)
3249 arguments = new ArrayList (1);
3250 arguments.Insert (0, extension_argument);
3251 base.EmitArguments (ec, arguments);
3254 public override void EmitCall (EmitContext ec, ArrayList arguments)
3256 if (arguments == null)
3257 arguments = new ArrayList (1);
3258 arguments.Insert (0, extension_argument);
3259 base.EmitCall (ec, arguments);
3262 public override MethodGroupExpr OverloadResolve (EmitContext ec, ref ArrayList arguments, bool may_fail, Location loc)
3264 if (arguments == null)
3265 arguments = new ArrayList (1);
3267 arguments.Insert (0, new Argument (ExtensionExpression));
3268 MethodGroupExpr mg = ResolveOverloadExtensions (ec, arguments, namespace_entry, loc);
3270 // Store resolved argument and restore original arguments
3272 ((ExtensionMethodGroupExpr)mg).extension_argument = (Argument)arguments [0];
3273 arguments.RemoveAt (0);
3278 MethodGroupExpr ResolveOverloadExtensions (EmitContext ec, ArrayList arguments, NamespaceEntry ns, Location loc)
3280 // Use normal resolve rules
3281 MethodGroupExpr mg = base.OverloadResolve (ec, ref arguments, ns != null, loc);
3289 ExtensionMethodGroupExpr e = ns.LookupExtensionMethod (type, null, Name, loc);
3291 return base.OverloadResolve (ec, ref arguments, false, loc);
3293 e.ExtensionExpression = ExtensionExpression;
3294 return e.ResolveOverloadExtensions (ec, arguments, e.namespace_entry, loc);
3299 /// MethodGroupExpr represents a group of method candidates which
3300 /// can be resolved to the best method overload
3302 public class MethodGroupExpr : MemberExpr
3304 public interface IErrorHandler
3306 bool NoExactMatch (EmitContext ec, MethodBase method);
3309 public IErrorHandler CustomErrorHandler;
3310 public MethodBase [] Methods;
3311 MethodBase best_candidate;
3312 // TODO: make private
3313 public TypeArguments type_arguments;
3314 bool identical_type_name;
3317 public MethodGroupExpr (MemberInfo [] mi, Type type, Location l)
3320 Methods = new MethodBase [mi.Length];
3321 mi.CopyTo (Methods, 0);
3324 public MethodGroupExpr (ArrayList list, Type type, Location l)
3328 Methods = (MethodBase[])list.ToArray (typeof (MethodBase));
3330 foreach (MemberInfo m in list){
3331 if (!(m is MethodBase)){
3332 Console.WriteLine ("Name " + m.Name);
3333 Console.WriteLine ("Found a: " + m.GetType ().FullName);
3342 protected MethodGroupExpr (Type type, Location loc)
3345 eclass = ExprClass.MethodGroup;
3349 public override Type DeclaringType {
3352 // We assume that the top-level type is in the end
3354 return Methods [Methods.Length - 1].DeclaringType;
3355 //return Methods [0].DeclaringType;
3359 public Type DelegateType {
3361 delegate_type = value;
3365 public bool IdenticalTypeName {
3367 return identical_type_name;
3371 identical_type_name = value;
3375 public override string GetSignatureForError ()
3377 if (best_candidate != null)
3378 return TypeManager.CSharpSignature (best_candidate);
3380 return TypeManager.CSharpSignature (Methods [0]);
3383 public override string Name {
3385 return Methods [0].Name;
3389 public override bool IsInstance {
3391 if (best_candidate != null)
3392 return !best_candidate.IsStatic;
3394 foreach (MethodBase mb in Methods)
3402 public override bool IsStatic {
3404 if (best_candidate != null)
3405 return best_candidate.IsStatic;
3407 foreach (MethodBase mb in Methods)
3415 public static explicit operator ConstructorInfo (MethodGroupExpr mg)
3417 return (ConstructorInfo)mg.best_candidate;
3420 public static explicit operator MethodInfo (MethodGroupExpr mg)
3422 return (MethodInfo)mg.best_candidate;
3426 // 7.4.3.3 Better conversion from expression
3427 // Returns : 1 if a->p is better,
3428 // 2 if a->q is better,
3429 // 0 if neither is better
3431 static int BetterExpressionConversion (EmitContext ec, Argument a, Type p, Type q)
3433 Type argument_type = TypeManager.TypeToCoreType (a.Type);
3434 if (argument_type == TypeManager.anonymous_method_type && RootContext.Version > LanguageVersion.ISO_2) {
3436 // Uwrap delegate from Expression<T>
3438 if (TypeManager.DropGenericTypeArguments (p) == TypeManager.expression_type) {
3439 p = TypeManager.GetTypeArguments (p) [0];
3440 q = TypeManager.GetTypeArguments (q) [0];
3442 p = Delegate.GetInvokeMethod (null, p).ReturnType;
3443 q = Delegate.GetInvokeMethod (null, q).ReturnType;
3445 if (argument_type == p)
3448 if (argument_type == q)
3452 return BetterTypeConversion (ec, p, q);
3456 // 7.4.3.4 Better conversion from type
3458 public static int BetterTypeConversion (EmitContext ec, Type p, Type q)
3460 if (p == null || q == null)
3461 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3463 if (p == TypeManager.int32_type) {
3464 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3466 } else if (p == TypeManager.int64_type) {
3467 if (q == TypeManager.uint64_type)
3469 } else if (p == TypeManager.sbyte_type) {
3470 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3471 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3473 } else if (p == TypeManager.short_type) {
3474 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3475 q == TypeManager.uint64_type)
3479 if (q == TypeManager.int32_type) {
3480 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3482 } if (q == TypeManager.int64_type) {
3483 if (p == TypeManager.uint64_type)
3485 } else if (q == TypeManager.sbyte_type) {
3486 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3487 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3489 } if (q == TypeManager.short_type) {
3490 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3491 p == TypeManager.uint64_type)
3495 // TODO: this is expensive
3496 Expression p_tmp = new EmptyExpression (p);
3497 Expression q_tmp = new EmptyExpression (q);
3499 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3500 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3502 if (p_to_q && !q_to_p)
3505 if (q_to_p && !p_to_q)
3512 /// Determines "Better function" between candidate
3513 /// and the current best match
3516 /// Returns a boolean indicating :
3517 /// false if candidate ain't better
3518 /// true if candidate is better than the current best match
3520 static bool BetterFunction (EmitContext ec, ArrayList args, int argument_count,
3521 MethodBase candidate, bool candidate_params,
3522 MethodBase best, bool best_params)
3524 ParameterData candidate_pd = TypeManager.GetParameterData (candidate);
3525 ParameterData best_pd = TypeManager.GetParameterData (best);
3527 bool better_at_least_one = false;
3529 for (int j = 0, c_idx = 0, b_idx = 0; j < argument_count; ++j, ++c_idx, ++b_idx)
3531 Argument a = (Argument) args [j];
3533 Type ct = TypeManager.TypeToCoreType (candidate_pd.ParameterType (c_idx));
3534 Type bt = TypeManager.TypeToCoreType (best_pd.ParameterType (b_idx));
3536 if (candidate_params && candidate_pd.ParameterModifier (c_idx) == Parameter.Modifier.PARAMS)
3538 ct = TypeManager.GetElementType (ct);
3542 if (best_params && best_pd.ParameterModifier (b_idx) == Parameter.Modifier.PARAMS)
3544 bt = TypeManager.GetElementType (bt);
3552 int result = BetterExpressionConversion (ec, a, ct, bt);
3554 // for each argument, the conversion to 'ct' should be no worse than
3555 // the conversion to 'bt'.
3559 // for at least one argument, the conversion to 'ct' should be better than
3560 // the conversion to 'bt'.
3562 better_at_least_one = true;
3565 if (better_at_least_one)
3569 // This handles the case
3571 // Add (float f1, float f2, float f3);
3572 // Add (params decimal [] foo);
3574 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3575 // first candidate would've chosen as better.
3581 // The two methods have equal parameter types. Now apply tie-breaking rules
3583 if (TypeManager.IsGenericMethod (best) && !TypeManager.IsGenericMethod (candidate))
3585 if (!TypeManager.IsGenericMethod (best) && TypeManager.IsGenericMethod (candidate))
3589 // This handles the following cases:
3591 // Trim () is better than Trim (params char[] chars)
3592 // Concat (string s1, string s2, string s3) is better than
3593 // Concat (string s1, params string [] srest)
3594 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3596 if (!candidate_params && best_params)
3598 if (candidate_params && !best_params)
3601 int candidate_param_count = candidate_pd.Count;
3602 int best_param_count = best_pd.Count;
3604 if (candidate_param_count != best_param_count)
3605 // can only happen if (candidate_params && best_params)
3606 return candidate_param_count > best_param_count;
3609 // now, both methods have the same number of parameters, and the parameters have the same types
3610 // Pick the "more specific" signature
3613 MethodBase orig_candidate = TypeManager.DropGenericMethodArguments (candidate);
3614 MethodBase orig_best = TypeManager.DropGenericMethodArguments (best);
3616 ParameterData orig_candidate_pd = TypeManager.GetParameterData (orig_candidate);
3617 ParameterData orig_best_pd = TypeManager.GetParameterData (orig_best);
3619 bool specific_at_least_once = false;
3620 for (int j = 0; j < candidate_param_count; ++j)
3622 Type ct = TypeManager.TypeToCoreType (orig_candidate_pd.ParameterType (j));
3623 Type bt = TypeManager.TypeToCoreType (orig_best_pd.ParameterType (j));
3626 Type specific = MoreSpecific (ct, bt);
3630 specific_at_least_once = true;
3633 if (specific_at_least_once)
3636 // FIXME: handle lifted operators
3642 protected override MemberExpr ResolveExtensionMemberAccess (Expression left)
3645 return base.ResolveExtensionMemberAccess (left);
3648 // When left side is an expression and at least one candidate method is
3649 // static, it can be extension method
3651 InstanceExpression = left;
3655 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3656 SimpleName original)
3658 if (!(left is TypeExpr) &&
3659 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3660 IdenticalTypeName = true;
3662 return base.ResolveMemberAccess (ec, left, loc, original);
3665 public override Expression CreateExpressionTree (EmitContext ec)
3667 Type t = best_candidate.IsConstructor ?
3668 typeof (ConstructorInfo) : typeof (MethodInfo);
3670 return new Cast (new TypeExpression (t, loc), new TypeOfMethod (best_candidate, loc));
3673 override public Expression DoResolve (EmitContext ec)
3675 if (InstanceExpression != null) {
3676 InstanceExpression = InstanceExpression.DoResolve (ec);
3677 if (InstanceExpression == null)
3684 public void ReportUsageError ()
3686 Report.Error (654, loc, "Method `" + DeclaringType + "." +
3687 Name + "()' is referenced without parentheses");
3690 override public void Emit (EmitContext ec)
3692 ReportUsageError ();
3695 public virtual void EmitArguments (EmitContext ec, ArrayList arguments)
3697 Invocation.EmitArguments (ec, arguments, false, null);
3700 public virtual void EmitCall (EmitContext ec, ArrayList arguments)
3702 Invocation.EmitCall (ec, IsBase, InstanceExpression, best_candidate, arguments, loc);
3705 protected virtual void Error_InvalidArguments (EmitContext ec, Location loc, int idx, MethodBase method,
3706 Argument a, ParameterData expected_par, Type paramType)
3708 if (a is CollectionElementInitializer.ElementInitializerArgument) {
3709 Report.SymbolRelatedToPreviousError (method);
3710 if ((expected_par.ParameterModifier (idx) & Parameter.Modifier.ISBYREF) != 0) {
3711 Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
3712 TypeManager.CSharpSignature (method));
3715 Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
3716 TypeManager.CSharpSignature (method));
3717 } else if (delegate_type == null) {
3718 Report.SymbolRelatedToPreviousError (method);
3719 Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
3720 TypeManager.CSharpSignature (method));
3722 Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
3723 TypeManager.CSharpName (delegate_type));
3725 Parameter.Modifier mod = expected_par.ParameterModifier (idx);
3727 string index = (idx + 1).ToString ();
3728 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
3729 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
3730 if ((mod & Parameter.Modifier.ISBYREF) == 0)
3731 Report.Error (1615, loc, "Argument `{0}' should not be passed with the `{1}' keyword",
3732 index, Parameter.GetModifierSignature (a.Modifier));
3734 Report.Error (1620, loc, "Argument `{0}' must be passed with the `{1}' keyword",
3735 index, Parameter.GetModifierSignature (mod));
3737 string p1 = a.GetSignatureForError ();
3738 string p2 = TypeManager.CSharpName (paramType);
3741 Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
3742 Report.SymbolRelatedToPreviousError (a.Expr.Type);
3743 Report.SymbolRelatedToPreviousError (paramType);
3745 Report.Error (1503, loc, "Argument {0}: Cannot convert type `{1}' to `{2}'", index, p1, p2);
3749 public override void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl)
3751 Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3752 Name, TypeManager.CSharpName (target));
3755 protected virtual int GetApplicableParametersCount (MethodBase method, ParameterData parameters)
3757 return parameters.Count;
3760 public static bool IsAncestralType (Type first_type, Type second_type)
3762 return first_type != second_type &&
3763 (TypeManager.IsSubclassOf (second_type, first_type) ||
3764 TypeManager.ImplementsInterface (second_type, first_type));
3768 /// Determines if the candidate method is applicable (section 14.4.2.1)
3769 /// to the given set of arguments
3770 /// A return value rates candidate method compatibility,
3771 /// 0 = the best, int.MaxValue = the worst
3773 public int IsApplicable (EmitContext ec,
3774 ArrayList arguments, int arg_count, ref MethodBase method, ref bool params_expanded_form)
3776 MethodBase candidate = method;
3778 ParameterData pd = TypeManager.GetParameterData (candidate);
3779 int param_count = GetApplicableParametersCount (candidate, pd);
3781 if (arg_count != param_count) {
3783 return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
3784 if (arg_count < param_count - 1)
3785 return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
3790 // 1. Handle generic method using type arguments when specified or type inference
3792 if (TypeManager.IsGenericMethod (candidate)) {
3793 if (type_arguments != null) {
3794 Type [] g_args = candidate.GetGenericArguments ();
3795 if (g_args.Length != type_arguments.Count)
3796 return int.MaxValue - 20000 + Math.Abs (type_arguments.Count - g_args.Length);
3798 // TODO: Don't create new method, create Parameters only
3799 method = ((MethodInfo) candidate).MakeGenericMethod (type_arguments.Arguments);
3801 pd = TypeManager.GetParameterData (candidate);
3803 int score = TypeManager.InferTypeArguments (ec, arguments, ref candidate);
3805 return score - 20000;
3807 if (TypeManager.IsGenericMethodDefinition (candidate))
3808 throw new InternalErrorException ("A generic method `{0}' definition took part in overload resolution",
3809 TypeManager.CSharpSignature (candidate));
3811 pd = TypeManager.GetParameterData (candidate);
3814 if (type_arguments != null)
3815 return int.MaxValue - 15000;
3820 // 2. Each argument has to be implicitly convertible to method parameter
3823 Parameter.Modifier p_mod = 0;
3825 for (int i = 0; i < arg_count; i++) {
3826 Argument a = (Argument) arguments [i];
3827 Parameter.Modifier a_mod = a.Modifier &
3828 ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3830 if (p_mod != Parameter.Modifier.PARAMS) {
3831 p_mod = pd.ParameterModifier (i) & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3833 if (p_mod == Parameter.Modifier.ARGLIST) {
3834 if (a.Type == TypeManager.runtime_argument_handle_type)
3840 pt = pd.ParameterType (i);
3842 params_expanded_form = true;
3846 if (!params_expanded_form)
3847 score = IsArgumentCompatible (ec, a_mod, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
3849 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0) {
3850 // It can be applicable in expanded form
3851 score = IsArgumentCompatible (ec, a_mod, a, 0, pt.GetElementType ());
3853 params_expanded_form = true;
3857 if (params_expanded_form)
3859 return (arg_count - i) * 2 + score;
3863 if (arg_count != param_count)
3864 params_expanded_form = true;
3869 int IsArgumentCompatible (EmitContext ec, Parameter.Modifier arg_mod, Argument argument, Parameter.Modifier param_mod, Type parameter)
3872 // Types have to be identical when ref or out modifer is used
3874 if (arg_mod != 0 || param_mod != 0) {
3875 if (TypeManager.HasElementType (parameter))
3876 parameter = parameter.GetElementType ();
3878 Type a_type = argument.Type;
3879 if (TypeManager.HasElementType (a_type))
3880 a_type = a_type.GetElementType ();
3882 if (a_type != parameter)
3888 // FIXME: Kill this abomination (EmitContext.TempEc)
3889 EmitContext prevec = EmitContext.TempEc;
3890 EmitContext.TempEc = ec;
3892 if (delegate_type != null ?
3893 !Delegate.IsTypeCovariant (argument.Expr, parameter) :
3894 !Convert.ImplicitConversionExists (ec, argument.Expr, parameter))
3897 if (arg_mod != param_mod)
3901 EmitContext.TempEc = prevec;
3907 public static bool IsOverride (MethodBase cand_method, MethodBase base_method)
3909 if (!IsAncestralType (base_method.DeclaringType, cand_method.DeclaringType))
3912 ParameterData cand_pd = TypeManager.GetParameterData (cand_method);
3913 ParameterData base_pd = TypeManager.GetParameterData (base_method);
3915 if (cand_pd.Count != base_pd.Count)
3918 for (int j = 0; j < cand_pd.Count; ++j)
3920 Parameter.Modifier cm = cand_pd.ParameterModifier (j);
3921 Parameter.Modifier bm = base_pd.ParameterModifier (j);
3922 Type ct = TypeManager.TypeToCoreType (cand_pd.ParameterType (j));
3923 Type bt = TypeManager.TypeToCoreType (base_pd.ParameterType (j));
3925 if (cm != bm || ct != bt)
3932 public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2, Location loc)
3934 MemberInfo [] miset;
3935 MethodGroupExpr union;
3940 return (MethodGroupExpr) mg2;
3943 return (MethodGroupExpr) mg1;
3946 MethodGroupExpr left_set = null, right_set = null;
3947 int length1 = 0, length2 = 0;
3949 left_set = (MethodGroupExpr) mg1;
3950 length1 = left_set.Methods.Length;
3952 right_set = (MethodGroupExpr) mg2;
3953 length2 = right_set.Methods.Length;
3955 ArrayList common = new ArrayList ();
3957 foreach (MethodBase r in right_set.Methods){
3958 if (TypeManager.ArrayContainsMethod (left_set.Methods, r))
3962 miset = new MemberInfo [length1 + length2 - common.Count];
3963 left_set.Methods.CopyTo (miset, 0);
3967 foreach (MethodBase r in right_set.Methods) {
3968 if (!common.Contains (r))
3972 union = new MethodGroupExpr (miset, mg1.Type, loc);
3977 static Type MoreSpecific (Type p, Type q)
3979 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
3981 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
3984 if (TypeManager.HasElementType (p))
3986 Type pe = TypeManager.GetElementType (p);
3987 Type qe = TypeManager.GetElementType (q);
3988 Type specific = MoreSpecific (pe, qe);
3994 else if (TypeManager.IsGenericType (p))
3996 Type[] pargs = TypeManager.GetTypeArguments (p);
3997 Type[] qargs = TypeManager.GetTypeArguments (q);
3999 bool p_specific_at_least_once = false;
4000 bool q_specific_at_least_once = false;
4002 for (int i = 0; i < pargs.Length; i++)
4004 Type specific = MoreSpecific (pargs [i], qargs [i]);
4005 if (specific == pargs [i])
4006 p_specific_at_least_once = true;
4007 if (specific == qargs [i])
4008 q_specific_at_least_once = true;
4011 if (p_specific_at_least_once && !q_specific_at_least_once)
4013 if (!p_specific_at_least_once && q_specific_at_least_once)
4021 /// Find the Applicable Function Members (7.4.2.1)
4023 /// me: Method Group expression with the members to select.
4024 /// it might contain constructors or methods (or anything
4025 /// that maps to a method).
4027 /// Arguments: ArrayList containing resolved Argument objects.
4029 /// loc: The location if we want an error to be reported, or a Null
4030 /// location for "probing" purposes.
4032 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4033 /// that is the best match of me on Arguments.
4036 public virtual MethodGroupExpr OverloadResolve (EmitContext ec, ref ArrayList Arguments,
4037 bool may_fail, Location loc)
4039 bool method_params = false;
4040 Type applicable_type = null;
4042 ArrayList candidates = new ArrayList (2);
4043 ArrayList candidate_overrides = null;
4046 // Used to keep a map between the candidate
4047 // and whether it is being considered in its
4048 // normal or expanded form
4050 // false is normal form, true is expanded form
4052 Hashtable candidate_to_form = null;
4054 if (Arguments != null)
4055 arg_count = Arguments.Count;
4057 if (RootContext.Version == LanguageVersion.ISO_1 && Name == "Invoke" && TypeManager.IsDelegateType (DeclaringType)) {
4059 Report.Error (1533, loc, "Invoke cannot be called directly on a delegate");
4063 int nmethods = Methods.Length;
4067 // Methods marked 'override' don't take part in 'applicable_type'
4068 // computation, nor in the actual overload resolution.
4069 // However, they still need to be emitted instead of a base virtual method.
4070 // So, we salt them away into the 'candidate_overrides' array.
4072 // In case of reflected methods, we replace each overriding method with
4073 // its corresponding base virtual method. This is to improve compatibility
4074 // with non-C# libraries which change the visibility of overrides (#75636)
4077 for (int i = 0; i < Methods.Length; ++i) {
4078 MethodBase m = Methods [i];
4079 if (TypeManager.IsOverride (m)) {
4080 if (candidate_overrides == null)
4081 candidate_overrides = new ArrayList ();
4082 candidate_overrides.Add (m);
4083 m = TypeManager.TryGetBaseDefinition (m);
4092 // Enable message recording, it's used mainly by lambda expressions
4094 Report.IMessageRecorder msg_recorder = new Report.MessageRecorder ();
4095 Report.IMessageRecorder prev_recorder = Report.SetMessageRecorder (msg_recorder);
4098 // First we construct the set of applicable methods
4100 bool is_sorted = true;
4101 int best_candidate_rate = int.MaxValue;
4102 for (int i = 0; i < nmethods; i++) {
4103 Type decl_type = Methods [i].DeclaringType;
4106 // If we have already found an applicable method
4107 // we eliminate all base types (Section 14.5.5.1)
4109 if (applicable_type != null && IsAncestralType (decl_type, applicable_type))
4113 // Check if candidate is applicable (section 14.4.2.1)
4115 bool params_expanded_form = false;
4116 int candidate_rate = IsApplicable (ec, Arguments, arg_count, ref Methods [i], ref params_expanded_form);
4118 if (candidate_rate < best_candidate_rate) {
4119 best_candidate_rate = candidate_rate;
4120 best_candidate = Methods [i];
4123 if (params_expanded_form) {
4124 if (candidate_to_form == null)
4125 candidate_to_form = new PtrHashtable ();
4126 MethodBase candidate = Methods [i];
4127 candidate_to_form [candidate] = candidate;
4130 if (candidate_rate != 0) {
4131 if (msg_recorder != null)
4132 msg_recorder.EndSession ();
4136 msg_recorder = null;
4137 candidates.Add (Methods [i]);
4139 if (applicable_type == null)
4140 applicable_type = decl_type;
4141 else if (applicable_type != decl_type) {
4143 if (IsAncestralType (applicable_type, decl_type))
4144 applicable_type = decl_type;
4148 Report.SetMessageRecorder (prev_recorder);
4149 if (msg_recorder != null && msg_recorder.PrintMessages ())
4152 int candidate_top = candidates.Count;
4154 if (applicable_type == null) {
4156 // When we found a top level method which does not match and it's
4157 // not an extension method. We start extension methods lookup from here
4159 if (InstanceExpression != null) {
4160 ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (type, Name, loc);
4161 if (ex_method_lookup != null) {
4162 ex_method_lookup.ExtensionExpression = InstanceExpression;
4163 ex_method_lookup.SetTypeArguments (type_arguments);
4164 return ex_method_lookup.OverloadResolve (ec, ref Arguments, may_fail, loc);
4172 // Okay so we have failed to find exact match so we
4173 // return error info about the closest match
4175 if (best_candidate != null) {
4176 if (CustomErrorHandler != null) {
4177 if (CustomErrorHandler.NoExactMatch (ec, best_candidate))
4181 ParameterData pd = TypeManager.GetParameterData (best_candidate);
4182 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4183 if (arg_count == pd.Count || pd.HasParams) {
4184 if (TypeManager.IsGenericMethodDefinition (best_candidate)) {
4185 if (type_arguments == null) {
4186 Report.Error (411, loc,
4187 "The type arguments for method `{0}' cannot be inferred from " +
4188 "the usage. Try specifying the type arguments explicitly",
4189 TypeManager.CSharpSignature (best_candidate));
4193 Type [] g_args = TypeManager.GetGenericArguments (best_candidate);
4194 if (type_arguments.Count != g_args.Length) {
4195 Report.SymbolRelatedToPreviousError (best_candidate);
4196 Report.Error (305, loc, "Using the generic method `{0}' requires `{1}' type argument(s)",
4197 TypeManager.CSharpSignature (best_candidate),
4198 g_args.Length.ToString ());
4202 if (type_arguments != null && !TypeManager.IsGenericMethod (best_candidate)) {
4203 Namespace.Error_TypeArgumentsCannotBeUsed (best_candidate, loc);
4208 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate, cand_params, may_fail, loc))
4213 if (almost_matched_members.Count != 0) {
4214 Error_MemberLookupFailed (ec.ContainerType, type, type, ".ctor",
4215 null, MemberTypes.Constructor, AllBindingFlags);
4220 // We failed to find any method with correct argument count
4222 if (Name == ConstructorInfo.ConstructorName) {
4223 Report.SymbolRelatedToPreviousError (type);
4224 Report.Error (1729, loc,
4225 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4226 TypeManager.CSharpName (type), arg_count);
4228 Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4229 Name, arg_count.ToString ());
4237 // At this point, applicable_type is _one_ of the most derived types
4238 // in the set of types containing the methods in this MethodGroup.
4239 // Filter the candidates so that they only contain methods from the
4240 // most derived types.
4243 int finalized = 0; // Number of finalized candidates
4246 // Invariant: applicable_type is a most derived type
4248 // We'll try to complete Section 14.5.5.1 for 'applicable_type' by
4249 // eliminating all it's base types. At the same time, we'll also move
4250 // every unrelated type to the end of the array, and pick the next
4251 // 'applicable_type'.
4253 Type next_applicable_type = null;
4254 int j = finalized; // where to put the next finalized candidate
4255 int k = finalized; // where to put the next undiscarded candidate
4256 for (int i = finalized; i < candidate_top; ++i) {
4257 MethodBase candidate = (MethodBase) candidates [i];
4258 Type decl_type = candidate.DeclaringType;
4260 if (decl_type == applicable_type) {
4261 candidates [k++] = candidates [j];
4262 candidates [j++] = candidates [i];
4266 if (IsAncestralType (decl_type, applicable_type))
4269 if (next_applicable_type != null &&
4270 IsAncestralType (decl_type, next_applicable_type))
4273 candidates [k++] = candidates [i];
4275 if (next_applicable_type == null ||
4276 IsAncestralType (next_applicable_type, decl_type))
4277 next_applicable_type = decl_type;
4280 applicable_type = next_applicable_type;
4283 } while (applicable_type != null);
4287 // Now we actually find the best method
4290 best_candidate = (MethodBase) candidates [0];
4291 if (delegate_type == null)
4292 method_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4294 for (int ix = 1; ix < candidate_top; ix++) {
4295 MethodBase candidate = (MethodBase) candidates [ix];
4297 if (candidate == best_candidate)
4300 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4302 if (BetterFunction (ec, Arguments, arg_count,
4303 candidate, cand_params,
4304 best_candidate, method_params)) {
4305 best_candidate = candidate;
4306 method_params = cand_params;
4310 // Now check that there are no ambiguities i.e the selected method
4311 // should be better than all the others
4313 MethodBase ambiguous = null;
4314 for (int ix = 1; ix < candidate_top; ix++) {
4315 MethodBase candidate = (MethodBase) candidates [ix];
4317 if (candidate == best_candidate)
4320 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4321 if (!BetterFunction (ec, Arguments, arg_count,
4322 best_candidate, method_params,
4323 candidate, cand_params))
4326 Report.SymbolRelatedToPreviousError (candidate);
4327 ambiguous = candidate;
4331 if (ambiguous != null) {
4332 Report.SymbolRelatedToPreviousError (best_candidate);
4333 Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4334 TypeManager.CSharpSignature (ambiguous), TypeManager.CSharpSignature (best_candidate));
4339 // If the method is a virtual function, pick an override closer to the LHS type.
4341 if (!IsBase && best_candidate.IsVirtual) {
4342 if (TypeManager.IsOverride (best_candidate))
4343 throw new InternalErrorException (
4344 "Should not happen. An 'override' method took part in overload resolution: " + best_candidate);
4346 if (candidate_overrides != null) {
4347 Type[] gen_args = null;
4348 bool gen_override = false;
4349 if (TypeManager.IsGenericMethod (best_candidate))
4350 gen_args = TypeManager.GetGenericArguments (best_candidate);
4352 foreach (MethodBase candidate in candidate_overrides) {
4353 if (TypeManager.IsGenericMethod (candidate)) {
4354 if (gen_args == null)
4357 if (gen_args.Length != TypeManager.GetGenericArguments (candidate).Length)
4360 if (gen_args != null)
4364 if (IsOverride (candidate, best_candidate)) {
4365 gen_override = true;
4366 best_candidate = candidate;
4370 if (gen_override && gen_args != null) {
4372 best_candidate = ((MethodInfo) best_candidate).MakeGenericMethod (gen_args);
4379 // And now check if the arguments are all
4380 // compatible, perform conversions if
4381 // necessary etc. and return if everything is
4384 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate,
4385 method_params, may_fail, loc))
4388 if (best_candidate == null)
4391 MethodBase the_method = TypeManager.DropGenericMethodArguments (best_candidate);
4393 if (the_method.IsGenericMethodDefinition &&
4394 !ConstraintChecker.CheckConstraints (ec, the_method, best_candidate, loc))
4398 IMethodData data = TypeManager.GetMethod (the_method);
4400 data.SetMemberIsUsed ();
4405 public override void SetTypeArguments (TypeArguments ta)
4407 type_arguments = ta;
4410 public bool VerifyArgumentsCompat (EmitContext ec, ref ArrayList arguments,
4411 int arg_count, MethodBase method,
4412 bool chose_params_expanded,
4413 bool may_fail, Location loc)
4415 ParameterData pd = TypeManager.GetParameterData (method);
4417 int errors = Report.Errors;
4418 Parameter.Modifier p_mod = 0;
4420 int a_idx = 0, a_pos = 0;
4422 ArrayList params_initializers = null;
4424 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4425 a = (Argument) arguments [a_idx];
4426 if (p_mod != Parameter.Modifier.PARAMS) {
4427 p_mod = pd.ParameterModifier (a_idx);
4428 pt = pd.ParameterType (a_idx);
4430 if (p_mod == Parameter.Modifier.ARGLIST) {
4431 if (a.Type != TypeManager.runtime_argument_handle_type)
4436 if (pt.IsPointer && !ec.InUnsafe) {
4443 if (p_mod == Parameter.Modifier.PARAMS) {
4444 if (chose_params_expanded) {
4445 params_initializers = new ArrayList (arg_count - a_idx);
4446 pt = TypeManager.GetElementType (pt);
4448 } else if (p_mod != 0) {
4449 pt = TypeManager.GetElementType (pt);
4454 // Types have to be identical when ref or out modifer is used
4456 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4457 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4460 if (!TypeManager.IsEqual (a.Expr.Type, pt))
4467 if (TypeManager.IsEqual (a.Type, pt)) {
4470 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4476 // Convert params arguments to an array initializer
4478 if (params_initializers != null) {
4479 params_initializers.Add (conv);
4480 arguments.RemoveAt (a_idx--);
4485 // Update the argument with the implicit conversion
4490 // Fill not provided arguments required by params modifier
4492 if (params_initializers == null && pd.HasParams && arg_count < pd.Count && a_idx + 1 == pd.Count) {
4493 if (arguments == null)
4494 arguments = new ArrayList (1);
4496 pt = pd.Types [GetApplicableParametersCount (method, pd) - 1];
4497 pt = TypeManager.GetElementType (pt);
4498 params_initializers = new ArrayList (0);
4501 if (a_idx == arg_count) {
4503 // Append an array argument with all params arguments
4505 if (params_initializers != null) {
4506 arguments.Add (new Argument (
4507 new ArrayCreation (new TypeExpression (pt, loc), "[]",
4508 params_initializers, loc).Resolve (ec)));
4513 if (!may_fail && Report.Errors == errors) {
4514 if (CustomErrorHandler != null)
4515 CustomErrorHandler.NoExactMatch (ec, best_candidate);
4517 Error_InvalidArguments (ec, loc, a_pos, method, a, pd, pt);
4523 public class ConstantExpr : MemberExpr
4527 public ConstantExpr (FieldInfo constant, Location loc)
4529 this.constant = constant;
4533 public override string Name {
4534 get { throw new NotImplementedException (); }
4537 public override bool IsInstance {
4538 get { return !IsStatic; }
4541 public override bool IsStatic {
4542 get { return constant.IsStatic; }
4545 public override Type DeclaringType {
4546 get { return constant.DeclaringType; }
4549 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc, SimpleName original)
4551 constant = TypeManager.GetGenericFieldDefinition (constant);
4553 IConstant ic = TypeManager.GetConstant (constant);
4555 if (constant.IsLiteral) {
4556 ic = new ExternalConstant (constant);
4558 ic = ExternalConstant.CreateDecimal (constant);
4559 // HACK: decimal field was not resolved as constant
4561 return new FieldExpr (constant, loc).ResolveMemberAccess (ec, left, loc, original);
4563 TypeManager.RegisterConstant (constant, ic);
4566 return base.ResolveMemberAccess (ec, left, loc, original);
4569 public override Expression CreateExpressionTree (EmitContext ec)
4571 throw new NotSupportedException ();
4574 public override Expression DoResolve (EmitContext ec)
4576 IConstant ic = TypeManager.GetConstant (constant);
4577 if (ic.ResolveValue ()) {
4578 if (!ec.IsInObsoleteScope)
4579 ic.CheckObsoleteness (loc);
4582 return ic.CreateConstantReference (loc);
4585 public override void Emit (EmitContext ec)
4587 throw new NotSupportedException ();
4590 public override string GetSignatureForError ()
4592 return TypeManager.GetFullNameSignature (constant);
4597 /// Fully resolved expression that evaluates to a Field
4599 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariable {
4600 public readonly FieldInfo FieldInfo;
4601 VariableInfo variable_info;
4603 LocalTemporary temp;
4605 bool in_initializer;
4607 public FieldExpr (FieldInfo fi, Location l, bool in_initializer):
4610 this.in_initializer = in_initializer;
4613 public FieldExpr (FieldInfo fi, Location l)
4616 eclass = ExprClass.Variable;
4617 type = TypeManager.TypeToCoreType (fi.FieldType);
4621 public override string Name {
4623 return FieldInfo.Name;
4627 public override bool IsInstance {
4629 return !FieldInfo.IsStatic;
4633 public override bool IsStatic {
4635 return FieldInfo.IsStatic;
4639 public override Type DeclaringType {
4641 return FieldInfo.DeclaringType;
4645 public override string GetSignatureForError ()
4647 return TypeManager.GetFullNameSignature (FieldInfo);
4650 public VariableInfo VariableInfo {
4652 return variable_info;
4656 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
4657 SimpleName original)
4659 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
4660 Type t = fi.FieldType;
4662 if (t.IsPointer && !ec.InUnsafe) {
4666 return base.ResolveMemberAccess (ec, left, loc, original);
4669 public override Expression CreateExpressionTree (EmitContext ec)
4671 Expression instance;
4672 if (InstanceExpression == null) {
4673 instance = new NullLiteral (loc);
4675 instance = InstanceExpression.CreateExpressionTree (ec);
4678 ArrayList args = new ArrayList (2);
4679 args.Add (new Argument (instance));
4680 args.Add (new Argument (CreateTypeOfExpression ()));
4681 return CreateExpressionFactoryCall ("Field", args);
4684 public Expression CreateTypeOfExpression ()
4686 return new TypeOfField (FieldInfo, loc);
4689 override public Expression DoResolve (EmitContext ec)
4691 return DoResolve (ec, false, false);
4694 Expression DoResolve (EmitContext ec, bool lvalue_instance, bool out_access)
4696 if (!FieldInfo.IsStatic){
4697 if (InstanceExpression == null){
4699 // This can happen when referencing an instance field using
4700 // a fully qualified type expression: TypeName.InstanceField = xxx
4702 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4706 // Resolve the field's instance expression while flow analysis is turned
4707 // off: when accessing a field "a.b", we must check whether the field
4708 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4710 if (lvalue_instance) {
4711 using (ec.With (EmitContext.Flags.DoFlowAnalysis, false)) {
4712 Expression right_side =
4713 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4714 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side, loc);
4717 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
4718 InstanceExpression = InstanceExpression.Resolve (ec, rf);
4721 if (InstanceExpression == null)
4724 using (ec.Set (EmitContext.Flags.OmitStructFlowAnalysis)) {
4725 InstanceExpression.CheckMarshalByRefAccess (ec);
4729 if (!in_initializer && !ec.IsInFieldInitializer) {
4730 ObsoleteAttribute oa;
4731 FieldBase f = TypeManager.GetField (FieldInfo);
4733 if (!ec.IsInObsoleteScope)
4734 f.CheckObsoleteness (loc);
4736 // To be sure that type is external because we do not register generated fields
4737 } else if (!(FieldInfo.DeclaringType is TypeBuilder)) {
4738 oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
4740 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
4744 AnonymousContainer am = ec.CurrentAnonymousMethod;
4746 if (!FieldInfo.IsStatic){
4747 if (!am.IsIterator && (ec.TypeContainer is Struct)){
4748 Report.Error (1673, loc,
4749 "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",
4756 IFixedBuffer fb = AttributeTester.GetFixedBuffer (FieldInfo);
4758 if (!ec.InFixedInitializer && ec.ContainerType.IsValueType) {
4759 Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4762 if (InstanceExpression.eclass != ExprClass.Variable) {
4763 Report.SymbolRelatedToPreviousError (FieldInfo);
4764 Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4765 TypeManager.GetFullNameSignature (FieldInfo));
4768 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4771 // If the instance expression is a local variable or parameter.
4772 IVariable var = InstanceExpression as IVariable;
4773 if ((var == null) || (var.VariableInfo == null))
4776 VariableInfo vi = var.VariableInfo;
4777 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
4780 variable_info = vi.GetSubStruct (FieldInfo.Name);
4784 static readonly int [] codes = {
4785 191, // instance, write access
4786 192, // instance, out access
4787 198, // static, write access
4788 199, // static, out access
4789 1648, // member of value instance, write access
4790 1649, // member of value instance, out access
4791 1650, // member of value static, write access
4792 1651 // member of value static, out access
4795 static readonly string [] msgs = {
4796 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4797 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4798 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4799 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4800 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4801 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4802 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4803 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4806 // The return value is always null. Returning a value simplifies calling code.
4807 Expression Report_AssignToReadonly (Expression right_side)
4810 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4814 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4816 Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4821 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4823 IVariable var = InstanceExpression as IVariable;
4824 if ((var != null) && (var.VariableInfo != null))
4825 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
4827 bool lvalue_instance = !FieldInfo.IsStatic && FieldInfo.DeclaringType.IsValueType;
4828 bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
4830 Expression e = DoResolve (ec, lvalue_instance, out_access);
4835 FieldBase fb = TypeManager.GetField (FieldInfo);
4839 if (FieldInfo.IsInitOnly) {
4840 // InitOnly fields can only be assigned in constructors or initializers
4841 if (!ec.IsInFieldInitializer && !ec.IsConstructor)
4842 return Report_AssignToReadonly (right_side);
4844 if (ec.IsConstructor) {
4845 Type ctype = ec.TypeContainer.CurrentType;
4847 ctype = ec.ContainerType;
4849 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4850 if (!TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
4851 return Report_AssignToReadonly (right_side);
4852 // static InitOnly fields cannot be assigned-to in an instance constructor
4853 if (IsStatic && !ec.IsStatic)
4854 return Report_AssignToReadonly (right_side);
4855 // instance constructors can't modify InitOnly fields of other instances of the same type
4856 if (!IsStatic && !(InstanceExpression is This))
4857 return Report_AssignToReadonly (right_side);
4861 if (right_side == EmptyExpression.OutAccess &&
4862 !IsStatic && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type)) {
4863 Report.SymbolRelatedToPreviousError (DeclaringType);
4864 Report.Warning (197, 1, loc,
4865 "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",
4866 GetSignatureForError ());
4872 bool is_marshal_by_ref ()
4874 return !IsStatic && Type.IsValueType && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type);
4877 public override void CheckMarshalByRefAccess (EmitContext ec)
4879 if (is_marshal_by_ref () && !(InstanceExpression is This)) {
4880 Report.SymbolRelatedToPreviousError (DeclaringType);
4881 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",
4882 GetSignatureForError ());
4886 public bool VerifyFixed ()
4888 IVariable variable = InstanceExpression as IVariable;
4889 // A variable of the form V.I is fixed when V is a fixed variable of a struct type.
4890 // We defer the InstanceExpression check after the variable check to avoid a
4891 // separate null check on InstanceExpression.
4892 return variable != null && InstanceExpression.Type.IsValueType && variable.VerifyFixed ();
4895 public override int GetHashCode ()
4897 return FieldInfo.GetHashCode ();
4900 public override bool Equals (object obj)
4902 FieldExpr fe = obj as FieldExpr;
4906 if (FieldInfo != fe.FieldInfo)
4909 if (InstanceExpression == null || fe.InstanceExpression == null)
4912 return InstanceExpression.Equals (fe.InstanceExpression);
4915 public void Emit (EmitContext ec, bool leave_copy)
4917 ILGenerator ig = ec.ig;
4918 bool is_volatile = false;
4920 FieldBase f = TypeManager.GetField (FieldInfo);
4922 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4925 f.SetMemberIsUsed ();
4928 if (FieldInfo.IsStatic){
4930 ig.Emit (OpCodes.Volatile);
4932 ig.Emit (OpCodes.Ldsfld, FieldInfo);
4935 EmitInstance (ec, false);
4937 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
4939 ig.Emit (OpCodes.Ldflda, FieldInfo);
4940 ig.Emit (OpCodes.Ldflda, ff.Element);
4943 ig.Emit (OpCodes.Volatile);
4945 ig.Emit (OpCodes.Ldfld, FieldInfo);
4950 ec.ig.Emit (OpCodes.Dup);
4951 if (!FieldInfo.IsStatic) {
4952 temp = new LocalTemporary (this.Type);
4958 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4960 FieldAttributes fa = FieldInfo.Attributes;
4961 bool is_static = (fa & FieldAttributes.Static) != 0;
4962 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
4963 ILGenerator ig = ec.ig;
4965 if (is_readonly && !ec.IsConstructor){
4966 Report_AssignToReadonly (source);
4971 // String concatenation creates a new string instance
4973 prepared = prepare_for_load && !(source is StringConcat);
4974 EmitInstance (ec, prepared);
4978 ec.ig.Emit (OpCodes.Dup);
4979 if (!FieldInfo.IsStatic) {
4980 temp = new LocalTemporary (this.Type);
4985 FieldBase f = TypeManager.GetField (FieldInfo);
4987 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4988 ig.Emit (OpCodes.Volatile);
4994 ig.Emit (OpCodes.Stsfld, FieldInfo);
4996 ig.Emit (OpCodes.Stfld, FieldInfo);
5004 public override void Emit (EmitContext ec)
5009 public override void EmitSideEffect (EmitContext ec)
5011 FieldBase f = TypeManager.GetField (FieldInfo);
5012 bool is_volatile = f != null && (f.ModFlags & Modifiers.VOLATILE) != 0;
5014 if (is_volatile || is_marshal_by_ref ())
5015 base.EmitSideEffect (ec);
5018 public void AddressOf (EmitContext ec, AddressOp mode)
5020 ILGenerator ig = ec.ig;
5022 FieldBase f = TypeManager.GetField (FieldInfo);
5024 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
5025 Report.Warning (420, 1, loc, "`{0}': A volatile field references will not be treated as volatile",
5026 f.GetSignatureForError ());
5029 if ((mode & AddressOp.Store) != 0)
5031 if ((mode & AddressOp.Load) != 0)
5032 f.SetMemberIsUsed ();
5036 // Handle initonly fields specially: make a copy and then
5037 // get the address of the copy.
5040 if (FieldInfo.IsInitOnly){
5042 if (ec.IsConstructor){
5043 if (FieldInfo.IsStatic){
5055 local = ig.DeclareLocal (type);
5056 ig.Emit (OpCodes.Stloc, local);
5057 ig.Emit (OpCodes.Ldloca, local);
5062 if (FieldInfo.IsStatic){
5063 ig.Emit (OpCodes.Ldsflda, FieldInfo);
5066 EmitInstance (ec, false);
5067 ig.Emit (OpCodes.Ldflda, FieldInfo);
5074 /// Expression that evaluates to a Property. The Assign class
5075 /// might set the `Value' expression if we are in an assignment.
5077 /// This is not an LValue because we need to re-write the expression, we
5078 /// can not take data from the stack and store it.
5080 public class PropertyExpr : MemberExpr, IAssignMethod {
5081 public readonly PropertyInfo PropertyInfo;
5082 MethodInfo getter, setter;
5087 LocalTemporary temp;
5090 public PropertyExpr (Type container_type, PropertyInfo pi, Location l)
5093 eclass = ExprClass.PropertyAccess;
5097 type = TypeManager.TypeToCoreType (pi.PropertyType);
5099 ResolveAccessors (container_type);
5102 public override string Name {
5104 return PropertyInfo.Name;
5108 public override bool IsInstance {
5114 public override bool IsStatic {
5120 public override Expression CreateExpressionTree (EmitContext ec)
5122 if (IsSingleDimensionalArrayLength ()) {
5123 ArrayList args = new ArrayList (1);
5124 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5125 return CreateExpressionFactoryCall ("ArrayLength", args);
5128 // TODO: it's waiting for PropertyExpr refactoring
5129 //ArrayList args = new ArrayList (2);
5130 //args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5131 //args.Add (getter expression);
5132 //return CreateExpressionFactoryCall ("Property", args);
5133 return base.CreateExpressionTree (ec);
5136 public Expression CreateSetterTypeOfExpression ()
5138 return new Cast (new TypeExpression (typeof (MethodInfo), loc), new TypeOfMethod (setter, loc));
5141 public override Type DeclaringType {
5143 return PropertyInfo.DeclaringType;
5147 public override string GetSignatureForError ()
5149 return TypeManager.GetFullNameSignature (PropertyInfo);
5152 void FindAccessors (Type invocation_type)
5154 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
5155 BindingFlags.Static | BindingFlags.Instance |
5156 BindingFlags.DeclaredOnly;
5158 Type current = PropertyInfo.DeclaringType;
5159 for (; current != null; current = current.BaseType) {
5160 MemberInfo[] group = TypeManager.MemberLookup (
5161 invocation_type, invocation_type, current,
5162 MemberTypes.Property, flags, PropertyInfo.Name, null);
5167 if (group.Length != 1)
5168 // Oooops, can this ever happen ?
5171 PropertyInfo pi = (PropertyInfo) group [0];
5174 getter = pi.GetGetMethod (true);
5177 setter = pi.GetSetMethod (true);
5179 MethodInfo accessor = getter != null ? getter : setter;
5181 if (!accessor.IsVirtual)
5187 // We also perform the permission checking here, as the PropertyInfo does not
5188 // hold the information for the accessibility of its setter/getter
5190 // TODO: Refactor to use some kind of cache together with GetPropertyFromAccessor
5191 void ResolveAccessors (Type container_type)
5193 FindAccessors (container_type);
5195 if (getter != null) {
5196 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
5197 IMethodData md = TypeManager.GetMethod (the_getter);
5199 md.SetMemberIsUsed ();
5201 is_static = getter.IsStatic;
5204 if (setter != null) {
5205 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
5206 IMethodData md = TypeManager.GetMethod (the_setter);
5208 md.SetMemberIsUsed ();
5210 is_static = setter.IsStatic;
5214 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
5217 InstanceExpression = null;
5221 if (InstanceExpression == null) {
5222 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5226 InstanceExpression = InstanceExpression.DoResolve (ec);
5227 if (lvalue_instance && InstanceExpression != null)
5228 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
5230 if (InstanceExpression == null)
5233 InstanceExpression.CheckMarshalByRefAccess (ec);
5235 if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) &&
5236 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
5237 !TypeManager.IsNestedChildOf (ec.ContainerType, InstanceExpression.Type) &&
5238 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.ContainerType)) {
5239 Report.SymbolRelatedToPreviousError (PropertyInfo);
5240 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
5247 void Error_PropertyNotFound (MethodInfo mi, bool getter)
5249 // TODO: correctly we should compare arguments but it will lead to bigger changes
5250 if (mi is MethodBuilder) {
5251 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
5255 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
5257 ParameterData iparams = TypeManager.GetParameterData (mi);
5258 sig.Append (getter ? "get_" : "set_");
5260 sig.Append (iparams.GetSignatureForError ());
5262 Report.SymbolRelatedToPreviousError (mi);
5263 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
5264 Name, sig.ToString ());
5267 public bool IsAccessibleFrom (Type invocation_type, bool lvalue)
5270 MethodInfo accessor = lvalue ? setter : getter;
5271 if (accessor == null && lvalue)
5273 return accessor != null && IsAccessorAccessible (invocation_type, accessor, out dummy);
5276 bool IsSingleDimensionalArrayLength ()
5278 if (DeclaringType != TypeManager.array_type || getter == null || Name != "Length")
5281 string t_name = InstanceExpression.Type.Name;
5282 int t_name_len = t_name.Length;
5283 return t_name_len > 2 && t_name [t_name_len - 2] == '[' && t_name [t_name_len - 3] != ']';
5286 override public Expression DoResolve (EmitContext ec)
5291 if (getter != null){
5292 if (TypeManager.GetParameterData (getter).Count != 0){
5293 Error_PropertyNotFound (getter, true);
5298 if (getter == null){
5300 // The following condition happens if the PropertyExpr was
5301 // created, but is invalid (ie, the property is inaccessible),
5302 // and we did not want to embed the knowledge about this in
5303 // the caller routine. This only avoids double error reporting.
5308 if (InstanceExpression != EmptyExpression.Null) {
5309 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5310 TypeManager.GetFullNameSignature (PropertyInfo));
5315 bool must_do_cs1540_check = false;
5316 if (getter != null &&
5317 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
5318 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
5319 if (pm != null && pm.HasCustomAccessModifier) {
5320 Report.SymbolRelatedToPreviousError (pm);
5321 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5322 TypeManager.CSharpSignature (getter));
5325 Report.SymbolRelatedToPreviousError (getter);
5326 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
5331 if (!InstanceResolve (ec, false, must_do_cs1540_check))
5335 // Only base will allow this invocation to happen.
5337 if (IsBase && getter.IsAbstract) {
5338 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5342 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
5352 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
5354 if (right_side == EmptyExpression.OutAccess) {
5355 if (ec.CurrentBlock.Toplevel.GetTransparentIdentifier (PropertyInfo.Name) != null) {
5356 Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5359 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as `ref' or `out' parameter",
5360 GetSignatureForError ());
5365 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5366 Error_CannotModifyIntermediateExpressionValue (ec);
5369 if (setter == null){
5371 // The following condition happens if the PropertyExpr was
5372 // created, but is invalid (ie, the property is inaccessible),
5373 // and we did not want to embed the knowledge about this in
5374 // the caller routine. This only avoids double error reporting.
5378 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
5379 GetSignatureForError ());
5383 if (TypeManager.GetParameterData (setter).Count != 1){
5384 Error_PropertyNotFound (setter, false);
5388 bool must_do_cs1540_check;
5389 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
5390 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
5391 if (pm != null && pm.HasCustomAccessModifier) {
5392 Report.SymbolRelatedToPreviousError (pm);
5393 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5394 TypeManager.CSharpSignature (setter));
5397 Report.SymbolRelatedToPreviousError (setter);
5398 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
5403 if (!InstanceResolve (ec, PropertyInfo.DeclaringType.IsValueType, must_do_cs1540_check))
5407 // Only base will allow this invocation to happen.
5409 if (IsBase && setter.IsAbstract){
5410 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5417 public override void Emit (EmitContext ec)
5422 public void Emit (EmitContext ec, bool leave_copy)
5425 // Special case: length of single dimension array property is turned into ldlen
5427 if (IsSingleDimensionalArrayLength ()) {
5429 EmitInstance (ec, false);
5430 ec.ig.Emit (OpCodes.Ldlen);
5431 ec.ig.Emit (OpCodes.Conv_I4);
5435 Invocation.EmitCall (ec, IsBase, InstanceExpression, getter, null, loc, prepared, false);
5438 ec.ig.Emit (OpCodes.Dup);
5440 temp = new LocalTemporary (this.Type);
5447 // Implements the IAssignMethod interface for assignments
5449 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5451 Expression my_source = source;
5453 if (prepare_for_load) {
5454 if (source is StringConcat)
5455 EmitInstance (ec, false);
5463 ec.ig.Emit (OpCodes.Dup);
5465 temp = new LocalTemporary (this.Type);
5469 } else if (leave_copy) {
5471 temp = new LocalTemporary (this.Type);
5476 ArrayList args = new ArrayList (1);
5477 args.Add (new Argument (my_source, Argument.AType.Expression));
5479 Invocation.EmitCall (ec, IsBase, InstanceExpression, setter, args, loc, false, prepared);
5489 /// Fully resolved expression that evaluates to an Event
5491 public class EventExpr : MemberExpr {
5492 public readonly EventInfo EventInfo;
5495 MethodInfo add_accessor, remove_accessor;
5497 public EventExpr (EventInfo ei, Location loc)
5501 eclass = ExprClass.EventAccess;
5503 add_accessor = TypeManager.GetAddMethod (ei);
5504 remove_accessor = TypeManager.GetRemoveMethod (ei);
5505 if (add_accessor.IsStatic || remove_accessor.IsStatic)
5508 if (EventInfo is MyEventBuilder){
5509 MyEventBuilder eb = (MyEventBuilder) EventInfo;
5510 type = eb.EventType;
5513 type = EventInfo.EventHandlerType;
5516 public override string Name {
5518 return EventInfo.Name;
5522 public override bool IsInstance {
5528 public override bool IsStatic {
5534 public override Type DeclaringType {
5536 return EventInfo.DeclaringType;
5540 void Error_AssignmentEventOnly ()
5542 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5543 GetSignatureForError ());
5546 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
5547 SimpleName original)
5550 // If the event is local to this class, we transform ourselves into a FieldExpr
5553 if (EventInfo.DeclaringType == ec.ContainerType ||
5554 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
5555 EventField mi = TypeManager.GetEventField (EventInfo);
5558 if (!ec.IsInObsoleteScope)
5559 mi.CheckObsoleteness (loc);
5561 if ((mi.ModFlags & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0 && !ec.IsInCompoundAssignment)
5562 Error_AssignmentEventOnly ();
5564 FieldExpr ml = new FieldExpr (mi.FieldBuilder, loc);
5566 InstanceExpression = null;
5568 return ml.ResolveMemberAccess (ec, left, loc, original);
5572 if (left is This && !ec.IsInCompoundAssignment)
5573 Error_AssignmentEventOnly ();
5575 return base.ResolveMemberAccess (ec, left, loc, original);
5579 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
5582 InstanceExpression = null;
5586 if (InstanceExpression == null) {
5587 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5591 InstanceExpression = InstanceExpression.DoResolve (ec);
5592 if (InstanceExpression == null)
5595 if (IsBase && add_accessor.IsAbstract) {
5596 Error_CannotCallAbstractBase(TypeManager.CSharpSignature(add_accessor));
5601 // This is using the same mechanism as the CS1540 check in PropertyExpr.
5602 // However, in the Event case, we reported a CS0122 instead.
5604 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
5605 InstanceExpression.Type != ec.ContainerType &&
5606 TypeManager.IsSubclassOf (ec.ContainerType, InstanceExpression.Type)) {
5607 Report.SymbolRelatedToPreviousError (EventInfo);
5608 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5615 public bool IsAccessibleFrom (Type invocation_type)
5618 return IsAccessorAccessible (invocation_type, add_accessor, out dummy) &&
5619 IsAccessorAccessible (invocation_type, remove_accessor, out dummy);
5622 public override Expression CreateExpressionTree (EmitContext ec)
5624 throw new NotSupportedException ();
5627 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5629 return DoResolve (ec);
5632 public override Expression DoResolve (EmitContext ec)
5634 bool must_do_cs1540_check;
5635 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
5636 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
5637 Report.SymbolRelatedToPreviousError (EventInfo);
5638 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5642 if (!InstanceResolve (ec, must_do_cs1540_check))
5648 public override void Emit (EmitContext ec)
5650 Report.Error (70, loc, "The event `{0}' can only appear on the left hand side of += or -= "+
5651 "(except on the defining type)", GetSignatureForError ());
5654 public override string GetSignatureForError ()
5656 return TypeManager.CSharpSignature (EventInfo);
5659 public void EmitAddOrRemove (EmitContext ec, Expression source)
5661 BinaryDelegate source_del = source as BinaryDelegate;
5662 if (source_del == null) {
5666 Expression handler = source_del.Right;
5668 Argument arg = new Argument (handler, Argument.AType.Expression);
5669 ArrayList args = new ArrayList ();
5673 if (source_del.IsAddition)
5674 Invocation.EmitCall (
5675 ec, IsBase, InstanceExpression, add_accessor, args, loc);
5677 Invocation.EmitCall (
5678 ec, IsBase, InstanceExpression, remove_accessor, args, loc);
5682 public class TemporaryVariable : Expression, IMemoryLocation
5687 public TemporaryVariable (Type type, Location loc)
5691 eclass = ExprClass.Value;
5694 public override Expression DoResolve (EmitContext ec)
5699 TypeExpr te = new TypeExpression (type, loc);
5700 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
5701 if (!li.Resolve (ec))
5704 if (ec.MustCaptureVariable (li)) {
5705 ScopeInfo scope = li.Block.CreateScopeInfo ();
5706 var = scope.AddLocal (li);
5713 public Variable Variable {
5714 get { return var != null ? var : li.Variable; }
5717 public override void Emit (EmitContext ec)
5719 Variable.EmitInstance (ec);
5723 public void EmitLoadAddress (EmitContext ec)
5725 Variable.EmitInstance (ec);
5726 Variable.EmitAddressOf (ec);
5729 public void Store (EmitContext ec, Expression right_side)
5731 Variable.EmitInstance (ec);
5732 right_side.Emit (ec);
5733 Variable.EmitAssign (ec);
5736 public void EmitThis (EmitContext ec)
5738 Variable.EmitInstance (ec);
5741 public void EmitStore (EmitContext ec)
5743 Variable.EmitAssign (ec);
5746 public void AddressOf (EmitContext ec, AddressOp mode)
5748 EmitLoadAddress (ec);
5753 /// Handles `var' contextual keyword; var becomes a keyword only
5754 /// if no type called var exists in a variable scope
5756 public class VarExpr : SimpleName
5758 // Used for error reporting only
5759 ArrayList initializer;
5761 public VarExpr (Location loc)
5766 public ArrayList VariableInitializer {
5768 this.initializer = value;
5772 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5775 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
5777 type = right_side.Type;
5778 if (type == TypeManager.null_type || type == TypeManager.void_type || type == TypeManager.anonymous_method_type) {
5779 Report.Error (815, loc, "An implicitly typed local variable declaration cannot be initialized with `{0}'",
5780 right_side.GetSignatureForError ());
5784 eclass = ExprClass.Variable;
5788 protected override void Error_TypeOrNamespaceNotFound (IResolveContext ec)
5790 Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");
5793 public override TypeExpr ResolveAsContextualType (IResolveContext rc, bool silent)
5795 TypeExpr te = base.ResolveAsContextualType (rc, true);
5799 if (initializer == null)
5802 if (initializer.Count > 1) {
5803 Location loc = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [1]).Location;
5804 Report.Error (819, loc, "An implicitly typed local variable declaration cannot include multiple declarators");
5809 Expression variable_initializer = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [0]).expression_or_array_initializer;
5810 if (variable_initializer == null) {
5811 Report.Error (818, loc, "An implicitly typed local variable declarator must include an initializer");