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 bool HasTypeArguments {
2273 return targs != null;
2277 public override string GetSignatureForError ()
2279 if (targs != null) {
2280 return TypeManager.RemoveGenericArity (Name) + "<" +
2281 targs.GetSignatureForError () + ">";
2289 /// SimpleName expressions are formed of a single word and only happen at the beginning
2290 /// of a dotted-name.
2292 public class SimpleName : ATypeNameExpression {
2295 public SimpleName (string name, Location l)
2300 public SimpleName (string name, TypeArguments args, Location l)
2301 : base (name, args, l)
2305 public SimpleName (string name, TypeParameter[] type_params, Location l)
2308 targs = new TypeArguments (l);
2309 foreach (TypeParameter type_param in type_params)
2310 targs.Add (new TypeParameterExpr (type_param, l));
2313 public static string RemoveGenericArity (string name)
2316 StringBuilder sb = null;
2318 int pos = name.IndexOf ('`', start);
2323 sb.Append (name.Substring (start));
2328 sb = new StringBuilder ();
2329 sb.Append (name.Substring (start, pos-start));
2332 while ((pos < name.Length) && Char.IsNumber (name [pos]))
2336 } while (start < name.Length);
2338 return sb.ToString ();
2341 public SimpleName GetMethodGroup ()
2343 return new SimpleName (RemoveGenericArity (Name), targs, loc);
2346 public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
2348 if (ec.IsInFieldInitializer)
2349 Report.Error (236, l,
2350 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2354 120, l, "`{0}': An object reference is required for the nonstatic field, method or property",
2358 public bool IdenticalNameAndTypeName (EmitContext ec, Expression resolved_to, Location loc)
2360 return resolved_to != null && resolved_to.Type != null &&
2361 resolved_to.Type.Name == Name &&
2362 (ec.DeclContainer.LookupNamespaceOrType (Name, loc, /* ignore_cs0104 = */ true) != null);
2365 public override Expression DoResolve (EmitContext ec)
2367 return SimpleNameResolve (ec, null, false);
2370 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
2372 return SimpleNameResolve (ec, right_side, false);
2376 public Expression DoResolve (EmitContext ec, bool intermediate)
2378 return SimpleNameResolve (ec, null, intermediate);
2381 static bool IsNestedChild (Type t, Type parent)
2383 while (parent != null) {
2384 if (TypeManager.IsNestedChildOf (t, TypeManager.DropGenericTypeArguments (parent)))
2387 parent = parent.BaseType;
2393 FullNamedExpression ResolveNested (IResolveContext ec, Type t)
2395 if (!TypeManager.IsGenericTypeDefinition (t) && !TypeManager.IsGenericType (t))
2398 DeclSpace ds = ec.DeclContainer;
2399 while (ds != null && !IsNestedChild (t, ds.TypeBuilder))
2405 Type[] gen_params = TypeManager.GetTypeArguments (t);
2407 int arg_count = targs != null ? targs.Count : 0;
2409 for (; (ds != null) && ds.IsGeneric; ds = ds.Parent) {
2410 if (arg_count + ds.CountTypeParameters == gen_params.Length) {
2411 TypeArguments new_args = new TypeArguments (loc);
2412 foreach (TypeParameter param in ds.TypeParameters)
2413 new_args.Add (new TypeParameterExpr (param, loc));
2416 new_args.Add (targs);
2418 return new ConstructedType (t, new_args, loc);
2425 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2427 FullNamedExpression fne = ec.GenericDeclContainer.LookupGeneric (Name, loc);
2429 return fne.ResolveAsTypeStep (ec, silent);
2431 int errors = Report.Errors;
2432 fne = ec.DeclContainer.LookupNamespaceOrType (Name, loc, /*ignore_cs0104=*/ false);
2435 if (fne.Type == null)
2438 FullNamedExpression nested = ResolveNested (ec, fne.Type);
2440 return nested.ResolveAsTypeStep (ec, false);
2442 if (targs != null) {
2443 ConstructedType ct = new ConstructedType (fne, targs, loc);
2444 return ct.ResolveAsTypeStep (ec, false);
2450 if (silent || errors != Report.Errors)
2453 Error_TypeOrNamespaceNotFound (ec);
2457 protected virtual void Error_TypeOrNamespaceNotFound (IResolveContext ec)
2459 MemberCore mc = ec.DeclContainer.GetDefinition (Name);
2461 Error_UnexpectedKind (ec.DeclContainer, "type", GetMemberType (mc), loc);
2465 string ns = ec.DeclContainer.NamespaceEntry.NS.Name;
2466 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2467 foreach (Assembly a in RootNamespace.Global.Assemblies) {
2468 Type type = a.GetType (fullname);
2470 Report.SymbolRelatedToPreviousError (type);
2471 Expression.ErrorIsInaccesible (loc, TypeManager.CSharpName (type));
2476 Type t = ec.DeclContainer.LookupAnyGeneric (Name);
2478 Namespace.Error_InvalidNumberOfTypeArguments (t, loc);
2482 if (targs != null) {
2483 FullNamedExpression retval = ec.DeclContainer.LookupNamespaceOrType (SimpleName.RemoveGenericArity (Name), loc, true);
2484 if (retval != null) {
2485 Namespace.Error_TypeArgumentsCannotBeUsed (retval.Type, loc);
2490 NamespaceEntry.Error_NamespaceNotFound (loc, Name);
2493 // TODO: I am still not convinced about this. If someone else will need it
2494 // implement this as virtual property in MemberCore hierarchy
2495 public static string GetMemberType (MemberCore mc)
2501 if (mc is FieldBase)
2503 if (mc is MethodCore)
2505 if (mc is EnumMember)
2513 Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2519 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2525 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2532 /// 7.5.2: Simple Names.
2534 /// Local Variables and Parameters are handled at
2535 /// parse time, so they never occur as SimpleNames.
2537 /// The `intermediate' flag is used by MemberAccess only
2538 /// and it is used to inform us that it is ok for us to
2539 /// avoid the static check, because MemberAccess might end
2540 /// up resolving the Name as a Type name and the access as
2541 /// a static type access.
2543 /// ie: Type Type; .... { Type.GetType (""); }
2545 /// Type is both an instance variable and a Type; Type.GetType
2546 /// is the static method not an instance method of type.
2548 Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2550 Expression e = null;
2553 // Stage 1: Performed by the parser (binding to locals or parameters).
2555 Block current_block = ec.CurrentBlock;
2556 if (current_block != null){
2557 LocalInfo vi = current_block.GetLocalInfo (Name);
2559 if (targs != null) {
2560 Report.Error (307, loc,
2561 "The variable `{0}' cannot be used with type arguments",
2566 LocalVariableReference var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2567 if (right_side != null) {
2568 return var.ResolveLValue (ec, right_side, loc);
2570 ResolveFlags rf = ResolveFlags.VariableOrValue;
2572 rf |= ResolveFlags.DisableFlowAnalysis;
2573 return var.Resolve (ec, rf);
2577 ParameterReference pref = current_block.Toplevel.GetParameterReference (Name, loc);
2579 if (targs != null) {
2580 Report.Error (307, loc,
2581 "The variable `{0}' cannot be used with type arguments",
2586 if (right_side != null)
2587 return pref.ResolveLValue (ec, right_side, loc);
2589 return pref.Resolve (ec);
2592 Expression expr = current_block.Toplevel.GetTransparentIdentifier (Name);
2594 if (right_side != null)
2595 return expr.ResolveLValue (ec, right_side, loc);
2596 return expr.Resolve (ec);
2601 // Stage 2: Lookup members
2604 Type almost_matched_type = null;
2605 ArrayList almost_matched = null;
2606 for (DeclSpace lookup_ds = ec.DeclContainer; lookup_ds != null; lookup_ds = lookup_ds.Parent) {
2607 // either RootDeclSpace or GenericMethod
2608 if (lookup_ds.TypeBuilder == null)
2611 e = MemberLookup (ec.ContainerType, lookup_ds.TypeBuilder, Name, loc);
2613 if (e is PropertyExpr) {
2614 // since TypeManager.MemberLookup doesn't know if we're doing a lvalue access or not,
2615 // it doesn't know which accessor to check permissions against
2616 if (((PropertyExpr) e).IsAccessibleFrom (ec.ContainerType, right_side != null))
2618 } else if (e is EventExpr) {
2619 if (((EventExpr) e).IsAccessibleFrom (ec.ContainerType))
2627 if (almost_matched == null && almost_matched_members.Count > 0) {
2628 almost_matched_type = lookup_ds.TypeBuilder;
2629 almost_matched = (ArrayList) almost_matched_members.Clone ();
2634 if (almost_matched == null && almost_matched_members.Count > 0) {
2635 almost_matched_type = ec.ContainerType;
2636 almost_matched = (ArrayList) almost_matched_members.Clone ();
2638 e = ResolveAsTypeStep (ec, true);
2642 if (current_block != null) {
2643 IKnownVariable ikv = current_block.Explicit.GetKnownVariable (Name);
2645 LocalInfo li = ikv as LocalInfo;
2646 // Supress CS0219 warning
2650 Error_VariableIsUsedBeforeItIsDeclared (Name);
2655 if (almost_matched != null)
2656 almost_matched_members = almost_matched;
2657 if (almost_matched_type == null)
2658 almost_matched_type = ec.ContainerType;
2659 Error_MemberLookupFailed (ec.ContainerType, null, almost_matched_type, Name,
2660 ec.DeclContainer.Name, AllMemberTypes, AllBindingFlags);
2664 if (e is TypeExpr) {
2668 ConstructedType ct = new ConstructedType (
2669 e.Type, targs, loc);
2670 return ct.ResolveAsTypeStep (ec, false);
2673 if (e is MemberExpr) {
2674 MemberExpr me = (MemberExpr) e;
2677 if (me.IsInstance) {
2678 if (ec.IsStatic || ec.IsInFieldInitializer) {
2680 // Note that an MemberExpr can be both IsInstance and IsStatic.
2681 // An unresolved MethodGroupExpr can contain both kinds of methods
2682 // and each predicate is true if the MethodGroupExpr contains
2683 // at least one of that kind of method.
2687 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2688 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2693 // Pass the buck to MemberAccess and Invocation.
2695 left = EmptyExpression.Null;
2697 left = ec.GetThis (loc);
2700 left = new TypeExpression (ec.ContainerType, loc);
2703 me = me.ResolveMemberAccess (ec, left, loc, null);
2707 if (targs != null) {
2709 me.SetTypeArguments (targs);
2712 if (!me.IsStatic && (me.InstanceExpression != null) &&
2713 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2714 me.InstanceExpression.Type != me.DeclaringType &&
2715 !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2716 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2717 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2718 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2722 return (right_side != null)
2723 ? me.DoResolveLValue (ec, right_side)
2724 : me.DoResolve (ec);
2730 protected override void CloneTo (CloneContext clonectx, Expression target)
2732 // CloneTo: Nothing, we do not keep any state on this expression
2737 /// Represents a namespace or a type. The name of the class was inspired by
2738 /// section 10.8.1 (Fully Qualified Names).
2740 public abstract class FullNamedExpression : Expression {
2741 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2746 public override void Emit (EmitContext ec)
2748 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2749 GetSignatureForError ());
2754 /// Expression that evaluates to a type
2756 public abstract class TypeExpr : FullNamedExpression {
2757 override public FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2759 TypeExpr t = DoResolveAsTypeStep (ec);
2763 eclass = ExprClass.Type;
2767 override public Expression DoResolve (EmitContext ec)
2769 return ResolveAsTypeTerminal (ec, false);
2772 public virtual bool CheckAccessLevel (DeclSpace ds)
2774 return ds.CheckAccessLevel (Type);
2777 public virtual bool AsAccessible (DeclSpace ds)
2779 return ds.IsAccessibleAs (Type);
2782 public virtual bool IsClass {
2783 get { return Type.IsClass; }
2786 public virtual bool IsValueType {
2787 get { return Type.IsValueType; }
2790 public virtual bool IsInterface {
2791 get { return Type.IsInterface; }
2794 public virtual bool IsSealed {
2795 get { return Type.IsSealed; }
2798 public virtual bool CanInheritFrom ()
2800 if (Type == TypeManager.enum_type ||
2801 (Type == TypeManager.value_type && RootContext.StdLib) ||
2802 Type == TypeManager.multicast_delegate_type ||
2803 Type == TypeManager.delegate_type ||
2804 Type == TypeManager.array_type)
2810 protected abstract TypeExpr DoResolveAsTypeStep (IResolveContext ec);
2812 public override bool Equals (object obj)
2814 TypeExpr tobj = obj as TypeExpr;
2818 return Type == tobj.Type;
2821 public override int GetHashCode ()
2823 return Type.GetHashCode ();
2828 /// Fully resolved Expression that already evaluated to a type
2830 public class TypeExpression : TypeExpr {
2831 public TypeExpression (Type t, Location l)
2834 eclass = ExprClass.Type;
2838 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2843 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2850 /// Used to create types from a fully qualified name. These are just used
2851 /// by the parser to setup the core types. A TypeLookupExpression is always
2852 /// classified as a type.
2854 public sealed class TypeLookupExpression : TypeExpr {
2855 readonly string name;
2857 public TypeLookupExpression (string name)
2860 eclass = ExprClass.Type;
2863 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2865 // It's null for corlib compilation only
2867 return DoResolveAsTypeStep (ec);
2872 private class UnexpectedType
2876 // This performes recursive type lookup, providing support for generic types.
2877 // For example, given the type:
2879 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]]
2881 // The types will be checked in the following order:
2884 // System.Collections |
2885 // System.Collections.Generic |
2887 // System | recursive call 1 |
2888 // System.Int32 _| | main method call
2890 // System | recursive call 2 |
2891 // System.String _| |
2893 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]] _|
2895 private Type TypeLookup (IResolveContext ec, string name)
2900 FullNamedExpression resolved = null;
2902 Type recursive_type = null;
2903 while (index < name.Length) {
2904 if (name[index] == '[') {
2909 if (name[index] == '[')
2911 else if (name[index] == ']')
2913 } while (braces > 0);
2914 recursive_type = TypeLookup (ec, name.Substring (open + 1, index - open - 1));
2915 if (recursive_type == null || (recursive_type == typeof(UnexpectedType)))
2916 return recursive_type;
2919 if (name[index] == ',')
2921 else if ((name[index] == '.' && !done) || (index == name.Length && name[0] != '[')) {
2922 string substring = name.Substring(dot, index - dot);
2924 if (resolved == null)
2925 resolved = RootNamespace.Global.Lookup (ec.DeclContainer, substring, Location.Null);
2926 else if (resolved is Namespace)
2927 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
2928 else if (type != null)
2929 type = TypeManager.GetNestedType (type, substring);
2933 if (resolved == null)
2935 else if (type == null && resolved is TypeExpr)
2936 type = resolved.Type;
2943 if (name[0] != '[') {
2944 string substring = name.Substring(dot, index - dot);
2947 return TypeManager.GetNestedType (type, substring);
2949 if (resolved != null) {
2950 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
2951 if (resolved is TypeExpr)
2952 return resolved.Type;
2954 if (resolved == null)
2957 resolved.Error_UnexpectedKind (ec.DeclContainer, "type", loc);
2958 return typeof (UnexpectedType);
2964 return recursive_type;
2967 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2969 Type t = TypeLookup (ec, name);
2971 NamespaceEntry.Error_NamespaceNotFound (loc, name);
2974 if (t == typeof(UnexpectedType))
2980 protected override void CloneTo (CloneContext clonectx, Expression target)
2982 // CloneTo: Nothing, we do not keep any state on this expression
2985 public override string GetSignatureForError ()
2988 return TypeManager.CSharpName (name);
2990 return base.GetSignatureForError ();
2995 /// Represents an "unbound generic type", ie. typeof (Foo<>).
2998 public class UnboundTypeExpression : TypeExpr
3002 public UnboundTypeExpression (MemberName name, Location l)
3008 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
3011 if (name.Left != null) {
3012 Expression lexpr = name.Left.GetTypeExpression ();
3013 expr = new MemberAccess (lexpr, name.Basename);
3015 expr = new SimpleName (name.Basename, loc);
3018 FullNamedExpression fne = expr.ResolveAsTypeStep (ec, false);
3023 return new TypeExpression (type, loc);
3028 /// This class denotes an expression which evaluates to a member
3029 /// of a struct or a class.
3031 public abstract class MemberExpr : Expression
3033 protected bool is_base;
3036 /// The name of this member.
3038 public abstract string Name {
3043 // When base.member is used
3045 public bool IsBase {
3046 get { return is_base; }
3047 set { is_base = value; }
3051 /// Whether this is an instance member.
3053 public abstract bool IsInstance {
3058 /// Whether this is a static member.
3060 public abstract bool IsStatic {
3065 /// The type which declares this member.
3067 public abstract Type DeclaringType {
3072 /// The instance expression associated with this member, if it's a
3073 /// non-static member.
3075 public Expression InstanceExpression;
3077 public static void error176 (Location loc, string name)
3079 Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
3080 "with an instance reference, qualify it with a type name instead", name);
3083 // TODO: possible optimalization
3084 // Cache resolved constant result in FieldBuilder <-> expression map
3085 public virtual MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3086 SimpleName original)
3090 // original == null || original.Resolve (...) ==> left
3093 if (left is TypeExpr) {
3094 left = left.ResolveAsTypeTerminal (ec, true);
3099 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3107 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3110 return ResolveExtensionMemberAccess (left);
3113 InstanceExpression = left;
3117 protected virtual MemberExpr ResolveExtensionMemberAccess (Expression left)
3119 error176 (loc, GetSignatureForError ());
3123 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3128 if (InstanceExpression == EmptyExpression.Null) {
3129 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3133 if (InstanceExpression.Type.IsValueType) {
3134 if (InstanceExpression is IMemoryLocation) {
3135 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
3137 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
3138 InstanceExpression.Emit (ec);
3140 t.AddressOf (ec, AddressOp.Store);
3143 InstanceExpression.Emit (ec);
3145 if (prepare_for_load)
3146 ec.ig.Emit (OpCodes.Dup);
3149 public virtual void SetTypeArguments (TypeArguments ta)
3151 // TODO: need to get correct member type
3152 Report.Error (307, loc, "The property `{0}' cannot be used with type arguments",
3153 GetSignatureForError ());
3158 /// Represents group of extension methods
3160 public class ExtensionMethodGroupExpr : MethodGroupExpr
3162 readonly NamespaceEntry namespace_entry;
3163 public Expression ExtensionExpression;
3164 Argument extension_argument;
3166 public ExtensionMethodGroupExpr (ArrayList list, NamespaceEntry n, Type extensionType, Location l)
3167 : base (list, extensionType, l)
3169 this.namespace_entry = n;
3172 public override bool IsStatic {
3173 get { return true; }
3176 public bool IsTopLevel {
3177 get { return namespace_entry == null; }
3180 public override void EmitArguments (EmitContext ec, ArrayList arguments)
3182 if (arguments == null)
3183 arguments = new ArrayList (1);
3184 arguments.Insert (0, extension_argument);
3185 base.EmitArguments (ec, arguments);
3188 public override void EmitCall (EmitContext ec, ArrayList arguments)
3190 if (arguments == null)
3191 arguments = new ArrayList (1);
3192 arguments.Insert (0, extension_argument);
3193 base.EmitCall (ec, arguments);
3196 public override MethodGroupExpr OverloadResolve (EmitContext ec, ref ArrayList arguments, bool may_fail, Location loc)
3198 if (arguments == null)
3199 arguments = new ArrayList (1);
3201 arguments.Insert (0, new Argument (ExtensionExpression));
3202 MethodGroupExpr mg = ResolveOverloadExtensions (ec, arguments, namespace_entry, loc);
3204 // Store resolved argument and restore original arguments
3206 ((ExtensionMethodGroupExpr)mg).extension_argument = (Argument)arguments [0];
3207 arguments.RemoveAt (0);
3212 MethodGroupExpr ResolveOverloadExtensions (EmitContext ec, ArrayList arguments, NamespaceEntry ns, Location loc)
3214 // Use normal resolve rules
3215 MethodGroupExpr mg = base.OverloadResolve (ec, ref arguments, ns != null, loc);
3223 ExtensionMethodGroupExpr e = ns.LookupExtensionMethod (type, null, Name, loc);
3225 return base.OverloadResolve (ec, ref arguments, false, loc);
3227 e.ExtensionExpression = ExtensionExpression;
3228 return e.ResolveOverloadExtensions (ec, arguments, e.namespace_entry, loc);
3233 /// MethodGroupExpr represents a group of method candidates which
3234 /// can be resolved to the best method overload
3236 public class MethodGroupExpr : MemberExpr
3238 public interface IErrorHandler
3240 bool NoExactMatch (EmitContext ec, MethodBase method);
3243 public IErrorHandler CustomErrorHandler;
3244 public MethodBase [] Methods;
3245 MethodBase best_candidate;
3246 // TODO: make private
3247 public TypeArguments type_arguments;
3248 bool identical_type_name;
3251 public MethodGroupExpr (MemberInfo [] mi, Type type, Location l)
3254 Methods = new MethodBase [mi.Length];
3255 mi.CopyTo (Methods, 0);
3258 public MethodGroupExpr (ArrayList list, Type type, Location l)
3262 Methods = (MethodBase[])list.ToArray (typeof (MethodBase));
3264 foreach (MemberInfo m in list){
3265 if (!(m is MethodBase)){
3266 Console.WriteLine ("Name " + m.Name);
3267 Console.WriteLine ("Found a: " + m.GetType ().FullName);
3276 protected MethodGroupExpr (Type type, Location loc)
3279 eclass = ExprClass.MethodGroup;
3283 public override Type DeclaringType {
3286 // We assume that the top-level type is in the end
3288 return Methods [Methods.Length - 1].DeclaringType;
3289 //return Methods [0].DeclaringType;
3293 public Type DelegateType {
3295 delegate_type = value;
3299 public bool IdenticalTypeName {
3301 return identical_type_name;
3305 identical_type_name = value;
3309 public override string GetSignatureForError ()
3311 if (best_candidate != null)
3312 return TypeManager.CSharpSignature (best_candidate);
3314 return TypeManager.CSharpSignature (Methods [0]);
3317 public override string Name {
3319 return Methods [0].Name;
3323 public override bool IsInstance {
3325 if (best_candidate != null)
3326 return !best_candidate.IsStatic;
3328 foreach (MethodBase mb in Methods)
3336 public override bool IsStatic {
3338 if (best_candidate != null)
3339 return best_candidate.IsStatic;
3341 foreach (MethodBase mb in Methods)
3349 public static explicit operator ConstructorInfo (MethodGroupExpr mg)
3351 return (ConstructorInfo)mg.best_candidate;
3354 public static explicit operator MethodInfo (MethodGroupExpr mg)
3356 return (MethodInfo)mg.best_candidate;
3360 // 7.4.3.3 Better conversion from expression
3361 // Returns : 1 if a->p is better,
3362 // 2 if a->q is better,
3363 // 0 if neither is better
3365 static int BetterExpressionConversion (EmitContext ec, Argument a, Type p, Type q)
3367 Type argument_type = TypeManager.TypeToCoreType (a.Type);
3368 if (argument_type == TypeManager.anonymous_method_type && RootContext.Version > LanguageVersion.ISO_2) {
3370 // Uwrap delegate from Expression<T>
3372 if (TypeManager.DropGenericTypeArguments (p) == TypeManager.expression_type) {
3373 p = TypeManager.GetTypeArguments (p) [0];
3374 q = TypeManager.GetTypeArguments (q) [0];
3376 p = Delegate.GetInvokeMethod (null, p).ReturnType;
3377 q = Delegate.GetInvokeMethod (null, q).ReturnType;
3379 if (argument_type == p)
3382 if (argument_type == q)
3386 return BetterTypeConversion (ec, p, q);
3390 // 7.4.3.4 Better conversion from type
3392 public static int BetterTypeConversion (EmitContext ec, Type p, Type q)
3394 if (p == null || q == null)
3395 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3397 if (p == TypeManager.int32_type) {
3398 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3400 } else if (p == TypeManager.int64_type) {
3401 if (q == TypeManager.uint64_type)
3403 } else if (p == TypeManager.sbyte_type) {
3404 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3405 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3407 } else if (p == TypeManager.short_type) {
3408 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3409 q == TypeManager.uint64_type)
3413 if (q == TypeManager.int32_type) {
3414 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3416 } if (q == TypeManager.int64_type) {
3417 if (p == TypeManager.uint64_type)
3419 } else if (q == TypeManager.sbyte_type) {
3420 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3421 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3423 } if (q == TypeManager.short_type) {
3424 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3425 p == TypeManager.uint64_type)
3429 // TODO: this is expensive
3430 Expression p_tmp = new EmptyExpression (p);
3431 Expression q_tmp = new EmptyExpression (q);
3433 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3434 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3436 if (p_to_q && !q_to_p)
3439 if (q_to_p && !p_to_q)
3446 /// Determines "Better function" between candidate
3447 /// and the current best match
3450 /// Returns a boolean indicating :
3451 /// false if candidate ain't better
3452 /// true if candidate is better than the current best match
3454 static bool BetterFunction (EmitContext ec, ArrayList args, int argument_count,
3455 MethodBase candidate, bool candidate_params,
3456 MethodBase best, bool best_params)
3458 ParameterData candidate_pd = TypeManager.GetParameterData (candidate);
3459 ParameterData best_pd = TypeManager.GetParameterData (best);
3461 bool better_at_least_one = false;
3463 for (int j = 0, c_idx = 0, b_idx = 0; j < argument_count; ++j, ++c_idx, ++b_idx)
3465 Argument a = (Argument) args [j];
3467 Type ct = TypeManager.TypeToCoreType (candidate_pd.ParameterType (c_idx));
3468 Type bt = TypeManager.TypeToCoreType (best_pd.ParameterType (b_idx));
3470 if (candidate_params && candidate_pd.ParameterModifier (c_idx) == Parameter.Modifier.PARAMS)
3472 ct = TypeManager.GetElementType (ct);
3476 if (best_params && best_pd.ParameterModifier (b_idx) == Parameter.Modifier.PARAMS)
3478 bt = TypeManager.GetElementType (bt);
3486 int result = BetterExpressionConversion (ec, a, ct, bt);
3488 // for each argument, the conversion to 'ct' should be no worse than
3489 // the conversion to 'bt'.
3493 // for at least one argument, the conversion to 'ct' should be better than
3494 // the conversion to 'bt'.
3496 better_at_least_one = true;
3499 if (better_at_least_one)
3503 // This handles the case
3505 // Add (float f1, float f2, float f3);
3506 // Add (params decimal [] foo);
3508 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3509 // first candidate would've chosen as better.
3515 // The two methods have equal parameter types. Now apply tie-breaking rules
3517 if (TypeManager.IsGenericMethod (best) && !TypeManager.IsGenericMethod (candidate))
3519 if (!TypeManager.IsGenericMethod (best) && TypeManager.IsGenericMethod (candidate))
3523 // This handles the following cases:
3525 // Trim () is better than Trim (params char[] chars)
3526 // Concat (string s1, string s2, string s3) is better than
3527 // Concat (string s1, params string [] srest)
3528 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3530 if (!candidate_params && best_params)
3532 if (candidate_params && !best_params)
3535 int candidate_param_count = candidate_pd.Count;
3536 int best_param_count = best_pd.Count;
3538 if (candidate_param_count != best_param_count)
3539 // can only happen if (candidate_params && best_params)
3540 return candidate_param_count > best_param_count;
3543 // now, both methods have the same number of parameters, and the parameters have the same types
3544 // Pick the "more specific" signature
3547 MethodBase orig_candidate = TypeManager.DropGenericMethodArguments (candidate);
3548 MethodBase orig_best = TypeManager.DropGenericMethodArguments (best);
3550 ParameterData orig_candidate_pd = TypeManager.GetParameterData (orig_candidate);
3551 ParameterData orig_best_pd = TypeManager.GetParameterData (orig_best);
3553 bool specific_at_least_once = false;
3554 for (int j = 0; j < candidate_param_count; ++j)
3556 Type ct = TypeManager.TypeToCoreType (orig_candidate_pd.ParameterType (j));
3557 Type bt = TypeManager.TypeToCoreType (orig_best_pd.ParameterType (j));
3560 Type specific = MoreSpecific (ct, bt);
3564 specific_at_least_once = true;
3567 if (specific_at_least_once)
3570 // FIXME: handle lifted operators
3576 protected override MemberExpr ResolveExtensionMemberAccess (Expression left)
3579 return base.ResolveExtensionMemberAccess (left);
3582 // When left side is an expression and at least one candidate method is
3583 // static, it can be extension method
3585 InstanceExpression = left;
3589 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3590 SimpleName original)
3592 if (!(left is TypeExpr) &&
3593 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3594 IdenticalTypeName = true;
3596 return base.ResolveMemberAccess (ec, left, loc, original);
3599 public override Expression CreateExpressionTree (EmitContext ec)
3601 if (best_candidate.IsConstructor)
3602 return new TypeOfConstructorInfo (best_candidate, loc);
3604 return new TypeOfMethodInfo (best_candidate, loc);
3607 override public Expression DoResolve (EmitContext ec)
3609 if (InstanceExpression != null) {
3610 InstanceExpression = InstanceExpression.DoResolve (ec);
3611 if (InstanceExpression == null)
3618 public void ReportUsageError ()
3620 Report.Error (654, loc, "Method `" + DeclaringType + "." +
3621 Name + "()' is referenced without parentheses");
3624 override public void Emit (EmitContext ec)
3626 ReportUsageError ();
3629 public virtual void EmitArguments (EmitContext ec, ArrayList arguments)
3631 Invocation.EmitArguments (ec, arguments, false, null);
3634 public virtual void EmitCall (EmitContext ec, ArrayList arguments)
3636 Invocation.EmitCall (ec, IsBase, InstanceExpression, best_candidate, arguments, loc);
3639 protected virtual void Error_InvalidArguments (EmitContext ec, Location loc, int idx, MethodBase method,
3640 Argument a, ParameterData expected_par, Type paramType)
3642 if (a is CollectionElementInitializer.ElementInitializerArgument) {
3643 Report.SymbolRelatedToPreviousError (method);
3644 if ((expected_par.ParameterModifier (idx) & Parameter.Modifier.ISBYREF) != 0) {
3645 Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
3646 TypeManager.CSharpSignature (method));
3649 Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
3650 TypeManager.CSharpSignature (method));
3651 } else if (delegate_type == null) {
3652 Report.SymbolRelatedToPreviousError (method);
3653 Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
3654 TypeManager.CSharpSignature (method));
3656 Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
3657 TypeManager.CSharpName (delegate_type));
3659 Parameter.Modifier mod = expected_par.ParameterModifier (idx);
3661 string index = (idx + 1).ToString ();
3662 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
3663 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
3664 if ((mod & Parameter.Modifier.ISBYREF) == 0)
3665 Report.Error (1615, loc, "Argument `{0}' should not be passed with the `{1}' keyword",
3666 index, Parameter.GetModifierSignature (a.Modifier));
3668 Report.Error (1620, loc, "Argument `{0}' must be passed with the `{1}' keyword",
3669 index, Parameter.GetModifierSignature (mod));
3671 string p1 = a.GetSignatureForError ();
3672 string p2 = TypeManager.CSharpName (paramType);
3675 Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
3676 Report.SymbolRelatedToPreviousError (a.Expr.Type);
3677 Report.SymbolRelatedToPreviousError (paramType);
3679 Report.Error (1503, loc, "Argument {0}: Cannot convert type `{1}' to `{2}'", index, p1, p2);
3683 public override void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl)
3685 Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3686 Name, TypeManager.CSharpName (target));
3689 protected virtual int GetApplicableParametersCount (MethodBase method, ParameterData parameters)
3691 return parameters.Count;
3694 public static bool IsAncestralType (Type first_type, Type second_type)
3696 return first_type != second_type &&
3697 (TypeManager.IsSubclassOf (second_type, first_type) ||
3698 TypeManager.ImplementsInterface (second_type, first_type));
3702 /// Determines if the candidate method is applicable (section 14.4.2.1)
3703 /// to the given set of arguments
3704 /// A return value rates candidate method compatibility,
3705 /// 0 = the best, int.MaxValue = the worst
3707 public int IsApplicable (EmitContext ec,
3708 ArrayList arguments, int arg_count, ref MethodBase method, ref bool params_expanded_form)
3710 MethodBase candidate = method;
3712 ParameterData pd = TypeManager.GetParameterData (candidate);
3713 int param_count = GetApplicableParametersCount (candidate, pd);
3715 if (arg_count != param_count) {
3717 return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
3718 if (arg_count < param_count - 1)
3719 return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
3724 // 1. Handle generic method using type arguments when specified or type inference
3726 if (TypeManager.IsGenericMethod (candidate)) {
3727 if (type_arguments != null) {
3728 Type [] g_args = candidate.GetGenericArguments ();
3729 if (g_args.Length != type_arguments.Count)
3730 return int.MaxValue - 20000 + Math.Abs (type_arguments.Count - g_args.Length);
3732 // TODO: Don't create new method, create Parameters only
3733 method = ((MethodInfo) candidate).MakeGenericMethod (type_arguments.Arguments);
3735 pd = TypeManager.GetParameterData (candidate);
3737 int score = TypeManager.InferTypeArguments (ec, arguments, ref candidate);
3739 return score - 20000;
3741 if (TypeManager.IsGenericMethodDefinition (candidate))
3742 throw new InternalErrorException ("A generic method `{0}' definition took part in overload resolution",
3743 TypeManager.CSharpSignature (candidate));
3745 pd = TypeManager.GetParameterData (candidate);
3748 if (type_arguments != null)
3749 return int.MaxValue - 15000;
3754 // 2. Each argument has to be implicitly convertible to method parameter
3757 Parameter.Modifier p_mod = 0;
3759 for (int i = 0; i < arg_count; i++) {
3760 Argument a = (Argument) arguments [i];
3761 Parameter.Modifier a_mod = a.Modifier &
3762 ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3764 if (p_mod != Parameter.Modifier.PARAMS) {
3765 p_mod = pd.ParameterModifier (i) & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3767 if (p_mod == Parameter.Modifier.ARGLIST) {
3768 if (a.Type == TypeManager.runtime_argument_handle_type)
3774 pt = pd.ParameterType (i);
3776 params_expanded_form = true;
3780 if (!params_expanded_form)
3781 score = IsArgumentCompatible (ec, a_mod, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
3783 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0) {
3784 // It can be applicable in expanded form
3785 score = IsArgumentCompatible (ec, a_mod, a, 0, pt.GetElementType ());
3787 params_expanded_form = true;
3791 if (params_expanded_form)
3793 return (arg_count - i) * 2 + score;
3797 if (arg_count != param_count)
3798 params_expanded_form = true;
3803 int IsArgumentCompatible (EmitContext ec, Parameter.Modifier arg_mod, Argument argument, Parameter.Modifier param_mod, Type parameter)
3806 // Types have to be identical when ref or out modifer is used
3808 if (arg_mod != 0 || param_mod != 0) {
3809 if (TypeManager.HasElementType (parameter))
3810 parameter = parameter.GetElementType ();
3812 Type a_type = argument.Type;
3813 if (TypeManager.HasElementType (a_type))
3814 a_type = a_type.GetElementType ();
3816 if (a_type != parameter)
3822 // FIXME: Kill this abomination (EmitContext.TempEc)
3823 EmitContext prevec = EmitContext.TempEc;
3824 EmitContext.TempEc = ec;
3826 if (delegate_type != null ?
3827 !Delegate.IsTypeCovariant (argument.Expr, parameter) :
3828 !Convert.ImplicitConversionExists (ec, argument.Expr, parameter))
3831 if (arg_mod != param_mod)
3835 EmitContext.TempEc = prevec;
3841 public static bool IsOverride (MethodBase cand_method, MethodBase base_method)
3843 if (!IsAncestralType (base_method.DeclaringType, cand_method.DeclaringType))
3846 ParameterData cand_pd = TypeManager.GetParameterData (cand_method);
3847 ParameterData base_pd = TypeManager.GetParameterData (base_method);
3849 if (cand_pd.Count != base_pd.Count)
3852 for (int j = 0; j < cand_pd.Count; ++j)
3854 Parameter.Modifier cm = cand_pd.ParameterModifier (j);
3855 Parameter.Modifier bm = base_pd.ParameterModifier (j);
3856 Type ct = TypeManager.TypeToCoreType (cand_pd.ParameterType (j));
3857 Type bt = TypeManager.TypeToCoreType (base_pd.ParameterType (j));
3859 if (cm != bm || ct != bt)
3866 public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2, Location loc)
3868 MemberInfo [] miset;
3869 MethodGroupExpr union;
3874 return (MethodGroupExpr) mg2;
3877 return (MethodGroupExpr) mg1;
3880 MethodGroupExpr left_set = null, right_set = null;
3881 int length1 = 0, length2 = 0;
3883 left_set = (MethodGroupExpr) mg1;
3884 length1 = left_set.Methods.Length;
3886 right_set = (MethodGroupExpr) mg2;
3887 length2 = right_set.Methods.Length;
3889 ArrayList common = new ArrayList ();
3891 foreach (MethodBase r in right_set.Methods){
3892 if (TypeManager.ArrayContainsMethod (left_set.Methods, r))
3896 miset = new MemberInfo [length1 + length2 - common.Count];
3897 left_set.Methods.CopyTo (miset, 0);
3901 foreach (MethodBase r in right_set.Methods) {
3902 if (!common.Contains (r))
3906 union = new MethodGroupExpr (miset, mg1.Type, loc);
3911 static Type MoreSpecific (Type p, Type q)
3913 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
3915 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
3918 if (TypeManager.HasElementType (p))
3920 Type pe = TypeManager.GetElementType (p);
3921 Type qe = TypeManager.GetElementType (q);
3922 Type specific = MoreSpecific (pe, qe);
3928 else if (TypeManager.IsGenericType (p))
3930 Type[] pargs = TypeManager.GetTypeArguments (p);
3931 Type[] qargs = TypeManager.GetTypeArguments (q);
3933 bool p_specific_at_least_once = false;
3934 bool q_specific_at_least_once = false;
3936 for (int i = 0; i < pargs.Length; i++)
3938 Type specific = MoreSpecific (pargs [i], qargs [i]);
3939 if (specific == pargs [i])
3940 p_specific_at_least_once = true;
3941 if (specific == qargs [i])
3942 q_specific_at_least_once = true;
3945 if (p_specific_at_least_once && !q_specific_at_least_once)
3947 if (!p_specific_at_least_once && q_specific_at_least_once)
3955 /// Find the Applicable Function Members (7.4.2.1)
3957 /// me: Method Group expression with the members to select.
3958 /// it might contain constructors or methods (or anything
3959 /// that maps to a method).
3961 /// Arguments: ArrayList containing resolved Argument objects.
3963 /// loc: The location if we want an error to be reported, or a Null
3964 /// location for "probing" purposes.
3966 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3967 /// that is the best match of me on Arguments.
3970 public virtual MethodGroupExpr OverloadResolve (EmitContext ec, ref ArrayList Arguments,
3971 bool may_fail, Location loc)
3973 bool method_params = false;
3974 Type applicable_type = null;
3976 ArrayList candidates = new ArrayList (2);
3977 ArrayList candidate_overrides = null;
3980 // Used to keep a map between the candidate
3981 // and whether it is being considered in its
3982 // normal or expanded form
3984 // false is normal form, true is expanded form
3986 Hashtable candidate_to_form = null;
3988 if (Arguments != null)
3989 arg_count = Arguments.Count;
3991 if (RootContext.Version == LanguageVersion.ISO_1 && Name == "Invoke" && TypeManager.IsDelegateType (DeclaringType)) {
3993 Report.Error (1533, loc, "Invoke cannot be called directly on a delegate");
3997 int nmethods = Methods.Length;
4001 // Methods marked 'override' don't take part in 'applicable_type'
4002 // computation, nor in the actual overload resolution.
4003 // However, they still need to be emitted instead of a base virtual method.
4004 // So, we salt them away into the 'candidate_overrides' array.
4006 // In case of reflected methods, we replace each overriding method with
4007 // its corresponding base virtual method. This is to improve compatibility
4008 // with non-C# libraries which change the visibility of overrides (#75636)
4011 for (int i = 0; i < Methods.Length; ++i) {
4012 MethodBase m = Methods [i];
4013 if (TypeManager.IsOverride (m)) {
4014 if (candidate_overrides == null)
4015 candidate_overrides = new ArrayList ();
4016 candidate_overrides.Add (m);
4017 m = TypeManager.TryGetBaseDefinition (m);
4026 // Enable message recording, it's used mainly by lambda expressions
4028 Report.IMessageRecorder msg_recorder = new Report.MessageRecorder ();
4029 Report.IMessageRecorder prev_recorder = Report.SetMessageRecorder (msg_recorder);
4032 // First we construct the set of applicable methods
4034 bool is_sorted = true;
4035 int best_candidate_rate = int.MaxValue;
4036 for (int i = 0; i < nmethods; i++) {
4037 Type decl_type = Methods [i].DeclaringType;
4040 // If we have already found an applicable method
4041 // we eliminate all base types (Section 14.5.5.1)
4043 if (applicable_type != null && IsAncestralType (decl_type, applicable_type))
4047 // Check if candidate is applicable (section 14.4.2.1)
4049 bool params_expanded_form = false;
4050 int candidate_rate = IsApplicable (ec, Arguments, arg_count, ref Methods [i], ref params_expanded_form);
4052 if (candidate_rate < best_candidate_rate) {
4053 best_candidate_rate = candidate_rate;
4054 best_candidate = Methods [i];
4057 if (params_expanded_form) {
4058 if (candidate_to_form == null)
4059 candidate_to_form = new PtrHashtable ();
4060 MethodBase candidate = Methods [i];
4061 candidate_to_form [candidate] = candidate;
4064 if (candidate_rate != 0) {
4065 if (msg_recorder != null)
4066 msg_recorder.EndSession ();
4070 msg_recorder = null;
4071 candidates.Add (Methods [i]);
4073 if (applicable_type == null)
4074 applicable_type = decl_type;
4075 else if (applicable_type != decl_type) {
4077 if (IsAncestralType (applicable_type, decl_type))
4078 applicable_type = decl_type;
4082 Report.SetMessageRecorder (prev_recorder);
4083 if (msg_recorder != null && msg_recorder.PrintMessages ())
4086 int candidate_top = candidates.Count;
4088 if (applicable_type == null) {
4090 // When we found a top level method which does not match and it's
4091 // not an extension method. We start extension methods lookup from here
4093 if (InstanceExpression != null) {
4094 ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (type, Name, loc);
4095 if (ex_method_lookup != null) {
4096 ex_method_lookup.ExtensionExpression = InstanceExpression;
4097 ex_method_lookup.SetTypeArguments (type_arguments);
4098 return ex_method_lookup.OverloadResolve (ec, ref Arguments, may_fail, loc);
4106 // Okay so we have failed to find exact match so we
4107 // return error info about the closest match
4109 if (best_candidate != null) {
4110 if (CustomErrorHandler != null) {
4111 if (CustomErrorHandler.NoExactMatch (ec, best_candidate))
4115 ParameterData pd = TypeManager.GetParameterData (best_candidate);
4116 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4117 if (arg_count == pd.Count || pd.HasParams) {
4118 if (TypeManager.IsGenericMethodDefinition (best_candidate)) {
4119 if (type_arguments == null) {
4120 Report.Error (411, loc,
4121 "The type arguments for method `{0}' cannot be inferred from " +
4122 "the usage. Try specifying the type arguments explicitly",
4123 TypeManager.CSharpSignature (best_candidate));
4127 Type [] g_args = TypeManager.GetGenericArguments (best_candidate);
4128 if (type_arguments.Count != g_args.Length) {
4129 Report.SymbolRelatedToPreviousError (best_candidate);
4130 Report.Error (305, loc, "Using the generic method `{0}' requires `{1}' type argument(s)",
4131 TypeManager.CSharpSignature (best_candidate),
4132 g_args.Length.ToString ());
4136 if (type_arguments != null && !TypeManager.IsGenericMethod (best_candidate)) {
4137 Namespace.Error_TypeArgumentsCannotBeUsed (best_candidate, loc);
4142 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate, cand_params, may_fail, loc))
4147 if (almost_matched_members.Count != 0) {
4148 Error_MemberLookupFailed (ec.ContainerType, type, type, ".ctor",
4149 null, MemberTypes.Constructor, AllBindingFlags);
4154 // We failed to find any method with correct argument count
4156 if (Name == ConstructorInfo.ConstructorName) {
4157 Report.SymbolRelatedToPreviousError (type);
4158 Report.Error (1729, loc,
4159 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4160 TypeManager.CSharpName (type), arg_count);
4162 Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4163 Name, arg_count.ToString ());
4171 // At this point, applicable_type is _one_ of the most derived types
4172 // in the set of types containing the methods in this MethodGroup.
4173 // Filter the candidates so that they only contain methods from the
4174 // most derived types.
4177 int finalized = 0; // Number of finalized candidates
4180 // Invariant: applicable_type is a most derived type
4182 // We'll try to complete Section 14.5.5.1 for 'applicable_type' by
4183 // eliminating all it's base types. At the same time, we'll also move
4184 // every unrelated type to the end of the array, and pick the next
4185 // 'applicable_type'.
4187 Type next_applicable_type = null;
4188 int j = finalized; // where to put the next finalized candidate
4189 int k = finalized; // where to put the next undiscarded candidate
4190 for (int i = finalized; i < candidate_top; ++i) {
4191 MethodBase candidate = (MethodBase) candidates [i];
4192 Type decl_type = candidate.DeclaringType;
4194 if (decl_type == applicable_type) {
4195 candidates [k++] = candidates [j];
4196 candidates [j++] = candidates [i];
4200 if (IsAncestralType (decl_type, applicable_type))
4203 if (next_applicable_type != null &&
4204 IsAncestralType (decl_type, next_applicable_type))
4207 candidates [k++] = candidates [i];
4209 if (next_applicable_type == null ||
4210 IsAncestralType (next_applicable_type, decl_type))
4211 next_applicable_type = decl_type;
4214 applicable_type = next_applicable_type;
4217 } while (applicable_type != null);
4221 // Now we actually find the best method
4224 best_candidate = (MethodBase) candidates [0];
4225 if (delegate_type == null)
4226 method_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4228 for (int ix = 1; ix < candidate_top; ix++) {
4229 MethodBase candidate = (MethodBase) candidates [ix];
4231 if (candidate == best_candidate)
4234 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4236 if (BetterFunction (ec, Arguments, arg_count,
4237 candidate, cand_params,
4238 best_candidate, method_params)) {
4239 best_candidate = candidate;
4240 method_params = cand_params;
4244 // Now check that there are no ambiguities i.e the selected method
4245 // should be better than all the others
4247 MethodBase ambiguous = null;
4248 for (int ix = 1; ix < candidate_top; ix++) {
4249 MethodBase candidate = (MethodBase) candidates [ix];
4251 if (candidate == best_candidate)
4254 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4255 if (!BetterFunction (ec, Arguments, arg_count,
4256 best_candidate, method_params,
4257 candidate, cand_params))
4260 Report.SymbolRelatedToPreviousError (candidate);
4261 ambiguous = candidate;
4265 if (ambiguous != null) {
4266 Report.SymbolRelatedToPreviousError (best_candidate);
4267 Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4268 TypeManager.CSharpSignature (ambiguous), TypeManager.CSharpSignature (best_candidate));
4273 // If the method is a virtual function, pick an override closer to the LHS type.
4275 if (!IsBase && best_candidate.IsVirtual) {
4276 if (TypeManager.IsOverride (best_candidate))
4277 throw new InternalErrorException (
4278 "Should not happen. An 'override' method took part in overload resolution: " + best_candidate);
4280 if (candidate_overrides != null) {
4281 Type[] gen_args = null;
4282 bool gen_override = false;
4283 if (TypeManager.IsGenericMethod (best_candidate))
4284 gen_args = TypeManager.GetGenericArguments (best_candidate);
4286 foreach (MethodBase candidate in candidate_overrides) {
4287 if (TypeManager.IsGenericMethod (candidate)) {
4288 if (gen_args == null)
4291 if (gen_args.Length != TypeManager.GetGenericArguments (candidate).Length)
4294 if (gen_args != null)
4298 if (IsOverride (candidate, best_candidate)) {
4299 gen_override = true;
4300 best_candidate = candidate;
4304 if (gen_override && gen_args != null) {
4306 best_candidate = ((MethodInfo) best_candidate).MakeGenericMethod (gen_args);
4313 // And now check if the arguments are all
4314 // compatible, perform conversions if
4315 // necessary etc. and return if everything is
4318 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate,
4319 method_params, may_fail, loc))
4322 if (best_candidate == null)
4325 MethodBase the_method = TypeManager.DropGenericMethodArguments (best_candidate);
4327 if (the_method.IsGenericMethodDefinition &&
4328 !ConstraintChecker.CheckConstraints (ec, the_method, best_candidate, loc))
4332 IMethodData data = TypeManager.GetMethod (the_method);
4334 data.SetMemberIsUsed ();
4339 public override void SetTypeArguments (TypeArguments ta)
4341 type_arguments = ta;
4344 public bool VerifyArgumentsCompat (EmitContext ec, ref ArrayList arguments,
4345 int arg_count, MethodBase method,
4346 bool chose_params_expanded,
4347 bool may_fail, Location loc)
4349 ParameterData pd = TypeManager.GetParameterData (method);
4351 int errors = Report.Errors;
4352 Parameter.Modifier p_mod = 0;
4354 int a_idx = 0, a_pos = 0;
4356 ArrayList params_initializers = null;
4358 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4359 a = (Argument) arguments [a_idx];
4360 if (p_mod != Parameter.Modifier.PARAMS) {
4361 p_mod = pd.ParameterModifier (a_idx);
4362 pt = pd.ParameterType (a_idx);
4364 if (p_mod == Parameter.Modifier.ARGLIST) {
4365 if (a.Type != TypeManager.runtime_argument_handle_type)
4370 if (pt.IsPointer && !ec.InUnsafe) {
4377 if (p_mod == Parameter.Modifier.PARAMS) {
4378 if (chose_params_expanded) {
4379 params_initializers = new ArrayList (arg_count - a_idx);
4380 pt = TypeManager.GetElementType (pt);
4382 } else if (p_mod != 0) {
4383 pt = TypeManager.GetElementType (pt);
4388 // Types have to be identical when ref or out modifer is used
4390 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4391 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4394 if (!TypeManager.IsEqual (a.Expr.Type, pt))
4401 if (TypeManager.IsEqual (a.Type, pt)) {
4404 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4410 // Convert params arguments to an array initializer
4412 if (params_initializers != null) {
4413 params_initializers.Add (conv);
4414 arguments.RemoveAt (a_idx--);
4419 // Update the argument with the implicit conversion
4424 // Fill not provided arguments required by params modifier
4426 if (params_initializers == null && pd.HasParams && arg_count < pd.Count && a_idx + 1 == pd.Count) {
4427 if (arguments == null)
4428 arguments = new ArrayList (1);
4430 pt = pd.Types [GetApplicableParametersCount (method, pd) - 1];
4431 pt = TypeManager.GetElementType (pt);
4432 params_initializers = new ArrayList (0);
4435 if (a_idx == arg_count) {
4437 // Append an array argument with all params arguments
4439 if (params_initializers != null) {
4440 arguments.Add (new Argument (
4441 new ArrayCreation (new TypeExpression (pt, loc), "[]",
4442 params_initializers, loc).Resolve (ec)));
4447 if (!may_fail && Report.Errors == errors) {
4448 if (CustomErrorHandler != null)
4449 CustomErrorHandler.NoExactMatch (ec, best_candidate);
4451 Error_InvalidArguments (ec, loc, a_pos, method, a, pd, pt);
4457 public class ConstantExpr : MemberExpr
4461 public ConstantExpr (FieldInfo constant, Location loc)
4463 this.constant = constant;
4467 public override string Name {
4468 get { throw new NotImplementedException (); }
4471 public override bool IsInstance {
4472 get { return !IsStatic; }
4475 public override bool IsStatic {
4476 get { return constant.IsStatic; }
4479 public override Type DeclaringType {
4480 get { return constant.DeclaringType; }
4483 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc, SimpleName original)
4485 constant = TypeManager.GetGenericFieldDefinition (constant);
4487 IConstant ic = TypeManager.GetConstant (constant);
4489 if (constant.IsLiteral) {
4490 ic = new ExternalConstant (constant);
4492 ic = ExternalConstant.CreateDecimal (constant);
4493 // HACK: decimal field was not resolved as constant
4495 return new FieldExpr (constant, loc).ResolveMemberAccess (ec, left, loc, original);
4497 TypeManager.RegisterConstant (constant, ic);
4500 return base.ResolveMemberAccess (ec, left, loc, original);
4503 public override Expression CreateExpressionTree (EmitContext ec)
4505 throw new NotSupportedException ();
4508 public override Expression DoResolve (EmitContext ec)
4510 IConstant ic = TypeManager.GetConstant (constant);
4511 if (ic.ResolveValue ()) {
4512 if (!ec.IsInObsoleteScope)
4513 ic.CheckObsoleteness (loc);
4516 return ic.CreateConstantReference (loc);
4519 public override void Emit (EmitContext ec)
4521 throw new NotSupportedException ();
4524 public override string GetSignatureForError ()
4526 return TypeManager.GetFullNameSignature (constant);
4531 /// Fully resolved expression that evaluates to a Field
4533 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariable {
4534 public readonly FieldInfo FieldInfo;
4535 VariableInfo variable_info;
4537 LocalTemporary temp;
4539 bool in_initializer;
4541 public FieldExpr (FieldInfo fi, Location l, bool in_initializer):
4544 this.in_initializer = in_initializer;
4547 public FieldExpr (FieldInfo fi, Location l)
4550 eclass = ExprClass.Variable;
4551 type = TypeManager.TypeToCoreType (fi.FieldType);
4555 public override string Name {
4557 return FieldInfo.Name;
4561 public override bool IsInstance {
4563 return !FieldInfo.IsStatic;
4567 public override bool IsStatic {
4569 return FieldInfo.IsStatic;
4573 public override Type DeclaringType {
4575 return FieldInfo.DeclaringType;
4579 public override string GetSignatureForError ()
4581 return TypeManager.GetFullNameSignature (FieldInfo);
4584 public VariableInfo VariableInfo {
4586 return variable_info;
4590 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
4591 SimpleName original)
4593 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
4594 Type t = fi.FieldType;
4596 if (t.IsPointer && !ec.InUnsafe) {
4600 return base.ResolveMemberAccess (ec, left, loc, original);
4603 public override Expression CreateExpressionTree (EmitContext ec)
4605 Expression instance;
4606 if (InstanceExpression == null) {
4607 instance = new NullLiteral (loc);
4609 instance = InstanceExpression.CreateExpressionTree (ec);
4612 ArrayList args = new ArrayList (2);
4613 args.Add (new Argument (instance));
4614 args.Add (new Argument (CreateTypeOfExpression ()));
4615 return CreateExpressionFactoryCall ("Field", args);
4618 public Expression CreateTypeOfExpression ()
4620 return new TypeOfField (FieldInfo, loc);
4623 override public Expression DoResolve (EmitContext ec)
4625 return DoResolve (ec, false, false);
4628 Expression DoResolve (EmitContext ec, bool lvalue_instance, bool out_access)
4630 if (!FieldInfo.IsStatic){
4631 if (InstanceExpression == null){
4633 // This can happen when referencing an instance field using
4634 // a fully qualified type expression: TypeName.InstanceField = xxx
4636 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4640 // Resolve the field's instance expression while flow analysis is turned
4641 // off: when accessing a field "a.b", we must check whether the field
4642 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4644 if (lvalue_instance) {
4645 using (ec.With (EmitContext.Flags.DoFlowAnalysis, false)) {
4646 Expression right_side =
4647 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4648 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side, loc);
4651 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
4652 InstanceExpression = InstanceExpression.Resolve (ec, rf);
4655 if (InstanceExpression == null)
4658 using (ec.Set (EmitContext.Flags.OmitStructFlowAnalysis)) {
4659 InstanceExpression.CheckMarshalByRefAccess (ec);
4663 if (!in_initializer && !ec.IsInFieldInitializer) {
4664 ObsoleteAttribute oa;
4665 FieldBase f = TypeManager.GetField (FieldInfo);
4667 if (!ec.IsInObsoleteScope)
4668 f.CheckObsoleteness (loc);
4670 // To be sure that type is external because we do not register generated fields
4671 } else if (!(FieldInfo.DeclaringType is TypeBuilder)) {
4672 oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
4674 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
4678 AnonymousContainer am = ec.CurrentAnonymousMethod;
4680 if (!FieldInfo.IsStatic){
4681 if (!am.IsIterator && (ec.TypeContainer is Struct)){
4682 Report.Error (1673, loc,
4683 "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",
4690 IFixedBuffer fb = AttributeTester.GetFixedBuffer (FieldInfo);
4692 if (!ec.InFixedInitializer && ec.ContainerType.IsValueType) {
4693 Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4696 if (InstanceExpression.eclass != ExprClass.Variable) {
4697 Report.SymbolRelatedToPreviousError (FieldInfo);
4698 Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4699 TypeManager.GetFullNameSignature (FieldInfo));
4702 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4705 // If the instance expression is a local variable or parameter.
4706 IVariable var = InstanceExpression as IVariable;
4707 if ((var == null) || (var.VariableInfo == null))
4710 VariableInfo vi = var.VariableInfo;
4711 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
4714 variable_info = vi.GetSubStruct (FieldInfo.Name);
4718 static readonly int [] codes = {
4719 191, // instance, write access
4720 192, // instance, out access
4721 198, // static, write access
4722 199, // static, out access
4723 1648, // member of value instance, write access
4724 1649, // member of value instance, out access
4725 1650, // member of value static, write access
4726 1651 // member of value static, out access
4729 static readonly string [] msgs = {
4730 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4731 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4732 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4733 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4734 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4735 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4736 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4737 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4740 // The return value is always null. Returning a value simplifies calling code.
4741 Expression Report_AssignToReadonly (Expression right_side)
4744 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4748 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4750 Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4755 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4757 IVariable var = InstanceExpression as IVariable;
4758 if ((var != null) && (var.VariableInfo != null))
4759 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
4761 bool lvalue_instance = !FieldInfo.IsStatic && FieldInfo.DeclaringType.IsValueType;
4762 bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
4764 Expression e = DoResolve (ec, lvalue_instance, out_access);
4769 FieldBase fb = TypeManager.GetField (FieldInfo);
4773 if (FieldInfo.IsInitOnly) {
4774 // InitOnly fields can only be assigned in constructors or initializers
4775 if (!ec.IsInFieldInitializer && !ec.IsConstructor)
4776 return Report_AssignToReadonly (right_side);
4778 if (ec.IsConstructor) {
4779 Type ctype = ec.TypeContainer.CurrentType;
4781 ctype = ec.ContainerType;
4783 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4784 if (!TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
4785 return Report_AssignToReadonly (right_side);
4786 // static InitOnly fields cannot be assigned-to in an instance constructor
4787 if (IsStatic && !ec.IsStatic)
4788 return Report_AssignToReadonly (right_side);
4789 // instance constructors can't modify InitOnly fields of other instances of the same type
4790 if (!IsStatic && !(InstanceExpression is This))
4791 return Report_AssignToReadonly (right_side);
4795 if (right_side == EmptyExpression.OutAccess &&
4796 !IsStatic && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type)) {
4797 Report.SymbolRelatedToPreviousError (DeclaringType);
4798 Report.Warning (197, 1, loc,
4799 "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",
4800 GetSignatureForError ());
4806 bool is_marshal_by_ref ()
4808 return !IsStatic && Type.IsValueType && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type);
4811 public override void CheckMarshalByRefAccess (EmitContext ec)
4813 if (is_marshal_by_ref () && !(InstanceExpression is This)) {
4814 Report.SymbolRelatedToPreviousError (DeclaringType);
4815 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",
4816 GetSignatureForError ());
4820 public bool VerifyFixed ()
4822 IVariable variable = InstanceExpression as IVariable;
4823 // A variable of the form V.I is fixed when V is a fixed variable of a struct type.
4824 // We defer the InstanceExpression check after the variable check to avoid a
4825 // separate null check on InstanceExpression.
4826 return variable != null && InstanceExpression.Type.IsValueType && variable.VerifyFixed ();
4829 public override int GetHashCode ()
4831 return FieldInfo.GetHashCode ();
4834 public override bool Equals (object obj)
4836 FieldExpr fe = obj as FieldExpr;
4840 if (FieldInfo != fe.FieldInfo)
4843 if (InstanceExpression == null || fe.InstanceExpression == null)
4846 return InstanceExpression.Equals (fe.InstanceExpression);
4849 public void Emit (EmitContext ec, bool leave_copy)
4851 ILGenerator ig = ec.ig;
4852 bool is_volatile = false;
4854 FieldBase f = TypeManager.GetField (FieldInfo);
4856 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4859 f.SetMemberIsUsed ();
4862 if (FieldInfo.IsStatic){
4864 ig.Emit (OpCodes.Volatile);
4866 ig.Emit (OpCodes.Ldsfld, FieldInfo);
4869 EmitInstance (ec, false);
4871 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
4873 ig.Emit (OpCodes.Ldflda, FieldInfo);
4874 ig.Emit (OpCodes.Ldflda, ff.Element);
4877 ig.Emit (OpCodes.Volatile);
4879 ig.Emit (OpCodes.Ldfld, FieldInfo);
4884 ec.ig.Emit (OpCodes.Dup);
4885 if (!FieldInfo.IsStatic) {
4886 temp = new LocalTemporary (this.Type);
4892 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4894 FieldAttributes fa = FieldInfo.Attributes;
4895 bool is_static = (fa & FieldAttributes.Static) != 0;
4896 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
4897 ILGenerator ig = ec.ig;
4899 if (is_readonly && !ec.IsConstructor){
4900 Report_AssignToReadonly (source);
4905 // String concatenation creates a new string instance
4907 prepared = prepare_for_load && !(source is StringConcat);
4908 EmitInstance (ec, prepared);
4912 ec.ig.Emit (OpCodes.Dup);
4913 if (!FieldInfo.IsStatic) {
4914 temp = new LocalTemporary (this.Type);
4919 FieldBase f = TypeManager.GetField (FieldInfo);
4921 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4922 ig.Emit (OpCodes.Volatile);
4928 ig.Emit (OpCodes.Stsfld, FieldInfo);
4930 ig.Emit (OpCodes.Stfld, FieldInfo);
4938 public override void Emit (EmitContext ec)
4943 public override void EmitSideEffect (EmitContext ec)
4945 FieldBase f = TypeManager.GetField (FieldInfo);
4946 bool is_volatile = f != null && (f.ModFlags & Modifiers.VOLATILE) != 0;
4948 if (is_volatile || is_marshal_by_ref ())
4949 base.EmitSideEffect (ec);
4952 public void AddressOf (EmitContext ec, AddressOp mode)
4954 ILGenerator ig = ec.ig;
4956 FieldBase f = TypeManager.GetField (FieldInfo);
4958 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
4959 Report.Warning (420, 1, loc, "`{0}': A volatile field references will not be treated as volatile",
4960 f.GetSignatureForError ());
4963 if ((mode & AddressOp.Store) != 0)
4965 if ((mode & AddressOp.Load) != 0)
4966 f.SetMemberIsUsed ();
4970 // Handle initonly fields specially: make a copy and then
4971 // get the address of the copy.
4974 if (FieldInfo.IsInitOnly){
4976 if (ec.IsConstructor){
4977 if (FieldInfo.IsStatic){
4989 local = ig.DeclareLocal (type);
4990 ig.Emit (OpCodes.Stloc, local);
4991 ig.Emit (OpCodes.Ldloca, local);
4996 if (FieldInfo.IsStatic){
4997 ig.Emit (OpCodes.Ldsflda, FieldInfo);
5000 EmitInstance (ec, false);
5001 ig.Emit (OpCodes.Ldflda, FieldInfo);
5008 /// Expression that evaluates to a Property. The Assign class
5009 /// might set the `Value' expression if we are in an assignment.
5011 /// This is not an LValue because we need to re-write the expression, we
5012 /// can not take data from the stack and store it.
5014 public class PropertyExpr : MemberExpr, IAssignMethod {
5015 public readonly PropertyInfo PropertyInfo;
5016 MethodInfo getter, setter;
5021 LocalTemporary temp;
5024 public PropertyExpr (Type container_type, PropertyInfo pi, Location l)
5027 eclass = ExprClass.PropertyAccess;
5031 type = TypeManager.TypeToCoreType (pi.PropertyType);
5033 ResolveAccessors (container_type);
5036 public override string Name {
5038 return PropertyInfo.Name;
5042 public override bool IsInstance {
5048 public override bool IsStatic {
5054 public override Expression CreateExpressionTree (EmitContext ec)
5056 if (IsSingleDimensionalArrayLength ()) {
5057 ArrayList args = new ArrayList (1);
5058 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5059 return CreateExpressionFactoryCall ("ArrayLength", args);
5062 // TODO: it's waiting for PropertyExpr refactoring
5063 //ArrayList args = new ArrayList (2);
5064 //args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5065 //args.Add (getter expression);
5066 //return CreateExpressionFactoryCall ("Property", args);
5067 return base.CreateExpressionTree (ec);
5070 public Expression CreateSetterTypeOfExpression ()
5072 return new TypeOfMethodInfo (setter, loc);
5075 public override Type DeclaringType {
5077 return PropertyInfo.DeclaringType;
5081 public override string GetSignatureForError ()
5083 return TypeManager.GetFullNameSignature (PropertyInfo);
5086 void FindAccessors (Type invocation_type)
5088 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
5089 BindingFlags.Static | BindingFlags.Instance |
5090 BindingFlags.DeclaredOnly;
5092 Type current = PropertyInfo.DeclaringType;
5093 for (; current != null; current = current.BaseType) {
5094 MemberInfo[] group = TypeManager.MemberLookup (
5095 invocation_type, invocation_type, current,
5096 MemberTypes.Property, flags, PropertyInfo.Name, null);
5101 if (group.Length != 1)
5102 // Oooops, can this ever happen ?
5105 PropertyInfo pi = (PropertyInfo) group [0];
5108 getter = pi.GetGetMethod (true);
5111 setter = pi.GetSetMethod (true);
5113 MethodInfo accessor = getter != null ? getter : setter;
5115 if (!accessor.IsVirtual)
5121 // We also perform the permission checking here, as the PropertyInfo does not
5122 // hold the information for the accessibility of its setter/getter
5124 // TODO: Refactor to use some kind of cache together with GetPropertyFromAccessor
5125 void ResolveAccessors (Type container_type)
5127 FindAccessors (container_type);
5129 if (getter != null) {
5130 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
5131 IMethodData md = TypeManager.GetMethod (the_getter);
5133 md.SetMemberIsUsed ();
5135 is_static = getter.IsStatic;
5138 if (setter != null) {
5139 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
5140 IMethodData md = TypeManager.GetMethod (the_setter);
5142 md.SetMemberIsUsed ();
5144 is_static = setter.IsStatic;
5148 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
5151 InstanceExpression = null;
5155 if (InstanceExpression == null) {
5156 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5160 InstanceExpression = InstanceExpression.DoResolve (ec);
5161 if (lvalue_instance && InstanceExpression != null)
5162 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
5164 if (InstanceExpression == null)
5167 InstanceExpression.CheckMarshalByRefAccess (ec);
5169 if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) &&
5170 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
5171 !TypeManager.IsNestedChildOf (ec.ContainerType, InstanceExpression.Type) &&
5172 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.ContainerType)) {
5173 Report.SymbolRelatedToPreviousError (PropertyInfo);
5174 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
5181 void Error_PropertyNotFound (MethodInfo mi, bool getter)
5183 // TODO: correctly we should compare arguments but it will lead to bigger changes
5184 if (mi is MethodBuilder) {
5185 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
5189 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
5191 ParameterData iparams = TypeManager.GetParameterData (mi);
5192 sig.Append (getter ? "get_" : "set_");
5194 sig.Append (iparams.GetSignatureForError ());
5196 Report.SymbolRelatedToPreviousError (mi);
5197 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
5198 Name, sig.ToString ());
5201 public bool IsAccessibleFrom (Type invocation_type, bool lvalue)
5204 MethodInfo accessor = lvalue ? setter : getter;
5205 if (accessor == null && lvalue)
5207 return accessor != null && IsAccessorAccessible (invocation_type, accessor, out dummy);
5210 bool IsSingleDimensionalArrayLength ()
5212 if (DeclaringType != TypeManager.array_type || getter == null || Name != "Length")
5215 string t_name = InstanceExpression.Type.Name;
5216 int t_name_len = t_name.Length;
5217 return t_name_len > 2 && t_name [t_name_len - 2] == '[' && t_name [t_name_len - 3] != ']';
5220 override public Expression DoResolve (EmitContext ec)
5225 if (getter != null){
5226 if (TypeManager.GetParameterData (getter).Count != 0){
5227 Error_PropertyNotFound (getter, true);
5232 if (getter == null){
5234 // The following condition happens if the PropertyExpr was
5235 // created, but is invalid (ie, the property is inaccessible),
5236 // and we did not want to embed the knowledge about this in
5237 // the caller routine. This only avoids double error reporting.
5242 if (InstanceExpression != EmptyExpression.Null) {
5243 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5244 TypeManager.GetFullNameSignature (PropertyInfo));
5249 bool must_do_cs1540_check = false;
5250 if (getter != null &&
5251 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
5252 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
5253 if (pm != null && pm.HasCustomAccessModifier) {
5254 Report.SymbolRelatedToPreviousError (pm);
5255 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5256 TypeManager.CSharpSignature (getter));
5259 Report.SymbolRelatedToPreviousError (getter);
5260 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
5265 if (!InstanceResolve (ec, false, must_do_cs1540_check))
5269 // Only base will allow this invocation to happen.
5271 if (IsBase && getter.IsAbstract) {
5272 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5276 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
5286 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
5288 if (right_side == EmptyExpression.OutAccess) {
5289 if (ec.CurrentBlock.Toplevel.GetTransparentIdentifier (PropertyInfo.Name) != null) {
5290 Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5293 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as `ref' or `out' parameter",
5294 GetSignatureForError ());
5299 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5300 Error_CannotModifyIntermediateExpressionValue (ec);
5303 if (setter == null){
5305 // The following condition happens if the PropertyExpr was
5306 // created, but is invalid (ie, the property is inaccessible),
5307 // and we did not want to embed the knowledge about this in
5308 // the caller routine. This only avoids double error reporting.
5312 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
5313 GetSignatureForError ());
5317 if (TypeManager.GetParameterData (setter).Count != 1){
5318 Error_PropertyNotFound (setter, false);
5322 bool must_do_cs1540_check;
5323 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
5324 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
5325 if (pm != null && pm.HasCustomAccessModifier) {
5326 Report.SymbolRelatedToPreviousError (pm);
5327 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5328 TypeManager.CSharpSignature (setter));
5331 Report.SymbolRelatedToPreviousError (setter);
5332 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
5337 if (!InstanceResolve (ec, PropertyInfo.DeclaringType.IsValueType, must_do_cs1540_check))
5341 // Only base will allow this invocation to happen.
5343 if (IsBase && setter.IsAbstract){
5344 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5351 public override void Emit (EmitContext ec)
5356 public void Emit (EmitContext ec, bool leave_copy)
5359 // Special case: length of single dimension array property is turned into ldlen
5361 if (IsSingleDimensionalArrayLength ()) {
5363 EmitInstance (ec, false);
5364 ec.ig.Emit (OpCodes.Ldlen);
5365 ec.ig.Emit (OpCodes.Conv_I4);
5369 Invocation.EmitCall (ec, IsBase, InstanceExpression, getter, null, loc, prepared, false);
5372 ec.ig.Emit (OpCodes.Dup);
5374 temp = new LocalTemporary (this.Type);
5381 // Implements the IAssignMethod interface for assignments
5383 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5385 Expression my_source = source;
5387 if (prepare_for_load) {
5388 if (source is StringConcat)
5389 EmitInstance (ec, false);
5397 ec.ig.Emit (OpCodes.Dup);
5399 temp = new LocalTemporary (this.Type);
5403 } else if (leave_copy) {
5405 temp = new LocalTemporary (this.Type);
5410 ArrayList args = new ArrayList (1);
5411 args.Add (new Argument (my_source, Argument.AType.Expression));
5413 Invocation.EmitCall (ec, IsBase, InstanceExpression, setter, args, loc, false, prepared);
5423 /// Fully resolved expression that evaluates to an Event
5425 public class EventExpr : MemberExpr {
5426 public readonly EventInfo EventInfo;
5429 MethodInfo add_accessor, remove_accessor;
5431 public EventExpr (EventInfo ei, Location loc)
5435 eclass = ExprClass.EventAccess;
5437 add_accessor = TypeManager.GetAddMethod (ei);
5438 remove_accessor = TypeManager.GetRemoveMethod (ei);
5439 if (add_accessor.IsStatic || remove_accessor.IsStatic)
5442 if (EventInfo is MyEventBuilder){
5443 MyEventBuilder eb = (MyEventBuilder) EventInfo;
5444 type = eb.EventType;
5447 type = EventInfo.EventHandlerType;
5450 public override string Name {
5452 return EventInfo.Name;
5456 public override bool IsInstance {
5462 public override bool IsStatic {
5468 public override Type DeclaringType {
5470 return EventInfo.DeclaringType;
5474 void Error_AssignmentEventOnly ()
5476 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5477 GetSignatureForError ());
5480 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
5481 SimpleName original)
5484 // If the event is local to this class, we transform ourselves into a FieldExpr
5487 if (EventInfo.DeclaringType == ec.ContainerType ||
5488 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
5489 EventField mi = TypeManager.GetEventField (EventInfo);
5492 if (!ec.IsInObsoleteScope)
5493 mi.CheckObsoleteness (loc);
5495 if ((mi.ModFlags & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0 && !ec.IsInCompoundAssignment)
5496 Error_AssignmentEventOnly ();
5498 FieldExpr ml = new FieldExpr (mi.FieldBuilder, loc);
5500 InstanceExpression = null;
5502 return ml.ResolveMemberAccess (ec, left, loc, original);
5506 if (left is This && !ec.IsInCompoundAssignment)
5507 Error_AssignmentEventOnly ();
5509 return base.ResolveMemberAccess (ec, left, loc, original);
5513 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
5516 InstanceExpression = null;
5520 if (InstanceExpression == null) {
5521 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5525 InstanceExpression = InstanceExpression.DoResolve (ec);
5526 if (InstanceExpression == null)
5529 if (IsBase && add_accessor.IsAbstract) {
5530 Error_CannotCallAbstractBase(TypeManager.CSharpSignature(add_accessor));
5535 // This is using the same mechanism as the CS1540 check in PropertyExpr.
5536 // However, in the Event case, we reported a CS0122 instead.
5538 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
5539 InstanceExpression.Type != ec.ContainerType &&
5540 TypeManager.IsSubclassOf (ec.ContainerType, InstanceExpression.Type)) {
5541 Report.SymbolRelatedToPreviousError (EventInfo);
5542 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5549 public bool IsAccessibleFrom (Type invocation_type)
5552 return IsAccessorAccessible (invocation_type, add_accessor, out dummy) &&
5553 IsAccessorAccessible (invocation_type, remove_accessor, out dummy);
5556 public override Expression CreateExpressionTree (EmitContext ec)
5558 throw new NotSupportedException ();
5561 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5563 return DoResolve (ec);
5566 public override Expression DoResolve (EmitContext ec)
5568 bool must_do_cs1540_check;
5569 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
5570 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
5571 Report.SymbolRelatedToPreviousError (EventInfo);
5572 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5576 if (!InstanceResolve (ec, must_do_cs1540_check))
5582 public override void Emit (EmitContext ec)
5584 Report.Error (70, loc, "The event `{0}' can only appear on the left hand side of += or -= "+
5585 "(except on the defining type)", GetSignatureForError ());
5588 public override string GetSignatureForError ()
5590 return TypeManager.CSharpSignature (EventInfo);
5593 public void EmitAddOrRemove (EmitContext ec, Expression source)
5595 BinaryDelegate source_del = source as BinaryDelegate;
5596 if (source_del == null) {
5600 Expression handler = source_del.Right;
5602 Argument arg = new Argument (handler, Argument.AType.Expression);
5603 ArrayList args = new ArrayList ();
5607 if (source_del.IsAddition)
5608 Invocation.EmitCall (
5609 ec, IsBase, InstanceExpression, add_accessor, args, loc);
5611 Invocation.EmitCall (
5612 ec, IsBase, InstanceExpression, remove_accessor, args, loc);
5616 public class TemporaryVariable : Expression, IMemoryLocation
5621 public TemporaryVariable (Type type, Location loc)
5625 eclass = ExprClass.Value;
5628 public override Expression DoResolve (EmitContext ec)
5633 TypeExpr te = new TypeExpression (type, loc);
5634 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
5635 if (!li.Resolve (ec))
5638 if (ec.MustCaptureVariable (li)) {
5639 ScopeInfo scope = li.Block.CreateScopeInfo ();
5640 var = scope.AddLocal (li);
5647 public Variable Variable {
5648 get { return var != null ? var : li.Variable; }
5651 public override void Emit (EmitContext ec)
5653 Variable.EmitInstance (ec);
5657 public void EmitLoadAddress (EmitContext ec)
5659 Variable.EmitInstance (ec);
5660 Variable.EmitAddressOf (ec);
5663 public void Store (EmitContext ec, Expression right_side)
5665 Variable.EmitInstance (ec);
5666 right_side.Emit (ec);
5667 Variable.EmitAssign (ec);
5670 public void EmitThis (EmitContext ec)
5672 Variable.EmitInstance (ec);
5675 public void EmitStore (EmitContext ec)
5677 Variable.EmitAssign (ec);
5680 public void AddressOf (EmitContext ec, AddressOp mode)
5682 EmitLoadAddress (ec);
5687 /// Handles `var' contextual keyword; var becomes a keyword only
5688 /// if no type called var exists in a variable scope
5690 public class VarExpr : SimpleName
5692 // Used for error reporting only
5693 ArrayList initializer;
5695 public VarExpr (Location loc)
5700 public ArrayList VariableInitializer {
5702 this.initializer = value;
5706 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5709 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
5711 type = right_side.Type;
5712 if (type == TypeManager.null_type || type == TypeManager.void_type || type == TypeManager.anonymous_method_type) {
5713 Report.Error (815, loc, "An implicitly typed local variable declaration cannot be initialized with `{0}'",
5714 right_side.GetSignatureForError ());
5718 eclass = ExprClass.Variable;
5722 protected override void Error_TypeOrNamespaceNotFound (IResolveContext ec)
5724 Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");
5727 public override TypeExpr ResolveAsContextualType (IResolveContext rc, bool silent)
5729 TypeExpr te = base.ResolveAsContextualType (rc, true);
5733 if (initializer == null)
5736 if (initializer.Count > 1) {
5737 Location loc = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [1]).Location;
5738 Report.Error (819, loc, "An implicitly typed local variable declaration cannot include multiple declarators");
5743 Expression variable_initializer = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [0]).expression_or_array_initializer;
5744 if (variable_initializer == null) {
5745 Report.Error (818, loc, "An implicitly typed local variable declarator must include an initializer");