2 // ecore.cs: Core of the Expression representation for the intermediate tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@seznam.cz)
8 // (C) 2001, 2002, 2003 Ximian, Inc.
12 namespace Mono.CSharp {
14 using System.Collections;
15 using System.Diagnostics;
16 using System.Reflection;
17 using System.Reflection.Emit;
21 /// The ExprClass class contains the is used to pass the
22 /// classification of an expression (value, variable, namespace,
23 /// type, method group, property access, event access, indexer access,
26 public enum ExprClass : byte {
41 /// This is used to tell Resolve in which types of expressions we're
45 public enum ResolveFlags {
46 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
49 // Returns a type expression.
52 // Returns a method group.
55 // Mask of all the expression class flags.
58 // Disable control flow analysis while resolving the expression.
59 // This is used when resolving the instance expression of a field expression.
60 DisableFlowAnalysis = 8,
62 // Set if this is resolving the first part of a MemberAccess.
65 // Disable control flow analysis _of struct_ while resolving the expression.
66 // This is used when resolving the instance expression of a field expression.
67 DisableStructFlowAnalysis = 32,
72 // This is just as a hint to AddressOf of what will be done with the
75 public enum AddressOp {
82 /// This interface is implemented by variables
84 public interface IMemoryLocation {
86 /// The AddressOf method should generate code that loads
87 /// the address of the object and leaves it on the stack.
89 /// The `mode' argument is used to notify the expression
90 /// of whether this will be used to read from the address or
91 /// write to the address.
93 /// This is just a hint that can be used to provide good error
94 /// reporting, and should have no other side effects.
96 void AddressOf (EmitContext ec, AddressOp mode);
100 /// This interface is implemented by variables
102 public interface IVariable {
103 VariableInfo VariableInfo {
111 /// Base class for expressions
113 public abstract class Expression {
114 public ExprClass eclass;
116 protected Location loc;
120 set { type = value; }
123 public virtual Location Location {
128 /// Utility wrapper routine for Error, just to beautify the code
130 public void Error (int error, string s)
132 Report.Error (error, loc, s);
135 // Not nice but we have broken hierarchy.
136 public virtual void CheckMarshalByRefAccess (EmitContext ec)
140 public virtual bool GetAttributableValue (Type value_type, out object value)
142 Attribute.Error_AttributeArgumentNotValid (loc);
147 public virtual string GetSignatureForError ()
149 return TypeManager.CSharpName (type);
152 public static bool IsAccessorAccessible (Type invocation_type, MethodInfo mi, out bool must_do_cs1540_check)
154 MethodAttributes ma = mi.Attributes & MethodAttributes.MemberAccessMask;
156 must_do_cs1540_check = false; // by default we do not check for this
158 if (ma == MethodAttributes.Public)
162 // If only accessible to the current class or children
164 if (ma == MethodAttributes.Private)
165 return TypeManager.IsPrivateAccessible (invocation_type, mi.DeclaringType) ||
166 TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType);
168 if (mi.DeclaringType.Assembly == invocation_type.Assembly ||
169 TypeManager.IsFriendAssembly (mi.DeclaringType.Assembly)) {
170 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamORAssem)
173 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamANDAssem)
177 // Family and FamANDAssem require that we derive.
178 // FamORAssem requires that we derive if in different assemblies.
179 if (!TypeManager.IsNestedFamilyAccessible (invocation_type, mi.DeclaringType))
182 if (!TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType))
183 must_do_cs1540_check = true;
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 ec, bool silent)
238 // C# 3.0 introduced contextual keywords (var) which behaves like a type if type with
239 // same name exists or as a keyword when no type was found
241 public virtual TypeExpr ResolveAsContextualType (IResolveContext rc, bool silent)
243 return ResolveAsTypeTerminal (rc, silent);
247 // This is used to resolve the expression as a type, a null
248 // value will be returned if the expression is not a type
251 public virtual TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
253 TypeExpr te = ResolveAsBaseTerminal (ec, silent);
257 if (!silent) { // && !(te is TypeParameterExpr)) {
258 ObsoleteAttribute obsolete_attr = AttributeTester.GetObsoleteAttribute (te.Type);
259 if (obsolete_attr != null && !ec.IsInObsoleteScope) {
260 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location);
264 // Constrains don't need to be checked for overrides
265 GenericMethod gm = ec.GenericDeclContainer as GenericMethod;
266 if (gm != null && (gm.ModFlags & Modifiers.OVERRIDE) != 0) {
271 ConstructedType ct = te as ConstructedType;
272 if ((ct != null) && !ct.CheckConstraints (ec))
278 public TypeExpr ResolveAsBaseTerminal (IResolveContext ec, bool silent)
280 int errors = Report.Errors;
282 FullNamedExpression fne = ResolveAsTypeStep (ec, silent);
287 if (fne.eclass != ExprClass.Type) {
288 if (!silent && errors == Report.Errors)
289 fne.Error_UnexpectedKind (null, "type", loc);
293 TypeExpr te = fne as TypeExpr;
295 if (!te.CheckAccessLevel (ec.DeclContainer)) {
296 Report.SymbolRelatedToPreviousError (te.Type);
297 ErrorIsInaccesible (loc, TypeManager.CSharpName (te.Type));
305 public static void ErrorIsInaccesible (Location loc, string name)
307 Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", name);
310 protected static void Error_CannotAccessProtected (Location loc, MemberInfo m, Type qualifier, Type container)
312 Report.Error (1540, loc, "Cannot access protected member `{0}' via a qualifier of type `{1}'."
313 + " The qualifier must be of type `{2}' or derived from it",
314 TypeManager.GetFullNameSignature (m),
315 TypeManager.CSharpName (qualifier),
316 TypeManager.CSharpName (container));
320 public static void Error_InvalidExpressionStatement (Location loc)
322 Report.Error (201, loc, "Only assignment, call, increment, decrement, and new object " +
323 "expressions can be used as a statement");
326 public void Error_InvalidExpressionStatement ()
328 Error_InvalidExpressionStatement (loc);
331 protected void Error_CannotAssign (string to, string roContext)
333 Report.Error (1656, loc, "Cannot assign to `{0}' because it is a `{1}'",
337 public static void Error_VoidInvalidInTheContext (Location loc)
339 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
342 public virtual void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl)
344 // The error was already reported as CS1660
345 if (type == TypeManager.anonymous_method_type)
348 if (TypeManager.IsGenericParameter (Type) && TypeManager.IsGenericParameter (target) && type.Name == target.Name) {
350 string sig1 = Type.DeclaringMethod == null ?
351 TypeManager.CSharpName (Type.DeclaringType) :
352 TypeManager.CSharpSignature (Type.DeclaringMethod);
353 string sig2 = target.DeclaringMethod == null ?
354 TypeManager.CSharpName (target.DeclaringType) :
355 TypeManager.CSharpSignature (target.DeclaringMethod);
356 Report.ExtraInformation (loc,
358 "The generic parameter `{0}' of `{1}' cannot be converted to the generic parameter `{0}' of `{2}' (in the previous ",
359 Type.Name, sig1, sig2));
361 } else if (Type.FullName == target.FullName){
362 Report.ExtraInformation (loc,
364 "The type `{0}' has two conflicting definitions, one comes from `{1}' and the other from `{2}' (in the previous ",
365 Type.FullName, Type.Assembly.FullName, target.Assembly.FullName));
369 Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
370 TypeManager.CSharpName (type), TypeManager.CSharpName (target));
374 Expression e = (this is EnumConstant) ? ((EnumConstant)this).Child : this;
375 bool b = Convert.ExplicitNumericConversion (e, target) != null;
378 Convert.ExplicitReferenceConversionExists (Type, target) ||
379 Convert.ExplicitUnsafe (e, target) != null ||
380 (ec != null && Convert.UserDefinedConversion (ec, this, target, Location.Null, true) != null))
382 Report.Error (266, loc, "Cannot implicitly convert type `{0}' to `{1}'. " +
383 "An explicit conversion exists (are you missing a cast?)",
384 TypeManager.CSharpName (Type), TypeManager.CSharpName (target));
388 if (Type != TypeManager.string_type && this is Constant && !(this is EmptyConstantCast)) {
389 Report.Error (31, loc, "Constant value `{0}' cannot be converted to a `{1}'",
390 ((Constant)(this)).GetValue ().ToString (), TypeManager.CSharpName (target));
394 Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
395 TypeManager.CSharpName (type),
396 TypeManager.CSharpName (target));
399 protected void Error_VariableIsUsedBeforeItIsDeclared (string name)
401 Report.Error (841, loc, "The variable `{0}' cannot be used before it is declared",
405 protected virtual void Error_TypeDoesNotContainDefinition (Type type, string name)
407 Error_TypeDoesNotContainDefinition (loc, type, name);
410 public static void Error_TypeDoesNotContainDefinition (Location loc, Type type, string name)
412 Report.SymbolRelatedToPreviousError (type);
413 Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
414 TypeManager.CSharpName (type), name);
417 protected static void Error_ValueAssignment (Location loc)
419 Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
422 ResolveFlags ExprClassToResolveFlags
427 case ExprClass.Namespace:
428 return ResolveFlags.Type;
430 case ExprClass.MethodGroup:
431 return ResolveFlags.MethodGroup;
433 case ExprClass.Value:
434 case ExprClass.Variable:
435 case ExprClass.PropertyAccess:
436 case ExprClass.EventAccess:
437 case ExprClass.IndexerAccess:
438 return ResolveFlags.VariableOrValue;
441 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
447 /// Resolves an expression and performs semantic analysis on it.
451 /// Currently Resolve wraps DoResolve to perform sanity
452 /// checking and assertion checking on what we expect from Resolve.
454 public Expression Resolve (EmitContext ec, ResolveFlags flags)
456 if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type)
457 return ResolveAsTypeStep (ec, false);
459 bool do_flow_analysis = ec.DoFlowAnalysis;
460 bool omit_struct_analysis = ec.OmitStructFlowAnalysis;
461 if ((flags & ResolveFlags.DisableFlowAnalysis) != 0)
462 do_flow_analysis = false;
463 if ((flags & ResolveFlags.DisableStructFlowAnalysis) != 0)
464 omit_struct_analysis = true;
467 using (ec.WithFlowAnalysis (do_flow_analysis, omit_struct_analysis)) {
468 if (this is SimpleName) {
469 bool intermediate = (flags & ResolveFlags.Intermediate) == ResolveFlags.Intermediate;
470 e = ((SimpleName) this).DoResolve (ec, intermediate);
479 if ((flags & e.ExprClassToResolveFlags) == 0) {
480 e.Error_UnexpectedKind (flags, loc);
484 if (e.type == null && !(e is Namespace)) {
485 throw new Exception (
486 "Expression " + e.GetType () +
487 " did not set its type after Resolve\n" +
488 "called from: " + this.GetType ());
495 /// Resolves an expression and performs semantic analysis on it.
497 public Expression Resolve (EmitContext ec)
499 Expression e = Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
501 if (e != null && e.eclass == ExprClass.MethodGroup && RootContext.Version == LanguageVersion.ISO_1) {
502 ((MethodGroupExpr) e).ReportUsageError ();
508 public Constant ResolveAsConstant (EmitContext ec, MemberCore mc)
510 Expression e = Resolve (ec);
514 Constant c = e as Constant;
518 Const.Error_ExpressionMustBeConstant (loc, mc.GetSignatureForError ());
523 /// Resolves an expression for LValue assignment
527 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
528 /// checking and assertion checking on what we expect from Resolve
530 public Expression ResolveLValue (EmitContext ec, Expression right_side, Location loc)
532 int errors = Report.Errors;
533 bool out_access = right_side == EmptyExpression.OutAccess;
535 Expression e = DoResolveLValue (ec, right_side);
537 if (e != null && out_access && !(e is IMemoryLocation)) {
538 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
539 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
541 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
542 // e.GetType () + " " + e.GetSignatureForError ());
547 if (errors == Report.Errors) {
549 Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
551 Error_ValueAssignment (loc);
556 if (e.eclass == ExprClass.Invalid)
557 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
559 if (e.eclass == ExprClass.MethodGroup) {
560 ((MethodGroupExpr) e).ReportUsageError ();
564 if ((e.type == null) && !(e is ConstructedType))
565 throw new Exception ("Expression " + e + " did not set its type after Resolve");
571 /// Emits the code for the expression
575 /// The Emit method is invoked to generate the code
576 /// for the expression.
578 public abstract void Emit (EmitContext ec);
580 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
583 ec.ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
587 /// Protected constructor. Only derivate types should
588 /// be able to be created
591 protected Expression ()
593 eclass = ExprClass.Invalid;
598 /// Returns a fully formed expression after a MemberLookup
601 public static Expression ExprClassFromMemberInfo (Type container_type, MemberInfo mi, Location loc)
604 return new EventExpr ((EventInfo) mi, loc);
605 else if (mi is FieldInfo) {
606 FieldInfo fi = (FieldInfo) mi;
607 if (fi.IsLiteral || (fi.IsInitOnly && fi.FieldType == TypeManager.decimal_type))
608 return new ConstantExpr (fi, loc);
609 return new FieldExpr (fi, loc);
610 } else if (mi is PropertyInfo)
611 return new PropertyExpr (container_type, (PropertyInfo) mi, loc);
612 else if (mi is Type) {
613 return new TypeExpression ((System.Type) mi, loc);
619 protected static ArrayList almost_matched_members = new ArrayList (4);
622 // FIXME: Probably implement a cache for (t,name,current_access_set)?
624 // This code could use some optimizations, but we need to do some
625 // measurements. For example, we could use a delegate to `flag' when
626 // something can not any longer be a method-group (because it is something
630 // If the return value is an Array, then it is an array of
633 // If the return value is an MemberInfo, it is anything, but a Method
637 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
638 // the arguments here and have MemberLookup return only the methods that
639 // match the argument count/type, unlike we are doing now (we delay this
642 // This is so we can catch correctly attempts to invoke instance methods
643 // from a static body (scan for error 120 in ResolveSimpleName).
646 // FIXME: Potential optimization, have a static ArrayList
649 public static Expression MemberLookup (Type container_type, Type queried_type, string name,
650 MemberTypes mt, BindingFlags bf, Location loc)
652 return MemberLookup (container_type, null, queried_type, name, mt, bf, loc);
656 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
657 // `qualifier_type' or null to lookup members in the current class.
660 public static Expression MemberLookup (Type container_type,
661 Type qualifier_type, Type queried_type,
662 string name, MemberTypes mt,
663 BindingFlags bf, Location loc)
665 almost_matched_members.Clear ();
667 MemberInfo [] mi = TypeManager.MemberLookup (container_type, qualifier_type,
668 queried_type, mt, bf, name, almost_matched_members);
674 bool is_interface = qualifier_type != null && qualifier_type.IsInterface;
675 ArrayList methods = new ArrayList (2);
676 ArrayList non_methods = null;
678 foreach (MemberInfo m in mi) {
679 if (m is MethodBase) {
684 if (non_methods == null) {
685 non_methods = new ArrayList (2);
690 foreach (MemberInfo n_m in non_methods) {
691 if (m.DeclaringType.IsInterface && TypeManager.ImplementsInterface (m.DeclaringType, n_m.DeclaringType))
694 Report.SymbolRelatedToPreviousError (m);
695 Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
696 TypeManager.GetFullNameSignature (m), TypeManager.GetFullNameSignature (n_m));
701 if (methods.Count == 0)
702 return ExprClassFromMemberInfo (container_type, (MemberInfo)non_methods [0], loc);
704 if (non_methods != null) {
705 MethodBase method = (MethodBase) methods [0];
706 MemberInfo non_method = (MemberInfo) non_methods [0];
707 if (method.DeclaringType == non_method.DeclaringType) {
708 // Cannot happen with C# code, but is valid in IL
709 Report.SymbolRelatedToPreviousError (method);
710 Report.SymbolRelatedToPreviousError (non_method);
711 Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
712 TypeManager.GetFullNameSignature (non_method),
713 TypeManager.CSharpSignature (method));
718 Report.SymbolRelatedToPreviousError (method);
719 Report.SymbolRelatedToPreviousError (non_method);
720 Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and non-method `{1}'. Using method `{0}'",
721 TypeManager.CSharpSignature (method), TypeManager.GetFullNameSignature (non_method));
725 return new MethodGroupExpr (methods, queried_type, loc);
728 if (mi [0] is MethodBase)
729 return new MethodGroupExpr (mi, queried_type, loc);
731 return ExprClassFromMemberInfo (container_type, mi [0], loc);
734 public const MemberTypes AllMemberTypes =
735 MemberTypes.Constructor |
739 MemberTypes.NestedType |
740 MemberTypes.Property;
742 public const BindingFlags AllBindingFlags =
743 BindingFlags.Public |
744 BindingFlags.Static |
745 BindingFlags.Instance;
747 public static Expression MemberLookup (Type container_type, Type queried_type,
748 string name, Location loc)
750 return MemberLookup (container_type, null, queried_type, name,
751 AllMemberTypes, AllBindingFlags, loc);
754 public static Expression MemberLookup (Type container_type, Type qualifier_type,
755 Type queried_type, string name, Location loc)
757 return MemberLookup (container_type, qualifier_type, queried_type,
758 name, AllMemberTypes, AllBindingFlags, loc);
761 public static MethodGroupExpr MethodLookup (Type container_type, Type queried_type,
762 string name, Location loc)
764 return (MethodGroupExpr)MemberLookup (container_type, null, queried_type, name,
765 MemberTypes.Method, AllBindingFlags, loc);
769 /// This is a wrapper for MemberLookup that is not used to "probe", but
770 /// to find a final definition. If the final definition is not found, we
771 /// look for private members and display a useful debugging message if we
774 protected Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
775 Type queried_type, string name,
776 MemberTypes mt, BindingFlags bf,
781 int errors = Report.Errors;
783 e = MemberLookup (ec.ContainerType, qualifier_type, queried_type, name, mt, bf, loc);
785 if (e != null || errors != Report.Errors)
788 // No errors were reported by MemberLookup, but there was an error.
789 return Error_MemberLookupFailed (ec.ContainerType, qualifier_type, queried_type,
793 protected virtual Expression Error_MemberLookupFailed (Type container_type, Type qualifier_type,
794 Type queried_type, string name, string class_name,
795 MemberTypes mt, BindingFlags bf)
797 if (almost_matched_members.Count != 0) {
798 for (int i = 0; i < almost_matched_members.Count; ++i) {
799 MemberInfo m = (MemberInfo) almost_matched_members [i];
800 for (int j = 0; j < i; ++j) {
801 if (m == almost_matched_members [j]) {
809 Type declaring_type = m.DeclaringType;
811 Report.SymbolRelatedToPreviousError (m);
812 if (qualifier_type == null) {
813 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
814 TypeManager.CSharpName (m.DeclaringType),
815 TypeManager.CSharpName (container_type));
817 } else if (qualifier_type != container_type &&
818 TypeManager.IsNestedFamilyAccessible (container_type, declaring_type)) {
819 // Although a derived class can access protected members of
820 // its base class it cannot do so through an instance of the
821 // base class (CS1540). If the qualifier_type is a base of the
822 // ec.ContainerType and the lookup succeeds with the latter one,
823 // then we are in this situation.
824 Error_CannotAccessProtected (loc, m, qualifier_type, container_type);
826 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (m));
829 almost_matched_members.Clear ();
833 MemberInfo[] lookup = null;
834 if (queried_type == null) {
835 class_name = "global::";
837 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
838 mt, (bf & ~BindingFlags.Public) | BindingFlags.NonPublic,
841 if (lookup != null) {
842 Report.SymbolRelatedToPreviousError (lookup [0]);
843 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (lookup [0]));
844 return Error_MemberLookupFailed (lookup);
847 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
848 AllMemberTypes, AllBindingFlags | BindingFlags.NonPublic,
852 if (lookup == null) {
853 if (class_name != null) {
854 Report.Error (103, loc, "The name `{0}' does not exist in the current context",
857 Error_TypeDoesNotContainDefinition (queried_type, name);
862 if (TypeManager.MemberLookup (queried_type, null, queried_type,
863 AllMemberTypes, AllBindingFlags |
864 BindingFlags.NonPublic, name, null) == null) {
865 if ((lookup.Length == 1) && (lookup [0] is Type)) {
866 Type t = (Type) lookup [0];
868 Report.Error (305, loc,
869 "Using the generic type `{0}' " +
870 "requires {1} type arguments",
871 TypeManager.CSharpName (t),
872 TypeManager.GetNumberOfTypeArguments (t).ToString ());
877 return Error_MemberLookupFailed (lookup);
880 protected virtual Expression Error_MemberLookupFailed (MemberInfo[] members)
882 for (int i = 0; i < members.Length; ++i) {
883 if (!(members [i] is MethodBase))
887 // By default propagate the closest candidates upwards
888 return new MethodGroupExpr (members, type, loc);
892 /// Returns an expression that can be used to invoke operator true
893 /// on the expression if it exists.
895 static public Expression GetOperatorTrue (EmitContext ec, Expression e, Location loc)
897 return GetOperatorTrueOrFalse (ec, e, true, loc);
901 /// Returns an expression that can be used to invoke operator false
902 /// on the expression if it exists.
904 static public Expression GetOperatorFalse (EmitContext ec, Expression e, Location loc)
906 return GetOperatorTrueOrFalse (ec, e, false, loc);
909 static Expression GetOperatorTrueOrFalse (EmitContext ec, Expression e, bool is_true, Location loc)
911 MethodGroupExpr operator_group;
914 if (TypeManager.IsNullableType (e.Type))
915 return new Nullable.OperatorTrueOrFalse (e, is_true, loc).Resolve (ec);
918 operator_group = MethodLookup (ec.ContainerType, e.Type, is_true ? "op_True" : "op_False", loc) as MethodGroupExpr;
919 if (operator_group == null)
922 ArrayList arguments = new ArrayList (1);
923 arguments.Add (new Argument (e, Argument.AType.Expression));
924 operator_group = operator_group.OverloadResolve (
925 ec, arguments, false, loc);
927 if (operator_group == null)
930 return new StaticCallExpr ((MethodInfo) operator_group, arguments, loc);
934 /// Resolves the expression `e' into a boolean expression: either through
935 /// an implicit conversion, or through an `operator true' invocation
937 public static Expression ResolveBoolean (EmitContext ec, Expression e, Location loc)
943 if (e.Type == TypeManager.bool_type)
946 Expression converted = Convert.ImplicitConversion (ec, e, TypeManager.bool_type, Location.Null);
948 if (converted != null)
952 // If no implicit conversion to bool exists, try using `operator true'
954 converted = Expression.GetOperatorTrue (ec, e, loc);
955 if (converted == null){
956 e.Error_ValueCannotBeConverted (ec, loc, TypeManager.bool_type, false);
962 public virtual string ExprClassName
966 case ExprClass.Invalid:
968 case ExprClass.Value:
970 case ExprClass.Variable:
972 case ExprClass.Namespace:
976 case ExprClass.MethodGroup:
977 return "method group";
978 case ExprClass.PropertyAccess:
979 return "property access";
980 case ExprClass.EventAccess:
981 return "event access";
982 case ExprClass.IndexerAccess:
983 return "indexer access";
984 case ExprClass.Nothing:
987 throw new Exception ("Should not happen");
992 /// Reports that we were expecting `expr' to be of class `expected'
994 public void Error_UnexpectedKind (DeclSpace ds, string expected, Location loc)
996 Error_UnexpectedKind (ds, expected, ExprClassName, loc);
999 public void Error_UnexpectedKind (DeclSpace ds, string expected, string was, Location loc)
1001 string name = GetSignatureForError ();
1003 name = ds.GetSignatureForError () + '.' + name;
1005 Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
1006 name, was, expected);
1009 public void Error_UnexpectedKind (ResolveFlags flags, Location loc)
1011 string [] valid = new string [4];
1014 if ((flags & ResolveFlags.VariableOrValue) != 0) {
1015 valid [count++] = "variable";
1016 valid [count++] = "value";
1019 if ((flags & ResolveFlags.Type) != 0)
1020 valid [count++] = "type";
1022 if ((flags & ResolveFlags.MethodGroup) != 0)
1023 valid [count++] = "method group";
1026 valid [count++] = "unknown";
1028 StringBuilder sb = new StringBuilder (valid [0]);
1029 for (int i = 1; i < count - 1; i++) {
1031 sb.Append (valid [i]);
1034 sb.Append ("' or `");
1035 sb.Append (valid [count - 1]);
1038 Report.Error (119, loc,
1039 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1042 public static void UnsafeError (Location loc)
1044 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1048 // Load the object from the pointer.
1050 public static void LoadFromPtr (ILGenerator ig, Type t)
1052 if (t == TypeManager.int32_type)
1053 ig.Emit (OpCodes.Ldind_I4);
1054 else if (t == TypeManager.uint32_type)
1055 ig.Emit (OpCodes.Ldind_U4);
1056 else if (t == TypeManager.short_type)
1057 ig.Emit (OpCodes.Ldind_I2);
1058 else if (t == TypeManager.ushort_type)
1059 ig.Emit (OpCodes.Ldind_U2);
1060 else if (t == TypeManager.char_type)
1061 ig.Emit (OpCodes.Ldind_U2);
1062 else if (t == TypeManager.byte_type)
1063 ig.Emit (OpCodes.Ldind_U1);
1064 else if (t == TypeManager.sbyte_type)
1065 ig.Emit (OpCodes.Ldind_I1);
1066 else if (t == TypeManager.uint64_type)
1067 ig.Emit (OpCodes.Ldind_I8);
1068 else if (t == TypeManager.int64_type)
1069 ig.Emit (OpCodes.Ldind_I8);
1070 else if (t == TypeManager.float_type)
1071 ig.Emit (OpCodes.Ldind_R4);
1072 else if (t == TypeManager.double_type)
1073 ig.Emit (OpCodes.Ldind_R8);
1074 else if (t == TypeManager.bool_type)
1075 ig.Emit (OpCodes.Ldind_I1);
1076 else if (t == TypeManager.intptr_type)
1077 ig.Emit (OpCodes.Ldind_I);
1078 else if (TypeManager.IsEnumType (t)) {
1079 if (t == TypeManager.enum_type)
1080 ig.Emit (OpCodes.Ldind_Ref);
1082 LoadFromPtr (ig, TypeManager.EnumToUnderlying (t));
1083 } else if (t.IsValueType || TypeManager.IsGenericParameter (t))
1084 ig.Emit (OpCodes.Ldobj, t);
1085 else if (t.IsPointer)
1086 ig.Emit (OpCodes.Ldind_I);
1088 ig.Emit (OpCodes.Ldind_Ref);
1092 // The stack contains the pointer and the value of type `type'
1094 public static void StoreFromPtr (ILGenerator ig, Type type)
1096 if (TypeManager.IsEnumType (type))
1097 type = TypeManager.EnumToUnderlying (type);
1098 if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
1099 ig.Emit (OpCodes.Stind_I4);
1100 else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
1101 ig.Emit (OpCodes.Stind_I8);
1102 else if (type == TypeManager.char_type || type == TypeManager.short_type ||
1103 type == TypeManager.ushort_type)
1104 ig.Emit (OpCodes.Stind_I2);
1105 else if (type == TypeManager.float_type)
1106 ig.Emit (OpCodes.Stind_R4);
1107 else if (type == TypeManager.double_type)
1108 ig.Emit (OpCodes.Stind_R8);
1109 else if (type == TypeManager.byte_type || type == TypeManager.sbyte_type ||
1110 type == TypeManager.bool_type)
1111 ig.Emit (OpCodes.Stind_I1);
1112 else if (type == TypeManager.intptr_type)
1113 ig.Emit (OpCodes.Stind_I);
1114 else if (type.IsValueType || TypeManager.IsGenericParameter (type))
1115 ig.Emit (OpCodes.Stobj, type);
1117 ig.Emit (OpCodes.Stind_Ref);
1121 // Returns the size of type `t' if known, otherwise, 0
1123 public static int GetTypeSize (Type t)
1125 t = TypeManager.TypeToCoreType (t);
1126 if (t == TypeManager.int32_type ||
1127 t == TypeManager.uint32_type ||
1128 t == TypeManager.float_type)
1130 else if (t == TypeManager.int64_type ||
1131 t == TypeManager.uint64_type ||
1132 t == TypeManager.double_type)
1134 else if (t == TypeManager.byte_type ||
1135 t == TypeManager.sbyte_type ||
1136 t == TypeManager.bool_type)
1138 else if (t == TypeManager.short_type ||
1139 t == TypeManager.char_type ||
1140 t == TypeManager.ushort_type)
1142 else if (t == TypeManager.decimal_type)
1148 public static void Error_NegativeArrayIndex (Location loc)
1150 Report.Error (248, loc, "Cannot create an array with a negative size");
1153 protected void Error_CannotCallAbstractBase (string name)
1155 Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
1158 protected void Error_CannotModifyIntermediateExpressionValue (EmitContext ec)
1160 Report.SymbolRelatedToPreviousError (type);
1161 if (ec.CurrentInitializerVariable != null) {
1162 Report.Error (1918, loc, "Members of a value type property `{0}' cannot be assigned with an object initializer",
1163 GetSignatureForError ());
1165 Report.Error (1612, loc, "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
1166 GetSignatureForError ());
1171 // Converts `source' to an int, uint, long or ulong.
1173 public Expression ExpressionToArrayArgument (EmitContext ec, Expression source, Location loc)
1177 using (ec.With (EmitContext.Flags.CheckState, true)) {
1178 target = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, loc);
1180 target = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, loc);
1182 target = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, loc);
1184 target = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, loc);
1186 if (target == null) {
1187 source.Error_ValueCannotBeConverted (ec, loc, TypeManager.int32_type, false);
1193 // Only positive constants are allowed at compile time
1195 if (target is Constant){
1196 if (target is IntConstant){
1197 if (((IntConstant) target).Value < 0){
1198 Error_NegativeArrayIndex (loc);
1203 if (target is LongConstant){
1204 if (((LongConstant) target).Value < 0){
1205 Error_NegativeArrayIndex (loc);
1216 // Derived classes implement this method by cloning the fields that
1217 // could become altered during the Resolve stage
1219 // Only expressions that are created for the parser need to implement
1222 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1224 throw new NotImplementedException (
1226 "CloneTo not implemented for expression {0}", this.GetType ()));
1230 // Clones an expression created by the parser.
1232 // We only support expressions created by the parser so far, not
1233 // expressions that have been resolved (many more classes would need
1234 // to implement CloneTo).
1236 // This infrastructure is here merely for Lambda expressions which
1237 // compile the same code using different type values for the same
1238 // arguments to find the correct overload
1240 public Expression Clone (CloneContext clonectx)
1242 Expression cloned = (Expression) MemberwiseClone ();
1243 CloneTo (clonectx, cloned);
1250 /// This is just a base class for expressions that can
1251 /// appear on statements (invocations, object creation,
1252 /// assignments, post/pre increment and decrement). The idea
1253 /// being that they would support an extra Emition interface that
1254 /// does not leave a result on the stack.
1256 public abstract class ExpressionStatement : Expression {
1258 public virtual ExpressionStatement ResolveStatement (EmitContext ec)
1260 Expression e = Resolve (ec);
1264 ExpressionStatement es = e as ExpressionStatement;
1266 Error_InvalidExpressionStatement ();
1272 /// Requests the expression to be emitted in a `statement'
1273 /// context. This means that no new value is left on the
1274 /// stack after invoking this method (constrasted with
1275 /// Emit that will always leave a value on the stack).
1277 public abstract void EmitStatement (EmitContext ec);
1281 /// This kind of cast is used to encapsulate the child
1282 /// whose type is child.Type into an expression that is
1283 /// reported to return "return_type". This is used to encapsulate
1284 /// expressions which have compatible types, but need to be dealt
1285 /// at higher levels with.
1287 /// For example, a "byte" expression could be encapsulated in one
1288 /// of these as an "unsigned int". The type for the expression
1289 /// would be "unsigned int".
1292 public class EmptyCast : Expression
1294 protected Expression child;
1296 protected EmptyCast (Expression child, Type return_type)
1298 eclass = child.eclass;
1299 loc = child.Location;
1304 public static Expression Create (Expression child, Type type)
1306 Constant c = child as Constant;
1308 return new EmptyConstantCast (c, type);
1310 return new EmptyCast (child, type);
1313 public override Expression DoResolve (EmitContext ec)
1315 // This should never be invoked, we are born in fully
1316 // initialized state.
1321 public override void Emit (EmitContext ec)
1326 public override bool GetAttributableValue (Type value_type, out object value)
1328 return child.GetAttributableValue (value_type, out value);
1331 protected override void CloneTo (CloneContext clonectx, Expression t)
1333 EmptyCast target = (EmptyCast) t;
1335 target.child = child.Clone (clonectx);
1340 /// Performs a cast using an operator (op_Explicit or op_Implicit)
1342 public class OperatorCast : EmptyCast {
1343 MethodInfo conversion_operator;
1346 public OperatorCast (Expression child, Type target_type) : this (child, target_type, false) {}
1348 public OperatorCast (Expression child, Type target_type, bool find_explicit)
1349 : base (child, target_type)
1351 this.find_explicit = find_explicit;
1354 // Returns the implicit operator that converts from
1355 // 'child.Type' to our target type (type)
1356 MethodInfo GetConversionOperator (bool find_explicit)
1358 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1362 mi = TypeManager.MemberLookup (child.Type, child.Type, child.Type, MemberTypes.Method,
1363 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1366 mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1367 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1370 foreach (MethodInfo oper in mi) {
1371 ParameterData pd = TypeManager.GetParameterData (oper);
1373 if (pd.ParameterType (0) == child.Type && oper.ReturnType == type)
1381 public override void Emit (EmitContext ec)
1383 ILGenerator ig = ec.ig;
1386 conversion_operator = GetConversionOperator (find_explicit);
1388 if (conversion_operator == null)
1389 throw new InternalErrorException ("Outer conversion routine is out of sync");
1391 ig.Emit (OpCodes.Call, conversion_operator);
1397 /// This is a numeric cast to a Decimal
1399 public class CastToDecimal : EmptyCast {
1400 MethodInfo conversion_operator;
1402 public CastToDecimal (Expression child)
1403 : this (child, false)
1407 public CastToDecimal (Expression child, bool find_explicit)
1408 : base (child, TypeManager.decimal_type)
1410 conversion_operator = GetConversionOperator (find_explicit);
1412 if (conversion_operator == null)
1413 throw new InternalErrorException ("Outer conversion routine is out of sync");
1416 // Returns the implicit operator that converts from
1417 // 'child.Type' to System.Decimal.
1418 MethodInfo GetConversionOperator (bool find_explicit)
1420 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1422 MemberInfo [] mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1423 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1425 foreach (MethodInfo oper in mi) {
1426 ParameterData pd = TypeManager.GetParameterData (oper);
1428 if (pd.ParameterType (0) == child.Type && oper.ReturnType == type)
1434 public override void Emit (EmitContext ec)
1436 ILGenerator ig = ec.ig;
1439 ig.Emit (OpCodes.Call, conversion_operator);
1444 /// This is an explicit numeric cast from a Decimal
1446 public class CastFromDecimal : EmptyCast
1448 static IDictionary operators;
1450 public CastFromDecimal (Expression child, Type return_type)
1451 : base (child, return_type)
1453 if (child.Type != TypeManager.decimal_type)
1454 throw new InternalErrorException (
1455 "The expected type is Decimal, instead it is " + child.Type.FullName);
1458 // Returns the explicit operator that converts from an
1459 // express of type System.Decimal to 'type'.
1460 public Expression Resolve ()
1462 if (operators == null) {
1463 MemberInfo[] all_oper = TypeManager.MemberLookup (TypeManager.decimal_type,
1464 TypeManager.decimal_type, TypeManager.decimal_type, MemberTypes.Method,
1465 BindingFlags.Static | BindingFlags.Public, "op_Explicit", null);
1467 operators = new System.Collections.Specialized.HybridDictionary ();
1468 foreach (MethodInfo oper in all_oper) {
1469 ParameterData pd = TypeManager.GetParameterData (oper);
1470 if (pd.ParameterType (0) == TypeManager.decimal_type)
1471 operators.Add (oper.ReturnType, oper);
1475 return operators.Contains (type) ? this : null;
1478 public override void Emit (EmitContext ec)
1480 ILGenerator ig = ec.ig;
1483 ig.Emit (OpCodes.Call, (MethodInfo)operators [type]);
1489 // Constant specialization of EmptyCast.
1490 // We need to special case this since an empty cast of
1491 // a constant is still a constant.
1493 public class EmptyConstantCast : Constant
1495 public readonly Constant child;
1497 public EmptyConstantCast(Constant child, Type type)
1498 : base (child.Location)
1500 eclass = child.eclass;
1505 public override string AsString ()
1507 return child.AsString ();
1510 public override object GetValue ()
1512 return child.GetValue ();
1515 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
1517 // FIXME: check that 'type' can be converted to 'target_type' first
1518 return child.ConvertExplicitly (in_checked_context, target_type);
1521 public override Constant Increment ()
1523 return child.Increment ();
1526 public override bool IsDefaultValue {
1527 get { return child.IsDefaultValue; }
1530 public override bool IsNegative {
1531 get { return child.IsNegative; }
1534 public override bool IsNull {
1535 get { return child.IsNull; }
1538 public override bool IsZeroInteger {
1539 get { return child.IsZeroInteger; }
1542 public override void Emit (EmitContext ec)
1547 public override Constant ConvertImplicitly (Type target_type)
1549 // FIXME: Do we need to check user conversions?
1550 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1552 return child.ConvertImplicitly (target_type);
1558 /// This class is used to wrap literals which belong inside Enums
1560 public class EnumConstant : Constant {
1561 public Constant Child;
1563 public EnumConstant (Constant child, Type enum_type):
1564 base (child.Location)
1566 eclass = child.eclass;
1571 public override Expression DoResolve (EmitContext ec)
1573 // This should never be invoked, we are born in fully
1574 // initialized state.
1579 public override void Emit (EmitContext ec)
1584 public override bool GetAttributableValue (Type value_type, out object value)
1586 value = GetTypedValue ();
1590 public override string GetSignatureForError()
1592 return TypeManager.CSharpName (Type);
1595 public override object GetValue ()
1597 return Child.GetValue ();
1600 public override object GetTypedValue ()
1602 // FIXME: runtime is not ready to work with just emited enums
1603 if (!RootContext.StdLib) {
1604 return Child.GetValue ();
1607 return System.Enum.ToObject (type, Child.GetValue ());
1610 public override string AsString ()
1612 return TypeManager.CSharpEnumValue (type, Child.GetValue ());
1615 public override Constant Increment()
1617 return new EnumConstant (Child.Increment (), type);
1620 public override bool IsDefaultValue {
1622 return Child.IsDefaultValue;
1626 public override bool IsZeroInteger {
1627 get { return Child.IsZeroInteger; }
1630 public override bool IsNegative {
1632 return Child.IsNegative;
1636 public override Constant ConvertExplicitly(bool in_checked_context, Type target_type)
1638 if (Child.Type == target_type)
1641 return Child.ConvertExplicitly (in_checked_context, target_type);
1644 public override Constant ConvertImplicitly (Type type)
1646 Type this_type = TypeManager.DropGenericTypeArguments (Type);
1647 type = TypeManager.DropGenericTypeArguments (type);
1649 if (this_type == type) {
1650 // This is workaround of mono bug. It can be removed when the latest corlib spreads enough
1651 if (TypeManager.IsEnumType (type.UnderlyingSystemType))
1654 Type child_type = TypeManager.DropGenericTypeArguments (Child.Type);
1655 if (type.UnderlyingSystemType != child_type)
1656 Child = Child.ConvertImplicitly (type.UnderlyingSystemType);
1660 if (!Convert.ImplicitStandardConversionExists (this, type)){
1664 return Child.ConvertImplicitly(type);
1670 /// This kind of cast is used to encapsulate Value Types in objects.
1672 /// The effect of it is to box the value type emitted by the previous
1675 public class BoxedCast : EmptyCast {
1677 public BoxedCast (Expression expr, Type target_type)
1678 : base (expr, target_type)
1680 eclass = ExprClass.Value;
1683 public override Expression DoResolve (EmitContext ec)
1685 // This should never be invoked, we are born in fully
1686 // initialized state.
1691 public override void Emit (EmitContext ec)
1695 ec.ig.Emit (OpCodes.Box, child.Type);
1699 public class UnboxCast : EmptyCast {
1700 public UnboxCast (Expression expr, Type return_type)
1701 : base (expr, return_type)
1705 public override Expression DoResolve (EmitContext ec)
1707 // This should never be invoked, we are born in fully
1708 // initialized state.
1713 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1715 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
1716 Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
1717 return base.DoResolveLValue (ec, right_side);
1720 public override void Emit (EmitContext ec)
1723 ILGenerator ig = ec.ig;
1727 if (t.IsGenericParameter || t.IsGenericType && t.IsValueType)
1728 ig.Emit (OpCodes.Unbox_Any, t);
1732 ig.Emit (OpCodes.Unbox, t);
1734 LoadFromPtr (ig, t);
1740 /// This is used to perform explicit numeric conversions.
1742 /// Explicit numeric conversions might trigger exceptions in a checked
1743 /// context, so they should generate the conv.ovf opcodes instead of
1746 public class ConvCast : EmptyCast {
1747 public enum Mode : byte {
1748 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1750 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1751 U2_I1, U2_U1, U2_I2, U2_CH,
1752 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1753 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1754 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH,
1755 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH,
1756 CH_I1, CH_U1, CH_I2,
1757 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1758 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4
1763 public ConvCast (Expression child, Type return_type, Mode m)
1764 : base (child, return_type)
1769 public override Expression DoResolve (EmitContext ec)
1771 // This should never be invoked, we are born in fully
1772 // initialized state.
1777 public override string ToString ()
1779 return String.Format ("ConvCast ({0}, {1})", mode, child);
1782 public override void Emit (EmitContext ec)
1784 ILGenerator ig = ec.ig;
1790 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1791 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1792 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1793 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1794 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1796 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1797 case Mode.U1_CH: /* nothing */ break;
1799 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1800 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1801 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1802 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1803 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1804 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1806 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1807 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1808 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1809 case Mode.U2_CH: /* nothing */ break;
1811 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1812 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1813 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1814 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1815 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1816 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1817 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1819 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1820 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1821 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1822 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1823 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1824 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1826 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1827 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1828 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1829 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1830 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1831 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1832 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1833 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1835 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1836 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1837 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1838 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1839 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1840 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1841 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1842 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1844 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1845 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1846 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1848 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1849 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1850 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1851 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1852 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1853 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1854 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1855 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1856 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1858 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1859 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1860 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1861 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1862 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1863 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1864 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1865 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1866 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1867 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1871 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
1872 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
1873 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
1874 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
1875 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
1877 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
1878 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
1880 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
1881 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
1882 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
1883 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
1884 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
1885 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
1887 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
1888 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
1889 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
1890 case Mode.U2_CH: /* nothing */ break;
1892 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
1893 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
1894 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
1895 case Mode.I4_U4: /* nothing */ break;
1896 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
1897 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
1898 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
1900 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
1901 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
1902 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
1903 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
1904 case Mode.U4_I4: /* nothing */ break;
1905 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
1907 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
1908 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
1909 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
1910 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
1911 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
1912 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
1913 case Mode.I8_U8: /* nothing */ break;
1914 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
1916 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
1917 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
1918 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
1919 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
1920 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
1921 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
1922 case Mode.U8_I8: /* nothing */ break;
1923 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
1925 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
1926 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
1927 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
1929 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
1930 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
1931 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
1932 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
1933 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
1934 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
1935 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
1936 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
1937 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
1939 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
1940 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
1941 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
1942 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
1943 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
1944 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
1945 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
1946 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
1947 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
1948 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1954 public class OpcodeCast : EmptyCast {
1958 public OpcodeCast (Expression child, Type return_type, OpCode op)
1959 : base (child, return_type)
1963 second_valid = false;
1966 public OpcodeCast (Expression child, Type return_type, OpCode op, OpCode op2)
1967 : base (child, return_type)
1972 second_valid = true;
1975 public override Expression DoResolve (EmitContext ec)
1977 // This should never be invoked, we are born in fully
1978 // initialized state.
1983 public override void Emit (EmitContext ec)
1994 /// This kind of cast is used to encapsulate a child and cast it
1995 /// to the class requested
1997 public class ClassCast : EmptyCast {
1998 public ClassCast (Expression child, Type return_type)
1999 : base (child, return_type)
2004 public override Expression DoResolve (EmitContext ec)
2006 // This should never be invoked, we are born in fully
2007 // initialized state.
2012 public override void Emit (EmitContext ec)
2016 if (TypeManager.IsGenericParameter (child.Type))
2017 ec.ig.Emit (OpCodes.Box, child.Type);
2020 if (type.IsGenericParameter)
2021 ec.ig.Emit (OpCodes.Unbox_Any, type);
2024 ec.ig.Emit (OpCodes.Castclass, type);
2029 /// SimpleName expressions are formed of a single word and only happen at the beginning
2030 /// of a dotted-name.
2032 public class SimpleName : Expression {
2033 public readonly string Name;
2034 public readonly TypeArguments Arguments;
2037 public SimpleName (string name, Location l)
2043 public SimpleName (string name, TypeArguments args, Location l)
2050 public SimpleName (string name, TypeParameter[] type_params, Location l)
2055 Arguments = new TypeArguments (l);
2056 foreach (TypeParameter type_param in type_params)
2057 Arguments.Add (new TypeParameterExpr (type_param, l));
2060 public static string RemoveGenericArity (string name)
2063 StringBuilder sb = null;
2065 int pos = name.IndexOf ('`', start);
2070 sb.Append (name.Substring (start));
2075 sb = new StringBuilder ();
2076 sb.Append (name.Substring (start, pos-start));
2079 while ((pos < name.Length) && Char.IsNumber (name [pos]))
2083 } while (start < name.Length);
2085 return sb.ToString ();
2088 public SimpleName GetMethodGroup ()
2090 return new SimpleName (RemoveGenericArity (Name), Arguments, loc);
2093 public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
2095 if (ec.IsInFieldInitializer)
2096 Report.Error (236, l,
2097 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2101 120, l, "`{0}': An object reference is required for the nonstatic field, method or property",
2105 public bool IdenticalNameAndTypeName (EmitContext ec, Expression resolved_to, Location loc)
2107 return resolved_to != null && resolved_to.Type != null &&
2108 resolved_to.Type.Name == Name &&
2109 (ec.DeclContainer.LookupNamespaceOrType (Name, loc, /* ignore_cs0104 = */ true) != null);
2112 public override Expression DoResolve (EmitContext ec)
2114 return SimpleNameResolve (ec, null, false);
2117 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
2119 return SimpleNameResolve (ec, right_side, false);
2123 public Expression DoResolve (EmitContext ec, bool intermediate)
2125 return SimpleNameResolve (ec, null, intermediate);
2128 private bool IsNestedChild (Type t, Type parent)
2133 while (parent != null) {
2134 parent = TypeManager.DropGenericTypeArguments (parent);
2135 if (TypeManager.IsNestedChildOf (t, parent))
2138 parent = parent.BaseType;
2144 FullNamedExpression ResolveNested (IResolveContext ec, Type t)
2146 if (!TypeManager.IsGenericTypeDefinition (t) && !TypeManager.IsGenericType (t))
2149 DeclSpace ds = ec.DeclContainer;
2150 while (ds != null) {
2151 if (IsNestedChild (t, ds.TypeBuilder))
2160 Type[] gen_params = TypeManager.GetTypeArguments (t);
2162 int arg_count = Arguments != null ? Arguments.Count : 0;
2164 for (; (ds != null) && ds.IsGeneric; ds = ds.Parent) {
2165 if (arg_count + ds.CountTypeParameters == gen_params.Length) {
2166 TypeArguments new_args = new TypeArguments (loc);
2167 foreach (TypeParameter param in ds.TypeParameters)
2168 new_args.Add (new TypeParameterExpr (param, loc));
2170 if (Arguments != null)
2171 new_args.Add (Arguments);
2173 return new ConstructedType (t, new_args, loc);
2180 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2182 FullNamedExpression fne = ec.GenericDeclContainer.LookupGeneric (Name, loc);
2184 return fne.ResolveAsTypeStep (ec, silent);
2186 int errors = Report.Errors;
2187 fne = ec.DeclContainer.LookupNamespaceOrType (Name, loc, /*ignore_cs0104=*/ false);
2190 if (fne.Type == null)
2193 FullNamedExpression nested = ResolveNested (ec, fne.Type);
2195 return nested.ResolveAsTypeStep (ec, false);
2197 if (Arguments != null) {
2198 ConstructedType ct = new ConstructedType (fne, Arguments, loc);
2199 return ct.ResolveAsTypeStep (ec, false);
2205 if (silent || errors != Report.Errors)
2208 Error_TypeOrNamespaceNotFound (ec);
2212 protected virtual void Error_TypeOrNamespaceNotFound (IResolveContext ec)
2214 MemberCore mc = ec.DeclContainer.GetDefinition (Name);
2216 Error_UnexpectedKind (ec.DeclContainer, "type", GetMemberType (mc), loc);
2220 string ns = ec.DeclContainer.NamespaceEntry.NS.Name;
2221 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2222 foreach (Assembly a in RootNamespace.Global.Assemblies) {
2223 Type type = a.GetType (fullname);
2225 Report.SymbolRelatedToPreviousError (type);
2226 Expression.ErrorIsInaccesible (loc, TypeManager.CSharpName (type));
2231 Type t = ec.DeclContainer.LookupAnyGeneric (Name);
2233 Namespace.Error_InvalidNumberOfTypeArguments (t, loc);
2237 if (Arguments != null) {
2238 FullNamedExpression retval = ec.DeclContainer.LookupNamespaceOrType (SimpleName.RemoveGenericArity (Name), loc, true);
2239 if (retval != null) {
2240 Namespace.Error_TypeArgumentsCannotBeUsed (retval.Type, loc);
2245 NamespaceEntry.Error_NamespaceNotFound (loc, Name);
2248 // TODO: I am still not convinced about this. If someone else will need it
2249 // implement this as virtual property in MemberCore hierarchy
2250 public static string GetMemberType (MemberCore mc)
2256 if (mc is FieldBase)
2258 if (mc is MethodCore)
2260 if (mc is EnumMember)
2268 Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2274 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2280 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2287 /// 7.5.2: Simple Names.
2289 /// Local Variables and Parameters are handled at
2290 /// parse time, so they never occur as SimpleNames.
2292 /// The `intermediate' flag is used by MemberAccess only
2293 /// and it is used to inform us that it is ok for us to
2294 /// avoid the static check, because MemberAccess might end
2295 /// up resolving the Name as a Type name and the access as
2296 /// a static type access.
2298 /// ie: Type Type; .... { Type.GetType (""); }
2300 /// Type is both an instance variable and a Type; Type.GetType
2301 /// is the static method not an instance method of type.
2303 Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2305 Expression e = null;
2308 // Stage 1: Performed by the parser (binding to locals or parameters).
2310 Block current_block = ec.CurrentBlock;
2311 if (current_block != null){
2312 LocalInfo vi = current_block.GetLocalInfo (Name);
2314 if (Arguments != null) {
2315 Report.Error (307, loc,
2316 "The variable `{0}' cannot be used with type arguments",
2321 LocalVariableReference var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2322 if (right_side != null) {
2323 return var.ResolveLValue (ec, right_side, loc);
2325 ResolveFlags rf = ResolveFlags.VariableOrValue;
2327 rf |= ResolveFlags.DisableFlowAnalysis;
2328 return var.Resolve (ec, rf);
2332 ParameterReference pref = current_block.Toplevel.GetParameterReference (Name, loc);
2334 if (Arguments != null) {
2335 Report.Error (307, loc,
2336 "The variable `{0}' cannot be used with type arguments",
2341 if (right_side != null)
2342 return pref.ResolveLValue (ec, right_side, loc);
2344 return pref.Resolve (ec);
2347 Expression expr = current_block.Toplevel.GetTransparentIdentifier (Name);
2349 if (right_side != null)
2350 return expr.ResolveLValue (ec, right_side, loc);
2351 return expr.Resolve (ec);
2356 // Stage 2: Lookup members
2359 Type almost_matched_type = null;
2360 ArrayList almost_matched = null;
2361 for (DeclSpace lookup_ds = ec.DeclContainer; lookup_ds != null; lookup_ds = lookup_ds.Parent) {
2362 // either RootDeclSpace or GenericMethod
2363 if (lookup_ds.TypeBuilder == null)
2366 e = MemberLookup (ec.ContainerType, lookup_ds.TypeBuilder, Name, loc);
2368 if (e is PropertyExpr) {
2369 // since TypeManager.MemberLookup doesn't know if we're doing a lvalue access or not,
2370 // it doesn't know which accessor to check permissions against
2371 if (((PropertyExpr) e).IsAccessibleFrom (ec.ContainerType, right_side != null))
2373 } else if (e is EventExpr) {
2374 if (((EventExpr) e).IsAccessibleFrom (ec.ContainerType))
2382 if (almost_matched == null && almost_matched_members.Count > 0) {
2383 almost_matched_type = lookup_ds.TypeBuilder;
2384 almost_matched = (ArrayList) almost_matched_members.Clone ();
2389 if (almost_matched == null && almost_matched_members.Count > 0) {
2390 almost_matched_type = ec.ContainerType;
2391 almost_matched = (ArrayList) almost_matched_members.Clone ();
2393 e = ResolveAsTypeStep (ec, true);
2397 if (current_block != null) {
2398 IKnownVariable ikv = current_block.Explicit.GetKnownVariable (Name);
2400 LocalInfo li = ikv as LocalInfo;
2401 // Supress CS0219 warning
2405 Error_VariableIsUsedBeforeItIsDeclared (Name);
2410 if (almost_matched != null)
2411 almost_matched_members = almost_matched;
2412 if (almost_matched_type == null)
2413 almost_matched_type = ec.ContainerType;
2414 Error_MemberLookupFailed (ec.ContainerType, null, almost_matched_type, Name,
2415 ec.DeclContainer.Name, AllMemberTypes, AllBindingFlags);
2419 if (e is TypeExpr) {
2420 if (Arguments == null)
2423 ConstructedType ct = new ConstructedType (
2424 (FullNamedExpression) e, Arguments, loc);
2425 return ct.ResolveAsTypeStep (ec, false);
2428 if (e is MemberExpr) {
2429 MemberExpr me = (MemberExpr) e;
2432 if (me.IsInstance) {
2433 if (ec.IsStatic || ec.IsInFieldInitializer) {
2435 // Note that an MemberExpr can be both IsInstance and IsStatic.
2436 // An unresolved MethodGroupExpr can contain both kinds of methods
2437 // and each predicate is true if the MethodGroupExpr contains
2438 // at least one of that kind of method.
2442 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2443 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2444 return EmptyExpression.Null;
2448 // Pass the buck to MemberAccess and Invocation.
2450 left = EmptyExpression.Null;
2452 left = ec.GetThis (loc);
2455 left = new TypeExpression (ec.ContainerType, loc);
2458 me = me.ResolveMemberAccess (ec, left, loc, null);
2462 if (Arguments != null) {
2463 Arguments.Resolve (ec);
2464 me.SetTypeArguments (Arguments);
2467 if (!me.IsStatic && (me.InstanceExpression != null) &&
2468 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2469 me.InstanceExpression.Type != me.DeclaringType &&
2470 !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2471 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2472 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2473 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2477 return (right_side != null)
2478 ? me.DoResolveLValue (ec, right_side)
2479 : me.DoResolve (ec);
2485 public override void Emit (EmitContext ec)
2487 throw new InternalErrorException ("The resolve phase was not executed");
2490 public override string ToString ()
2495 public override string GetSignatureForError ()
2497 if (Arguments != null) {
2498 return TypeManager.RemoveGenericArity (Name) + "<" +
2499 Arguments.GetSignatureForError () + ">";
2505 protected override void CloneTo (CloneContext clonectx, Expression target)
2507 // CloneTo: Nothing, we do not keep any state on this expression
2512 /// Represents a namespace or a type. The name of the class was inspired by
2513 /// section 10.8.1 (Fully Qualified Names).
2515 public abstract class FullNamedExpression : Expression {
2516 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2521 public abstract string FullName {
2527 /// Expression that evaluates to a type
2529 public abstract class TypeExpr : FullNamedExpression {
2530 override public FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2532 TypeExpr t = DoResolveAsTypeStep (ec);
2536 eclass = ExprClass.Type;
2540 override public Expression DoResolve (EmitContext ec)
2542 return ResolveAsTypeTerminal (ec, false);
2545 override public void Emit (EmitContext ec)
2547 throw new Exception ("Should never be called");
2550 public virtual bool CheckAccessLevel (DeclSpace ds)
2552 return ds.CheckAccessLevel (Type);
2555 public virtual bool AsAccessible (DeclSpace ds, int flags)
2557 return ds.AsAccessible (Type, flags);
2560 public virtual bool IsClass {
2561 get { return Type.IsClass; }
2564 public virtual bool IsValueType {
2565 get { return Type.IsValueType; }
2568 public virtual bool IsInterface {
2569 get { return Type.IsInterface; }
2572 public virtual bool IsSealed {
2573 get { return Type.IsSealed; }
2576 public virtual bool CanInheritFrom ()
2578 if (Type == TypeManager.enum_type ||
2579 (Type == TypeManager.value_type && RootContext.StdLib) ||
2580 Type == TypeManager.multicast_delegate_type ||
2581 Type == TypeManager.delegate_type ||
2582 Type == TypeManager.array_type)
2588 protected abstract TypeExpr DoResolveAsTypeStep (IResolveContext ec);
2590 public abstract string Name {
2594 public override bool Equals (object obj)
2596 TypeExpr tobj = obj as TypeExpr;
2600 return Type == tobj.Type;
2603 public override int GetHashCode ()
2605 return Type.GetHashCode ();
2608 public override string ToString ()
2615 /// Fully resolved Expression that already evaluated to a type
2617 public class TypeExpression : TypeExpr {
2618 public TypeExpression (Type t, Location l)
2621 eclass = ExprClass.Type;
2625 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2630 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2635 public override string Name {
2636 get { return Type.ToString (); }
2639 public override string FullName {
2640 get { return Type.FullName; }
2645 /// Used to create types from a fully qualified name. These are just used
2646 /// by the parser to setup the core types. A TypeLookupExpression is always
2647 /// classified as a type.
2649 public sealed class TypeLookupExpression : TypeExpr {
2650 readonly string name;
2652 public TypeLookupExpression (string name)
2655 eclass = ExprClass.Type;
2658 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2660 // It's null for corlib compilation only
2662 return DoResolveAsTypeStep (ec);
2667 private class UnexpectedType
2671 // This performes recursive type lookup, providing support for generic types.
2672 // For example, given the type:
2674 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]]
2676 // The types will be checked in the following order:
2679 // System.Collections |
2680 // System.Collections.Generic |
2682 // System | recursive call 1 |
2683 // System.Int32 _| | main method call
2685 // System | recursive call 2 |
2686 // System.String _| |
2688 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]] _|
2690 private Type TypeLookup (IResolveContext ec, string name)
2695 FullNamedExpression resolved = null;
2697 Type recursive_type = null;
2698 while (index < name.Length) {
2699 if (name[index] == '[') {
2704 if (name[index] == '[')
2706 else if (name[index] == ']')
2708 } while (braces > 0);
2709 recursive_type = TypeLookup (ec, name.Substring (open + 1, index - open - 1));
2710 if (recursive_type == null || (recursive_type == typeof(UnexpectedType)))
2711 return recursive_type;
2714 if (name[index] == ',')
2716 else if ((name[index] == '.' && !done) || (index == name.Length && name[0] != '[')) {
2717 string substring = name.Substring(dot, index - dot);
2719 if (resolved == null)
2720 resolved = RootNamespace.Global.Lookup (ec.DeclContainer, substring, Location.Null);
2721 else if (resolved is Namespace)
2722 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
2723 else if (type != null)
2724 type = TypeManager.GetNestedType (type, substring);
2728 if (resolved == null)
2730 else if (type == null && resolved is TypeExpr)
2731 type = resolved.Type;
2738 if (name[0] != '[') {
2739 string substring = name.Substring(dot, index - dot);
2742 return TypeManager.GetNestedType (type, substring);
2744 if (resolved != null) {
2745 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
2746 if (resolved is TypeExpr)
2747 return resolved.Type;
2749 if (resolved == null)
2752 resolved.Error_UnexpectedKind (ec.DeclContainer, "type", loc);
2753 return typeof (UnexpectedType);
2759 return recursive_type;
2762 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2764 Type t = TypeLookup (ec, name);
2766 NamespaceEntry.Error_NamespaceNotFound (loc, name);
2769 if (t == typeof(UnexpectedType))
2775 public override string Name {
2776 get { return name; }
2779 public override string FullName {
2780 get { return name; }
2783 protected override void CloneTo (CloneContext clonectx, Expression target)
2785 // CloneTo: Nothing, we do not keep any state on this expression
2788 public override string GetSignatureForError ()
2791 return TypeManager.CSharpName (name);
2793 return base.GetSignatureForError ();
2798 /// Represents an "unbound generic type", ie. typeof (Foo<>).
2801 public class UnboundTypeExpression : TypeExpr
2805 public UnboundTypeExpression (MemberName name, Location l)
2811 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2814 if (name.Left != null) {
2815 Expression lexpr = name.Left.GetTypeExpression ();
2816 expr = new MemberAccess (lexpr, name.Basename);
2818 expr = new SimpleName (name.Basename, loc);
2821 FullNamedExpression fne = expr.ResolveAsTypeStep (ec, false);
2826 return new TypeExpression (type, loc);
2829 public override string Name {
2830 get { return name.FullName; }
2833 public override string FullName {
2834 get { return name.FullName; }
2838 public class TypeAliasExpression : TypeExpr {
2839 FullNamedExpression alias;
2844 public TypeAliasExpression (FullNamedExpression alias, TypeArguments args, Location l)
2850 eclass = ExprClass.Type;
2852 name = alias.FullName + "<" + args.ToString () + ">";
2854 name = alias.FullName;
2857 public override string Name {
2858 get { return alias.FullName; }
2861 public override string FullName {
2862 get { return name; }
2865 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2867 texpr = alias.ResolveAsTypeTerminal (ec, false);
2871 Type type = texpr.Type;
2872 int num_args = TypeManager.GetNumberOfTypeArguments (type);
2875 if (num_args == 0) {
2876 Report.Error (308, loc,
2877 "The non-generic type `{0}' cannot " +
2878 "be used with type arguments.",
2879 TypeManager.CSharpName (type));
2883 ConstructedType ctype = new ConstructedType (type, args, loc);
2884 return ctype.ResolveAsTypeTerminal (ec, false);
2885 } else if (num_args > 0) {
2886 Report.Error (305, loc,
2887 "Using the generic type `{0}' " +
2888 "requires {1} type arguments",
2889 TypeManager.CSharpName (type), num_args.ToString ());
2896 public override bool CheckAccessLevel (DeclSpace ds)
2898 return texpr.CheckAccessLevel (ds);
2901 public override bool AsAccessible (DeclSpace ds, int flags)
2903 return texpr.AsAccessible (ds, flags);
2906 public override bool IsClass {
2907 get { return texpr.IsClass; }
2910 public override bool IsValueType {
2911 get { return texpr.IsValueType; }
2914 public override bool IsInterface {
2915 get { return texpr.IsInterface; }
2918 public override bool IsSealed {
2919 get { return texpr.IsSealed; }
2924 /// This class denotes an expression which evaluates to a member
2925 /// of a struct or a class.
2927 public abstract class MemberExpr : Expression
2929 protected bool is_base;
2932 /// The name of this member.
2934 public abstract string Name {
2939 // When base.member is used
2941 public bool IsBase {
2942 get { return is_base; }
2943 set { is_base = value; }
2947 /// Whether this is an instance member.
2949 public abstract bool IsInstance {
2954 /// Whether this is a static member.
2956 public abstract bool IsStatic {
2961 /// The type which declares this member.
2963 public abstract Type DeclaringType {
2968 /// The instance expression associated with this member, if it's a
2969 /// non-static member.
2971 public Expression InstanceExpression;
2973 public static void error176 (Location loc, string name)
2975 Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
2976 "with an instance reference, qualify it with a type name instead", name);
2979 // TODO: possible optimalization
2980 // Cache resolved constant result in FieldBuilder <-> expression map
2981 public virtual MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
2982 SimpleName original)
2986 // original == null || original.Resolve (...) ==> left
2989 if (left is TypeExpr) {
2990 left = left.ResolveAsTypeTerminal (ec, true);
2995 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3003 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3006 return ResolveExtensionMemberAccess (left);
3009 InstanceExpression = left;
3013 protected virtual MemberExpr ResolveExtensionMemberAccess (Expression left)
3015 error176 (loc, GetSignatureForError ());
3019 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3024 if (InstanceExpression == EmptyExpression.Null) {
3025 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3029 if (InstanceExpression.Type.IsValueType) {
3030 if (InstanceExpression is IMemoryLocation) {
3031 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
3033 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
3034 InstanceExpression.Emit (ec);
3036 t.AddressOf (ec, AddressOp.Store);
3039 InstanceExpression.Emit (ec);
3041 if (prepare_for_load)
3042 ec.ig.Emit (OpCodes.Dup);
3045 public virtual void SetTypeArguments (TypeArguments ta)
3047 // TODO: need to get correct member type
3048 Report.Error (307, loc, "The property `{0}' cannot be used with type arguments",
3049 GetSignatureForError ());
3054 /// Represents group of extension methods
3056 public class ExtensionMethodGroupExpr : MethodGroupExpr
3058 readonly NamespaceEntry namespace_entry;
3059 public Expression ExtensionExpression;
3060 Argument extension_argument;
3062 public ExtensionMethodGroupExpr (ArrayList list, NamespaceEntry n, Type extensionType, Location l)
3063 : base (list, extensionType, l)
3065 this.namespace_entry = n;
3068 public override bool IsStatic {
3069 get { return true; }
3072 public bool IsTopLevel {
3073 get { return namespace_entry == null; }
3076 public override void EmitArguments (EmitContext ec, ArrayList arguments)
3078 if (arguments == null)
3079 arguments = new ArrayList (1);
3080 arguments.Insert (0, extension_argument);
3081 base.EmitArguments (ec, arguments);
3084 public override void EmitCall (EmitContext ec, ArrayList arguments)
3086 if (arguments == null)
3087 arguments = new ArrayList (1);
3088 arguments.Insert (0, extension_argument);
3089 base.EmitCall (ec, arguments);
3092 public override MethodGroupExpr OverloadResolve (EmitContext ec, ArrayList arguments, bool may_fail, Location loc)
3094 if ((ExtensionExpression.eclass & (ExprClass.Value | ExprClass.Variable)) == 0)
3095 return base.OverloadResolve (ec, arguments, may_fail, loc);
3097 if (arguments == null)
3098 arguments = new ArrayList (1);
3100 arguments.Insert (0, new Argument (ExtensionExpression));
3101 MethodGroupExpr mg = ResolveOverloadExtensions (ec, arguments, namespace_entry, loc);
3103 // Store resolved argument and restore original arguments
3105 ((ExtensionMethodGroupExpr)mg).extension_argument = (Argument)arguments [0];
3106 arguments.RemoveAt (0);
3111 MethodGroupExpr ResolveOverloadExtensions (EmitContext ec, ArrayList arguments, NamespaceEntry ns, Location loc)
3113 // Use normal resolve rules
3114 MethodGroupExpr mg = base.OverloadResolve (ec, arguments, ns != null, loc);
3122 ExtensionMethodGroupExpr e = ns.LookupExtensionMethod (type, null, Name);
3124 return base.OverloadResolve (ec, arguments, false, loc);
3126 e.ExtensionExpression = ExtensionExpression;
3127 return e.ResolveOverloadExtensions (ec, arguments, e.namespace_entry, loc);
3132 /// MethodGroupExpr represents a group of method candidates which
3133 /// can be resolved to the best method overload
3135 public class MethodGroupExpr : MemberExpr
3137 public interface IErrorHandler
3139 bool NoExactMatch (EmitContext ec, MethodBase method);
3142 public IErrorHandler CustomErrorHandler;
3143 public MethodBase [] Methods;
3144 MethodBase best_candidate;
3145 // TODO: make private
3146 public TypeArguments type_arguments;
3147 bool identical_type_name;
3150 public MethodGroupExpr (MemberInfo [] mi, Type type, Location l)
3153 Methods = new MethodBase [mi.Length];
3154 mi.CopyTo (Methods, 0);
3157 public MethodGroupExpr (ArrayList list, Type type, Location l)
3161 Methods = (MethodBase[])list.ToArray (typeof (MethodBase));
3163 foreach (MemberInfo m in list){
3164 if (!(m is MethodBase)){
3165 Console.WriteLine ("Name " + m.Name);
3166 Console.WriteLine ("Found a: " + m.GetType ().FullName);
3175 protected MethodGroupExpr (Type type, Location loc)
3178 eclass = ExprClass.MethodGroup;
3182 public override Type DeclaringType {
3185 // We assume that the top-level type is in the end
3187 return Methods [Methods.Length - 1].DeclaringType;
3188 //return Methods [0].DeclaringType;
3192 public Type DelegateType {
3194 delegate_type = value;
3198 public bool IdenticalTypeName {
3200 return identical_type_name;
3204 identical_type_name = value;
3208 public override string GetSignatureForError ()
3210 if (best_candidate != null)
3211 return TypeManager.CSharpSignature (best_candidate);
3213 return TypeManager.CSharpSignature (Methods [0]);
3216 public override string Name {
3218 return Methods [0].Name;
3222 public override bool IsInstance {
3224 if (best_candidate != null)
3225 return !best_candidate.IsStatic;
3227 foreach (MethodBase mb in Methods)
3235 public override bool IsStatic {
3237 if (best_candidate != null)
3238 return best_candidate.IsStatic;
3240 foreach (MethodBase mb in Methods)
3248 public static explicit operator ConstructorInfo (MethodGroupExpr mg)
3250 return (ConstructorInfo)mg.best_candidate;
3253 public static explicit operator MethodInfo (MethodGroupExpr mg)
3255 return (MethodInfo)mg.best_candidate;
3259 /// Determines "better conversion" as specified in 14.4.2.3
3261 /// Returns : p if a->p is better,
3262 /// q if a->q is better,
3263 /// null if neither is better
3265 static Type BetterConversion (EmitContext ec, Argument a, Type p, Type q)
3267 Type argument_type = TypeManager.TypeToCoreType (a.Type);
3268 Expression argument_expr = a.Expr;
3270 if (argument_type == null)
3271 throw new Exception ("Expression of type " + a.Expr +
3272 " does not resolve its type");
3274 if (p == null || q == null)
3275 throw new InternalErrorException ("BetterConversion Got a null conversion");
3280 if (argument_expr is NullLiteral)
3283 // If the argument is null and one of the types to compare is 'object' and
3284 // the other is a reference type, we prefer the other.
3286 // This follows from the usual rules:
3287 // * There is an implicit conversion from 'null' to type 'object'
3288 // * There is an implicit conversion from 'null' to any reference type
3289 // * There is an implicit conversion from any reference type to type 'object'
3290 // * There is no implicit conversion from type 'object' to other reference types
3291 // => Conversion of 'null' to a reference type is better than conversion to 'object'
3293 // FIXME: This probably isn't necessary, since the type of a NullLiteral is the
3294 // null type. I think it used to be 'object' and thus needed a special
3295 // case to avoid the immediately following two checks.
3297 if (!p.IsValueType && q == TypeManager.object_type)
3299 if (!q.IsValueType && p == TypeManager.object_type)
3303 if (argument_type == p)
3306 if (argument_type == q)
3309 Expression p_tmp = new EmptyExpression (p);
3310 Expression q_tmp = new EmptyExpression (q);
3312 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3313 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3315 if (p_to_q && !q_to_p)
3318 if (q_to_p && !p_to_q)
3321 if (p == TypeManager.sbyte_type)
3322 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3323 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3325 if (q == TypeManager.sbyte_type)
3326 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3327 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3330 if (p == TypeManager.short_type)
3331 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3332 q == TypeManager.uint64_type)
3334 if (q == TypeManager.short_type)
3335 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3336 p == TypeManager.uint64_type)
3339 if (p == TypeManager.int32_type)
3340 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3342 if (q == TypeManager.int32_type)
3343 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3346 if (p == TypeManager.int64_type)
3347 if (q == TypeManager.uint64_type)
3349 if (q == TypeManager.int64_type)
3350 if (p == TypeManager.uint64_type)
3357 /// Determines "Better function" between candidate
3358 /// and the current best match
3361 /// Returns a boolean indicating :
3362 /// false if candidate ain't better
3363 /// true if candidate is better than the current best match
3365 static bool BetterFunction (EmitContext ec, ArrayList args, int argument_count,
3366 MethodBase candidate, bool candidate_params,
3367 MethodBase best, bool best_params)
3369 ParameterData candidate_pd = TypeManager.GetParameterData (candidate);
3370 ParameterData best_pd = TypeManager.GetParameterData (best);
3372 bool better_at_least_one = false;
3374 for (int j = 0, c_idx = 0, b_idx = 0; j < argument_count; ++j, ++c_idx, ++b_idx)
3376 Argument a = (Argument) args [j];
3378 Type ct = TypeManager.TypeToCoreType (candidate_pd.ParameterType (c_idx));
3379 Type bt = TypeManager.TypeToCoreType (best_pd.ParameterType (b_idx));
3381 if (candidate_params && candidate_pd.ParameterModifier (c_idx) == Parameter.Modifier.PARAMS)
3383 ct = TypeManager.GetElementType (ct);
3387 if (best_params && best_pd.ParameterModifier (b_idx) == Parameter.Modifier.PARAMS)
3389 bt = TypeManager.GetElementType (bt);
3397 Type better = BetterConversion (ec, a, ct, bt);
3399 // for each argument, the conversion to 'ct' should be no worse than
3400 // the conversion to 'bt'.
3404 // for at least one argument, the conversion to 'ct' should be better than
3405 // the conversion to 'bt'.
3407 better_at_least_one = true;
3410 if (better_at_least_one)
3414 // This handles the case
3416 // Add (float f1, float f2, float f3);
3417 // Add (params decimal [] foo);
3419 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3420 // first candidate would've chosen as better.
3426 // The two methods have equal parameter types. Now apply tie-breaking rules
3428 if (TypeManager.IsGenericMethod (best) && !TypeManager.IsGenericMethod (candidate))
3430 if (!TypeManager.IsGenericMethod (best) && TypeManager.IsGenericMethod (candidate))
3434 // This handles the following cases:
3436 // Trim () is better than Trim (params char[] chars)
3437 // Concat (string s1, string s2, string s3) is better than
3438 // Concat (string s1, params string [] srest)
3439 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3441 if (!candidate_params && best_params)
3443 if (candidate_params && !best_params)
3446 int candidate_param_count = candidate_pd.Count;
3447 int best_param_count = best_pd.Count;
3449 if (candidate_param_count != best_param_count)
3450 // can only happen if (candidate_params && best_params)
3451 return candidate_param_count > best_param_count;
3454 // now, both methods have the same number of parameters, and the parameters have the same types
3455 // Pick the "more specific" signature
3458 MethodBase orig_candidate = TypeManager.DropGenericMethodArguments (candidate);
3459 MethodBase orig_best = TypeManager.DropGenericMethodArguments (best);
3461 ParameterData orig_candidate_pd = TypeManager.GetParameterData (orig_candidate);
3462 ParameterData orig_best_pd = TypeManager.GetParameterData (orig_best);
3464 bool specific_at_least_once = false;
3465 for (int j = 0; j < candidate_param_count; ++j)
3467 Type ct = TypeManager.TypeToCoreType (orig_candidate_pd.ParameterType (j));
3468 Type bt = TypeManager.TypeToCoreType (orig_best_pd.ParameterType (j));
3471 Type specific = MoreSpecific (ct, bt);
3475 specific_at_least_once = true;
3478 if (specific_at_least_once)
3481 // FIXME: handle lifted operators
3487 protected override MemberExpr ResolveExtensionMemberAccess (Expression left)
3490 return base.ResolveExtensionMemberAccess (left);
3493 // When left side is an expression and at least one candidate method is
3494 // static, it can be extension method
3496 InstanceExpression = left;
3500 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3501 SimpleName original)
3503 if (!(left is TypeExpr) &&
3504 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3505 IdenticalTypeName = true;
3507 return base.ResolveMemberAccess (ec, left, loc, original);
3510 override public Expression DoResolve (EmitContext ec)
3512 if (InstanceExpression != null) {
3513 InstanceExpression = InstanceExpression.DoResolve (ec);
3514 if (InstanceExpression == null)
3521 public void ReportUsageError ()
3523 Report.Error (654, loc, "Method `" + DeclaringType + "." +
3524 Name + "()' is referenced without parentheses");
3527 override public void Emit (EmitContext ec)
3529 ReportUsageError ();
3532 public virtual void EmitArguments (EmitContext ec, ArrayList arguments)
3534 Invocation.EmitArguments (ec, best_candidate, arguments, false, null);
3537 public virtual void EmitCall (EmitContext ec, ArrayList arguments)
3539 Invocation.EmitCall (ec, IsBase, InstanceExpression, best_candidate, arguments, loc);
3542 protected virtual void Error_InvalidArguments (EmitContext ec, Location loc, int idx, MethodBase method,
3543 Argument a, ParameterData expected_par, Type paramType)
3545 if (a is CollectionElementInitializer.ElementInitializerArgument) {
3546 Report.SymbolRelatedToPreviousError (method);
3547 if ((expected_par.ParameterModifier (idx) & Parameter.Modifier.ISBYREF) != 0) {
3548 Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
3549 TypeManager.CSharpSignature (method));
3552 Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
3553 TypeManager.CSharpSignature (method));
3554 } else if (delegate_type == null) {
3555 Report.SymbolRelatedToPreviousError (method);
3556 Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
3557 TypeManager.CSharpSignature (method));
3559 Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
3560 TypeManager.CSharpName (delegate_type));
3562 Parameter.Modifier mod = expected_par.ParameterModifier (idx);
3564 string index = (idx + 1).ToString ();
3565 if ((mod & Parameter.Modifier.ISBYREF) != (a.Modifier & Parameter.Modifier.ISBYREF) ||
3566 (mod & Parameter.Modifier.ISBYREF) != 0) {
3567 if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) == 0)
3568 Report.Error (1615, loc, "Argument `{0}' should not be passed with the `{1}' keyword",
3569 index, Parameter.GetModifierSignature (a.Modifier));
3571 Report.Error (1620, loc, "Argument `{0}' must be passed with the `{1}' keyword",
3572 index, Parameter.GetModifierSignature (mod));
3574 string p1 = Argument.FullDesc (a);
3575 string p2 = TypeManager.CSharpName (paramType);
3578 Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
3579 Report.SymbolRelatedToPreviousError (a.Expr.Type);
3580 Report.SymbolRelatedToPreviousError (paramType);
3582 Report.Error (1503, loc, "Argument {0}: Cannot convert type `{1}' to `{2}'", index, p1, p2);
3586 protected virtual int GetApplicableParametersCount (MethodBase method, ParameterData parameters)
3588 return parameters.Count;
3591 public static bool IsAncestralType (Type first_type, Type second_type)
3593 return first_type != second_type &&
3594 (TypeManager.IsSubclassOf (second_type, first_type) ||
3595 TypeManager.ImplementsInterface (second_type, first_type));
3599 /// Determines if the candidate method is applicable (section 14.4.2.1)
3600 /// to the given set of arguments
3601 /// A return value rates candidate method compatibility,
3602 /// 0 = the best, int.MaxValue = the worst
3604 public int IsApplicable (EmitContext ec,
3605 ArrayList arguments, int arg_count, ref MethodBase method, ref bool params_expanded_form)
3607 MethodBase candidate = method;
3609 ParameterData pd = TypeManager.GetParameterData (candidate);
3610 int param_count = GetApplicableParametersCount (candidate, pd);
3612 if (arg_count != param_count) {
3614 return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
3615 if (arg_count < param_count - 1)
3616 return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
3621 // 1. Handle generic method using type arguments when specified or type inference
3623 if (TypeManager.IsGenericMethod (candidate)) {
3624 if (type_arguments != null) {
3625 Type [] g_args = candidate.GetGenericArguments ();
3626 if (g_args.Length != type_arguments.Count)
3627 return int.MaxValue - 20000 + Math.Abs (type_arguments.Count - g_args.Length);
3629 // TODO: Don't create new method, create Parameters only
3630 method = ((MethodInfo) candidate).MakeGenericMethod (type_arguments.Arguments);
3632 pd = TypeManager.GetParameterData (candidate);
3634 int score = TypeManager.InferTypeArguments (ec, arguments, ref candidate);
3636 return score - 20000;
3638 if (TypeManager.IsGenericMethodDefinition (candidate))
3639 throw new InternalErrorException ("a generic method definition took part in overload resolution");
3641 pd = TypeManager.GetParameterData (candidate);
3644 if (type_arguments != null)
3645 return int.MaxValue - 15000;
3650 // 2. Each argument has to be implicitly convertible to method parameter
3652 Parameter.Modifier p_mod = 0;
3654 for (int i = 0; i < arg_count; i++) {
3655 Argument a = (Argument) arguments [i];
3656 Parameter.Modifier a_mod = a.Modifier &
3657 ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3659 if (p_mod != Parameter.Modifier.PARAMS) {
3660 p_mod = pd.ParameterModifier (i) & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3662 if (p_mod == Parameter.Modifier.ARGLIST) {
3663 if (a.Type == TypeManager.runtime_argument_handle_type)
3669 pt = pd.ParameterType (i);
3671 params_expanded_form = true;
3675 if (!params_expanded_form)
3676 score = IsArgumentCompatible (ec, a_mod, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
3678 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0) {
3679 // It can be applicable in expanded form
3680 score = IsArgumentCompatible (ec, a_mod, a, 0, pt.GetElementType ());
3682 params_expanded_form = true;
3686 return (arg_count - i) * 2 + score;
3689 if (arg_count != param_count)
3690 params_expanded_form = true;
3696 int IsArgumentCompatible (EmitContext ec, Parameter.Modifier arg_mod, Argument argument, Parameter.Modifier param_mod, Type parameter)
3699 // Types have to be identical when ref or out modifer is used
3701 if (arg_mod != 0 || param_mod != 0) {
3702 if (TypeManager.HasElementType (parameter))
3703 parameter = parameter.GetElementType ();
3705 Type a_type = argument.Type;
3706 if (TypeManager.HasElementType (a_type))
3707 a_type = a_type.GetElementType ();
3709 if (a_type != parameter)
3715 // FIXME: Kill this abomination (EmitContext.TempEc)
3716 EmitContext prevec = EmitContext.TempEc;
3717 EmitContext.TempEc = ec;
3719 if (delegate_type != null ?
3720 !Delegate.IsTypeCovariant (argument.Expr, parameter) :
3721 !Convert.ImplicitConversionExists (ec, argument.Expr, parameter))
3724 if (arg_mod != param_mod)
3728 EmitContext.TempEc = prevec;
3734 public static bool IsOverride (MethodBase cand_method, MethodBase base_method)
3736 if (!IsAncestralType (base_method.DeclaringType, cand_method.DeclaringType))
3739 ParameterData cand_pd = TypeManager.GetParameterData (cand_method);
3740 ParameterData base_pd = TypeManager.GetParameterData (base_method);
3742 if (cand_pd.Count != base_pd.Count)
3745 for (int j = 0; j < cand_pd.Count; ++j)
3747 Parameter.Modifier cm = cand_pd.ParameterModifier (j);
3748 Parameter.Modifier bm = base_pd.ParameterModifier (j);
3749 Type ct = TypeManager.TypeToCoreType (cand_pd.ParameterType (j));
3750 Type bt = TypeManager.TypeToCoreType (base_pd.ParameterType (j));
3752 if (cm != bm || ct != bt)
3759 public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2, Location loc)
3761 MemberInfo [] miset;
3762 MethodGroupExpr union;
3767 return (MethodGroupExpr) mg2;
3770 return (MethodGroupExpr) mg1;
3773 MethodGroupExpr left_set = null, right_set = null;
3774 int length1 = 0, length2 = 0;
3776 left_set = (MethodGroupExpr) mg1;
3777 length1 = left_set.Methods.Length;
3779 right_set = (MethodGroupExpr) mg2;
3780 length2 = right_set.Methods.Length;
3782 ArrayList common = new ArrayList ();
3784 foreach (MethodBase r in right_set.Methods){
3785 if (TypeManager.ArrayContainsMethod (left_set.Methods, r))
3789 miset = new MemberInfo [length1 + length2 - common.Count];
3790 left_set.Methods.CopyTo (miset, 0);
3794 foreach (MethodBase r in right_set.Methods) {
3795 if (!common.Contains (r))
3799 union = new MethodGroupExpr (miset, mg1.Type, loc);
3804 static Type MoreSpecific (Type p, Type q)
3806 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
3808 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
3811 if (TypeManager.HasElementType (p))
3813 Type pe = TypeManager.GetElementType (p);
3814 Type qe = TypeManager.GetElementType (q);
3815 Type specific = MoreSpecific (pe, qe);
3821 else if (TypeManager.IsGenericType (p))
3823 Type[] pargs = TypeManager.GetTypeArguments (p);
3824 Type[] qargs = TypeManager.GetTypeArguments (q);
3826 bool p_specific_at_least_once = false;
3827 bool q_specific_at_least_once = false;
3829 for (int i = 0; i < pargs.Length; i++)
3831 Type specific = MoreSpecific (pargs [i], qargs [i]);
3832 if (specific == pargs [i])
3833 p_specific_at_least_once = true;
3834 if (specific == qargs [i])
3835 q_specific_at_least_once = true;
3838 if (p_specific_at_least_once && !q_specific_at_least_once)
3840 if (!p_specific_at_least_once && q_specific_at_least_once)
3848 /// Find the Applicable Function Members (7.4.2.1)
3850 /// me: Method Group expression with the members to select.
3851 /// it might contain constructors or methods (or anything
3852 /// that maps to a method).
3854 /// Arguments: ArrayList containing resolved Argument objects.
3856 /// loc: The location if we want an error to be reported, or a Null
3857 /// location for "probing" purposes.
3859 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3860 /// that is the best match of me on Arguments.
3863 public virtual MethodGroupExpr OverloadResolve (EmitContext ec, ArrayList Arguments,
3864 bool may_fail, Location loc)
3866 bool method_params = false;
3867 Type applicable_type = null;
3869 ArrayList candidates = new ArrayList (2);
3870 ArrayList candidate_overrides = null;
3873 // Used to keep a map between the candidate
3874 // and whether it is being considered in its
3875 // normal or expanded form
3877 // false is normal form, true is expanded form
3879 Hashtable candidate_to_form = null;
3881 if (Arguments != null)
3882 arg_count = Arguments.Count;
3884 if (RootContext.Version == LanguageVersion.ISO_1 && Name == "Invoke" && TypeManager.IsDelegateType (DeclaringType)) {
3886 Report.Error (1533, loc, "Invoke cannot be called directly on a delegate");
3890 int nmethods = Methods.Length;
3894 // Methods marked 'override' don't take part in 'applicable_type'
3895 // computation, nor in the actual overload resolution.
3896 // However, they still need to be emitted instead of a base virtual method.
3897 // So, we salt them away into the 'candidate_overrides' array.
3899 // In case of reflected methods, we replace each overriding method with
3900 // its corresponding base virtual method. This is to improve compatibility
3901 // with non-C# libraries which change the visibility of overrides (#75636)
3904 for (int i = 0; i < Methods.Length; ++i) {
3905 MethodBase m = Methods [i];
3906 if (TypeManager.IsOverride (m)) {
3907 if (candidate_overrides == null)
3908 candidate_overrides = new ArrayList ();
3909 candidate_overrides.Add (m);
3910 m = TypeManager.TryGetBaseDefinition (m);
3919 // Enable message recording, it's used mainly by lambda expressions
3921 Report.IMessageRecorder msg_recorder = new Report.MessageRecorder ();
3922 Report.IMessageRecorder prev_recorder = Report.SetMessageRecorder (msg_recorder);
3925 // First we construct the set of applicable methods
3927 bool is_sorted = true;
3928 int best_candidate_rate = int.MaxValue;
3929 for (int i = 0; i < nmethods; i++) {
3930 Type decl_type = Methods [i].DeclaringType;
3933 // If we have already found an applicable method
3934 // we eliminate all base types (Section 14.5.5.1)
3936 if (applicable_type != null && IsAncestralType (decl_type, applicable_type))
3940 // Check if candidate is applicable (section 14.4.2.1)
3942 bool params_expanded_form = false;
3943 int candidate_rate = IsApplicable (ec, Arguments, arg_count, ref Methods [i], ref params_expanded_form);
3945 if (candidate_rate < best_candidate_rate) {
3946 best_candidate_rate = candidate_rate;
3947 best_candidate = Methods [i];
3950 if (params_expanded_form) {
3951 if (candidate_to_form == null)
3952 candidate_to_form = new PtrHashtable ();
3953 MethodBase candidate = Methods [i];
3954 candidate_to_form [candidate] = candidate;
3957 if (candidate_rate != 0) {
3958 if (msg_recorder != null)
3959 msg_recorder.EndSession ();
3963 msg_recorder = null;
3964 candidates.Add (Methods [i]);
3966 if (applicable_type == null)
3967 applicable_type = decl_type;
3968 else if (applicable_type != decl_type) {
3970 if (IsAncestralType (applicable_type, decl_type))
3971 applicable_type = decl_type;
3975 Report.SetMessageRecorder (prev_recorder);
3976 if (msg_recorder != null && msg_recorder.PrintMessages ())
3979 int candidate_top = candidates.Count;
3981 if (applicable_type == null) {
3983 // When we found a top level method which does not match and it's
3984 // not an extension method. We start extension methods lookup from here
3986 if (InstanceExpression != null) {
3987 ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (type, Name);
3988 if (ex_method_lookup != null) {
3989 ex_method_lookup.ExtensionExpression = InstanceExpression;
3990 ex_method_lookup.SetTypeArguments (type_arguments);
3991 return ex_method_lookup.OverloadResolve (ec, Arguments, may_fail, loc);
3999 // Okay so we have failed to find exact match so we
4000 // return error info about the closest match
4002 if (best_candidate != null) {
4003 if (CustomErrorHandler != null) {
4004 if (CustomErrorHandler.NoExactMatch (ec, best_candidate))
4008 ParameterData pd = TypeManager.GetParameterData (best_candidate);
4009 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4010 if (arg_count == pd.Count || pd.HasParams) {
4011 if (TypeManager.IsGenericMethod (best_candidate)) {
4012 if (type_arguments == null) {
4013 Report.Error (411, loc,
4014 "The type arguments for method `{0}' cannot be inferred from " +
4015 "the usage. Try specifying the type arguments explicitly",
4016 TypeManager.CSharpSignature (best_candidate));
4020 Type [] g_args = TypeManager.GetGenericArguments (best_candidate);
4021 if (type_arguments.Count != g_args.Length) {
4022 Report.SymbolRelatedToPreviousError (best_candidate);
4023 Report.Error (305, loc, "Using the generic method `{0}' requires `{1}' type argument(s)",
4024 TypeManager.CSharpSignature (best_candidate),
4025 g_args.Length.ToString ());
4029 if (type_arguments != null) {
4030 Namespace.Error_TypeArgumentsCannotBeUsed (best_candidate, loc);
4035 if (VerifyArgumentsCompat (ec, Arguments, arg_count, best_candidate, cand_params, may_fail, loc))
4036 throw new InternalErrorException ("Overload verification expected failure");
4041 if (almost_matched_members.Count != 0) {
4042 Error_MemberLookupFailed (ec.ContainerType, type, type, ".ctor",
4043 null, MemberTypes.Constructor, AllBindingFlags);
4048 // We failed to find any method with correct argument count
4050 if (Name == ConstructorInfo.ConstructorName) {
4051 Report.SymbolRelatedToPreviousError (type);
4052 Report.Error (1729, loc,
4053 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4054 TypeManager.CSharpName (type), arg_count);
4056 Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4057 Name, arg_count.ToString ());
4065 // At this point, applicable_type is _one_ of the most derived types
4066 // in the set of types containing the methods in this MethodGroup.
4067 // Filter the candidates so that they only contain methods from the
4068 // most derived types.
4071 int finalized = 0; // Number of finalized candidates
4074 // Invariant: applicable_type is a most derived type
4076 // We'll try to complete Section 14.5.5.1 for 'applicable_type' by
4077 // eliminating all it's base types. At the same time, we'll also move
4078 // every unrelated type to the end of the array, and pick the next
4079 // 'applicable_type'.
4081 Type next_applicable_type = null;
4082 int j = finalized; // where to put the next finalized candidate
4083 int k = finalized; // where to put the next undiscarded candidate
4084 for (int i = finalized; i < candidate_top; ++i) {
4085 MethodBase candidate = (MethodBase) candidates [i];
4086 Type decl_type = candidate.DeclaringType;
4088 if (decl_type == applicable_type) {
4089 candidates [k++] = candidates [j];
4090 candidates [j++] = candidates [i];
4094 if (IsAncestralType (decl_type, applicable_type))
4097 if (next_applicable_type != null &&
4098 IsAncestralType (decl_type, next_applicable_type))
4101 candidates [k++] = candidates [i];
4103 if (next_applicable_type == null ||
4104 IsAncestralType (next_applicable_type, decl_type))
4105 next_applicable_type = decl_type;
4108 applicable_type = next_applicable_type;
4111 } while (applicable_type != null);
4115 // Now we actually find the best method
4118 best_candidate = (MethodBase) candidates [0];
4119 method_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4120 for (int ix = 1; ix < candidate_top; ix++) {
4121 MethodBase candidate = (MethodBase) candidates [ix];
4123 if (candidate == best_candidate)
4126 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4128 if (BetterFunction (ec, Arguments, arg_count,
4129 candidate, cand_params,
4130 best_candidate, method_params)) {
4131 best_candidate = candidate;
4132 method_params = cand_params;
4136 // Now check that there are no ambiguities i.e the selected method
4137 // should be better than all the others
4139 MethodBase ambiguous = null;
4140 for (int ix = 0; ix < candidate_top; ix++) {
4141 MethodBase candidate = (MethodBase) candidates [ix];
4143 if (candidate == best_candidate)
4146 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4147 if (!BetterFunction (ec, Arguments, arg_count,
4148 best_candidate, method_params,
4149 candidate, cand_params))
4152 Report.SymbolRelatedToPreviousError (candidate);
4153 ambiguous = candidate;
4157 if (ambiguous != null) {
4158 Report.SymbolRelatedToPreviousError (best_candidate);
4159 Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4160 TypeManager.CSharpSignature (ambiguous), TypeManager.CSharpSignature (best_candidate));
4165 // If the method is a virtual function, pick an override closer to the LHS type.
4167 if (!IsBase && best_candidate.IsVirtual) {
4168 if (TypeManager.IsOverride (best_candidate))
4169 throw new InternalErrorException (
4170 "Should not happen. An 'override' method took part in overload resolution: " + best_candidate);
4172 if (candidate_overrides != null) {
4173 Type[] gen_args = null;
4174 bool gen_override = false;
4175 if (TypeManager.IsGenericMethod (best_candidate))
4176 gen_args = TypeManager.GetGenericArguments (best_candidate);
4178 foreach (MethodBase candidate in candidate_overrides) {
4179 if (TypeManager.IsGenericMethod (candidate)) {
4180 if (gen_args == null)
4183 if (gen_args.Length != TypeManager.GetGenericArguments (candidate).Length)
4186 if (gen_args != null)
4190 if (IsOverride (candidate, best_candidate)) {
4191 gen_override = true;
4192 best_candidate = candidate;
4196 if (gen_override && gen_args != null) {
4198 best_candidate = ((MethodInfo) best_candidate).MakeGenericMethod (gen_args);
4205 // And now check if the arguments are all
4206 // compatible, perform conversions if
4207 // necessary etc. and return if everything is
4210 if (!VerifyArgumentsCompat (ec, Arguments, arg_count, best_candidate,
4211 method_params, may_fail, loc))
4214 if (best_candidate == null)
4217 MethodBase the_method = TypeManager.DropGenericMethodArguments (best_candidate);
4219 if (the_method.IsGenericMethodDefinition &&
4220 !ConstraintChecker.CheckConstraints (ec, the_method, best_candidate, loc))
4224 IMethodData data = TypeManager.GetMethod (the_method);
4226 data.SetMemberIsUsed ();
4231 public override void SetTypeArguments (TypeArguments ta)
4233 type_arguments = ta;
4236 public bool VerifyArgumentsCompat (EmitContext ec, ArrayList arguments,
4237 int arg_count, MethodBase method,
4238 bool chose_params_expanded,
4239 bool may_fail, Location loc)
4241 ParameterData pd = TypeManager.GetParameterData (method);
4243 int errors = Report.Errors;
4244 Parameter.Modifier p_mod = 0;
4248 for (; a_idx < arg_count; a_idx++) {
4249 a = (Argument) arguments [a_idx];
4250 if (p_mod != Parameter.Modifier.PARAMS) {
4251 p_mod = pd.ParameterModifier (a_idx);
4252 pt = pd.ParameterType (a_idx);
4254 if (p_mod == Parameter.Modifier.ARGLIST) {
4255 if (a.Type != TypeManager.runtime_argument_handle_type)
4260 if (pt.IsPointer && !ec.InUnsafe) {
4267 if (p_mod == Parameter.Modifier.PARAMS) {
4268 if (chose_params_expanded)
4269 pt = TypeManager.GetElementType (pt);
4270 } else if (p_mod != 0) {
4271 pt = TypeManager.GetElementType (pt);
4276 // Types have to be identical when ref or out modifer is used
4278 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4279 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4282 if (!TypeManager.IsEqual (a.Expr.Type, pt))
4288 if (TypeManager.IsEqual (a.Type, pt))
4291 Expression conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4295 if (!chose_params_expanded && (p_mod & Parameter.Modifier.PARAMS) != 0 && a.Type == TypeManager.null_type)
4296 conv.Type = pd.ParameterType (a_idx);
4298 // Update the argument with the implicit conversion
4302 if (a_idx == arg_count)
4305 if (!may_fail && Report.Errors == errors)
4306 Error_InvalidArguments (ec, loc, a_idx, method, a, pd, pt);
4311 public class ConstantExpr : MemberExpr
4315 public ConstantExpr (FieldInfo constant, Location loc)
4317 this.constant = constant;
4321 public override string Name {
4322 get { throw new NotImplementedException (); }
4325 public override bool IsInstance {
4326 get { return !IsStatic; }
4329 public override bool IsStatic {
4330 get { return constant.IsStatic; }
4333 public override Type DeclaringType {
4334 get { return constant.DeclaringType; }
4337 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc, SimpleName original)
4339 constant = TypeManager.GetGenericFieldDefinition (constant);
4341 IConstant ic = TypeManager.GetConstant (constant);
4343 if (constant.IsLiteral) {
4344 ic = new ExternalConstant (constant);
4346 ic = ExternalConstant.CreateDecimal (constant);
4347 // HACK: decimal field was not resolved as constant
4349 return new FieldExpr (constant, loc).ResolveMemberAccess (ec, left, loc, original);
4351 TypeManager.RegisterConstant (constant, ic);
4354 return base.ResolveMemberAccess (ec, left, loc, original);
4357 public override Expression DoResolve (EmitContext ec)
4359 IConstant ic = TypeManager.GetConstant (constant);
4360 if (ic.ResolveValue ()) {
4361 if (!ec.IsInObsoleteScope)
4362 ic.CheckObsoleteness (loc);
4365 return ic.CreateConstantReference (loc);
4368 public override void Emit (EmitContext ec)
4370 throw new NotSupportedException ();
4373 public override string GetSignatureForError ()
4375 return TypeManager.GetFullNameSignature (constant);
4380 /// Fully resolved expression that evaluates to a Field
4382 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariable {
4383 public readonly FieldInfo FieldInfo;
4384 VariableInfo variable_info;
4386 LocalTemporary temp;
4388 bool in_initializer;
4390 public FieldExpr (FieldInfo fi, Location l, bool in_initializer):
4393 this.in_initializer = in_initializer;
4396 public FieldExpr (FieldInfo fi, Location l)
4399 eclass = ExprClass.Variable;
4400 type = TypeManager.TypeToCoreType (fi.FieldType);
4404 public override string Name {
4406 return FieldInfo.Name;
4410 public override bool IsInstance {
4412 return !FieldInfo.IsStatic;
4416 public override bool IsStatic {
4418 return FieldInfo.IsStatic;
4422 public override Type DeclaringType {
4424 return FieldInfo.DeclaringType;
4428 public override string GetSignatureForError ()
4430 return TypeManager.GetFullNameSignature (FieldInfo);
4433 public VariableInfo VariableInfo {
4435 return variable_info;
4439 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
4440 SimpleName original)
4442 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
4443 Type t = fi.FieldType;
4445 if (t.IsPointer && !ec.InUnsafe) {
4449 return base.ResolveMemberAccess (ec, left, loc, original);
4452 override public Expression DoResolve (EmitContext ec)
4454 return DoResolve (ec, false, false);
4457 Expression DoResolve (EmitContext ec, bool lvalue_instance, bool out_access)
4459 if (!FieldInfo.IsStatic){
4460 if (InstanceExpression == null){
4462 // This can happen when referencing an instance field using
4463 // a fully qualified type expression: TypeName.InstanceField = xxx
4465 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4469 // Resolve the field's instance expression while flow analysis is turned
4470 // off: when accessing a field "a.b", we must check whether the field
4471 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4473 if (lvalue_instance) {
4474 using (ec.With (EmitContext.Flags.DoFlowAnalysis, false)) {
4475 Expression right_side =
4476 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4477 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side, loc);
4480 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
4481 InstanceExpression = InstanceExpression.Resolve (ec, rf);
4484 if (InstanceExpression == null)
4487 using (ec.Set (EmitContext.Flags.OmitStructFlowAnalysis)) {
4488 InstanceExpression.CheckMarshalByRefAccess (ec);
4492 if (!in_initializer && !ec.IsInFieldInitializer) {
4493 ObsoleteAttribute oa;
4494 FieldBase f = TypeManager.GetField (FieldInfo);
4496 if (!ec.IsInObsoleteScope)
4497 f.CheckObsoleteness (loc);
4499 // To be sure that type is external because we do not register generated fields
4500 } else if (!(FieldInfo.DeclaringType is TypeBuilder)) {
4501 oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
4503 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
4507 AnonymousContainer am = ec.CurrentAnonymousMethod;
4509 if (!FieldInfo.IsStatic){
4510 if (!am.IsIterator && (ec.TypeContainer is Struct)){
4511 Report.Error (1673, loc,
4512 "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",
4519 IFixedBuffer fb = AttributeTester.GetFixedBuffer (FieldInfo);
4521 if (!ec.InFixedInitializer && ec.ContainerType.IsValueType) {
4522 Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4525 if (InstanceExpression.eclass != ExprClass.Variable) {
4526 Report.SymbolRelatedToPreviousError (FieldInfo);
4527 Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4528 TypeManager.GetFullNameSignature (FieldInfo));
4531 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4534 // If the instance expression is a local variable or parameter.
4535 IVariable var = InstanceExpression as IVariable;
4536 if ((var == null) || (var.VariableInfo == null))
4539 VariableInfo vi = var.VariableInfo;
4540 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
4543 variable_info = vi.GetSubStruct (FieldInfo.Name);
4547 static readonly int [] codes = {
4548 191, // instance, write access
4549 192, // instance, out access
4550 198, // static, write access
4551 199, // static, out access
4552 1648, // member of value instance, write access
4553 1649, // member of value instance, out access
4554 1650, // member of value static, write access
4555 1651 // member of value static, out access
4558 static readonly string [] msgs = {
4559 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4560 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4561 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4562 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4563 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4564 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4565 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4566 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4569 // The return value is always null. Returning a value simplifies calling code.
4570 Expression Report_AssignToReadonly (Expression right_side)
4573 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4577 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4579 Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4584 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4586 IVariable var = InstanceExpression as IVariable;
4587 if ((var != null) && (var.VariableInfo != null))
4588 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
4590 bool lvalue_instance = !FieldInfo.IsStatic && FieldInfo.DeclaringType.IsValueType;
4591 bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
4593 Expression e = DoResolve (ec, lvalue_instance, out_access);
4598 FieldBase fb = TypeManager.GetField (FieldInfo);
4602 if (FieldInfo.IsInitOnly) {
4603 // InitOnly fields can only be assigned in constructors or initializers
4604 if (!ec.IsInFieldInitializer && !ec.IsConstructor)
4605 return Report_AssignToReadonly (right_side);
4607 if (ec.IsConstructor) {
4608 Type ctype = ec.TypeContainer.CurrentType;
4610 ctype = ec.ContainerType;
4612 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4613 if (!TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
4614 return Report_AssignToReadonly (right_side);
4615 // static InitOnly fields cannot be assigned-to in an instance constructor
4616 if (IsStatic && !ec.IsStatic)
4617 return Report_AssignToReadonly (right_side);
4618 // instance constructors can't modify InitOnly fields of other instances of the same type
4619 if (!IsStatic && !(InstanceExpression is This))
4620 return Report_AssignToReadonly (right_side);
4624 if (right_side == EmptyExpression.OutAccess &&
4625 !IsStatic && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
4626 Report.SymbolRelatedToPreviousError (DeclaringType);
4627 Report.Warning (197, 1, loc,
4628 "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",
4629 GetSignatureForError ());
4635 public override void CheckMarshalByRefAccess (EmitContext ec)
4637 if (!IsStatic && Type.IsValueType && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
4638 Report.SymbolRelatedToPreviousError (DeclaringType);
4639 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",
4640 GetSignatureForError ());
4644 public bool VerifyFixed ()
4646 IVariable variable = InstanceExpression as IVariable;
4647 // A variable of the form V.I is fixed when V is a fixed variable of a struct type.
4648 // We defer the InstanceExpression check after the variable check to avoid a
4649 // separate null check on InstanceExpression.
4650 return variable != null && InstanceExpression.Type.IsValueType && variable.VerifyFixed ();
4653 public override int GetHashCode ()
4655 return FieldInfo.GetHashCode ();
4658 public override bool Equals (object obj)
4660 FieldExpr fe = obj as FieldExpr;
4664 if (FieldInfo != fe.FieldInfo)
4667 if (InstanceExpression == null || fe.InstanceExpression == null)
4670 return InstanceExpression.Equals (fe.InstanceExpression);
4673 public void Emit (EmitContext ec, bool leave_copy)
4675 ILGenerator ig = ec.ig;
4676 bool is_volatile = false;
4678 FieldBase f = TypeManager.GetField (FieldInfo);
4680 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4683 f.SetMemberIsUsed ();
4686 if (FieldInfo.IsStatic){
4688 ig.Emit (OpCodes.Volatile);
4690 ig.Emit (OpCodes.Ldsfld, FieldInfo);
4693 EmitInstance (ec, false);
4695 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
4697 ig.Emit (OpCodes.Ldflda, FieldInfo);
4698 ig.Emit (OpCodes.Ldflda, ff.Element);
4701 ig.Emit (OpCodes.Volatile);
4703 ig.Emit (OpCodes.Ldfld, FieldInfo);
4708 ec.ig.Emit (OpCodes.Dup);
4709 if (!FieldInfo.IsStatic) {
4710 temp = new LocalTemporary (this.Type);
4716 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4718 FieldAttributes fa = FieldInfo.Attributes;
4719 bool is_static = (fa & FieldAttributes.Static) != 0;
4720 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
4721 ILGenerator ig = ec.ig;
4723 if (is_readonly && !ec.IsConstructor){
4724 Report_AssignToReadonly (source);
4729 // String concatenation creates a new string instance
4731 prepared = prepare_for_load && !(source is StringConcat);
4732 EmitInstance (ec, prepared);
4736 ec.ig.Emit (OpCodes.Dup);
4737 if (!FieldInfo.IsStatic) {
4738 temp = new LocalTemporary (this.Type);
4743 FieldBase f = TypeManager.GetField (FieldInfo);
4745 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4746 ig.Emit (OpCodes.Volatile);
4752 ig.Emit (OpCodes.Stsfld, FieldInfo);
4754 ig.Emit (OpCodes.Stfld, FieldInfo);
4762 public override void Emit (EmitContext ec)
4767 public void AddressOf (EmitContext ec, AddressOp mode)
4769 ILGenerator ig = ec.ig;
4771 FieldBase f = TypeManager.GetField (FieldInfo);
4773 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
4774 Report.Warning (420, 1, loc, "`{0}': A volatile field references will not be treated as volatile",
4775 f.GetSignatureForError ());
4778 if ((mode & AddressOp.Store) != 0)
4780 if ((mode & AddressOp.Load) != 0)
4781 f.SetMemberIsUsed ();
4785 // Handle initonly fields specially: make a copy and then
4786 // get the address of the copy.
4789 if (FieldInfo.IsInitOnly){
4791 if (ec.IsConstructor){
4792 if (FieldInfo.IsStatic){
4804 local = ig.DeclareLocal (type);
4805 ig.Emit (OpCodes.Stloc, local);
4806 ig.Emit (OpCodes.Ldloca, local);
4811 if (FieldInfo.IsStatic){
4812 ig.Emit (OpCodes.Ldsflda, FieldInfo);
4815 EmitInstance (ec, false);
4816 ig.Emit (OpCodes.Ldflda, FieldInfo);
4823 /// Expression that evaluates to a Property. The Assign class
4824 /// might set the `Value' expression if we are in an assignment.
4826 /// This is not an LValue because we need to re-write the expression, we
4827 /// can not take data from the stack and store it.
4829 public class PropertyExpr : MemberExpr, IAssignMethod {
4830 public readonly PropertyInfo PropertyInfo;
4831 MethodInfo getter, setter;
4836 LocalTemporary temp;
4839 public PropertyExpr (Type container_type, PropertyInfo pi, Location l)
4842 eclass = ExprClass.PropertyAccess;
4846 type = TypeManager.TypeToCoreType (pi.PropertyType);
4848 ResolveAccessors (container_type);
4851 public override string Name {
4853 return PropertyInfo.Name;
4857 public override bool IsInstance {
4863 public override bool IsStatic {
4869 public override Type DeclaringType {
4871 return PropertyInfo.DeclaringType;
4875 public override string GetSignatureForError ()
4877 return TypeManager.GetFullNameSignature (PropertyInfo);
4880 void FindAccessors (Type invocation_type)
4882 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
4883 BindingFlags.Static | BindingFlags.Instance |
4884 BindingFlags.DeclaredOnly;
4886 Type current = PropertyInfo.DeclaringType;
4887 for (; current != null; current = current.BaseType) {
4888 MemberInfo[] group = TypeManager.MemberLookup (
4889 invocation_type, invocation_type, current,
4890 MemberTypes.Property, flags, PropertyInfo.Name, null);
4895 if (group.Length != 1)
4896 // Oooops, can this ever happen ?
4899 PropertyInfo pi = (PropertyInfo) group [0];
4902 getter = pi.GetGetMethod (true);
4905 setter = pi.GetSetMethod (true);
4907 MethodInfo accessor = getter != null ? getter : setter;
4909 if (!accessor.IsVirtual)
4915 // We also perform the permission checking here, as the PropertyInfo does not
4916 // hold the information for the accessibility of its setter/getter
4918 // TODO: Refactor to use some kind of cache together with GetPropertyFromAccessor
4919 void ResolveAccessors (Type container_type)
4921 FindAccessors (container_type);
4923 if (getter != null) {
4924 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
4925 IMethodData md = TypeManager.GetMethod (the_getter);
4927 md.SetMemberIsUsed ();
4929 is_static = getter.IsStatic;
4932 if (setter != null) {
4933 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
4934 IMethodData md = TypeManager.GetMethod (the_setter);
4936 md.SetMemberIsUsed ();
4938 is_static = setter.IsStatic;
4942 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
4945 InstanceExpression = null;
4949 if (InstanceExpression == null) {
4950 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4954 InstanceExpression = InstanceExpression.DoResolve (ec);
4955 if (lvalue_instance && InstanceExpression != null)
4956 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
4958 if (InstanceExpression == null)
4961 InstanceExpression.CheckMarshalByRefAccess (ec);
4963 if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) &&
4964 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
4965 !TypeManager.IsNestedChildOf (ec.ContainerType, InstanceExpression.Type) &&
4966 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.ContainerType)) {
4967 Report.SymbolRelatedToPreviousError (PropertyInfo);
4968 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
4975 void Error_PropertyNotFound (MethodInfo mi, bool getter)
4977 // TODO: correctly we should compare arguments but it will lead to bigger changes
4978 if (mi is MethodBuilder) {
4979 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
4983 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
4985 ParameterData iparams = TypeManager.GetParameterData (mi);
4986 sig.Append (getter ? "get_" : "set_");
4988 sig.Append (iparams.GetSignatureForError ());
4990 Report.SymbolRelatedToPreviousError (mi);
4991 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
4992 Name, sig.ToString ());
4995 public bool IsAccessibleFrom (Type invocation_type, bool lvalue)
4998 MethodInfo accessor = lvalue ? setter : getter;
4999 if (accessor == null && lvalue)
5001 return accessor != null && IsAccessorAccessible (invocation_type, accessor, out dummy);
5004 override public Expression DoResolve (EmitContext ec)
5009 if (getter != null){
5010 if (TypeManager.GetParameterData (getter).Count != 0){
5011 Error_PropertyNotFound (getter, true);
5016 if (getter == null){
5018 // The following condition happens if the PropertyExpr was
5019 // created, but is invalid (ie, the property is inaccessible),
5020 // and we did not want to embed the knowledge about this in
5021 // the caller routine. This only avoids double error reporting.
5026 if (InstanceExpression != EmptyExpression.Null) {
5027 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5028 TypeManager.GetFullNameSignature (PropertyInfo));
5033 bool must_do_cs1540_check = false;
5034 if (getter != null &&
5035 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
5036 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
5037 if (pm != null && pm.HasCustomAccessModifier) {
5038 Report.SymbolRelatedToPreviousError (pm);
5039 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5040 TypeManager.CSharpSignature (getter));
5043 Report.SymbolRelatedToPreviousError (getter);
5044 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
5049 if (!InstanceResolve (ec, false, must_do_cs1540_check))
5053 // Only base will allow this invocation to happen.
5055 if (IsBase && getter.IsAbstract) {
5056 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5060 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
5070 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
5072 if (right_side == EmptyExpression.OutAccess) {
5073 if (ec.CurrentBlock.Toplevel.GetTransparentIdentifier (PropertyInfo.Name) != null) {
5074 Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5077 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as `ref' or `out' parameter",
5078 GetSignatureForError ());
5083 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5084 Error_CannotModifyIntermediateExpressionValue (ec);
5087 if (setter == null){
5089 // The following condition happens if the PropertyExpr was
5090 // created, but is invalid (ie, the property is inaccessible),
5091 // and we did not want to embed the knowledge about this in
5092 // the caller routine. This only avoids double error reporting.
5096 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
5097 GetSignatureForError ());
5101 if (TypeManager.GetParameterData (setter).Count != 1){
5102 Error_PropertyNotFound (setter, false);
5106 bool must_do_cs1540_check;
5107 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
5108 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
5109 if (pm != null && pm.HasCustomAccessModifier) {
5110 Report.SymbolRelatedToPreviousError (pm);
5111 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5112 TypeManager.CSharpSignature (setter));
5115 Report.SymbolRelatedToPreviousError (setter);
5116 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
5121 if (!InstanceResolve (ec, PropertyInfo.DeclaringType.IsValueType, must_do_cs1540_check))
5125 // Only base will allow this invocation to happen.
5127 if (IsBase && setter.IsAbstract){
5128 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5135 public override void Emit (EmitContext ec)
5140 public void Emit (EmitContext ec, bool leave_copy)
5143 // Special case: length of single dimension array property is turned into ldlen
5145 if ((getter == TypeManager.system_int_array_get_length) ||
5146 (getter == TypeManager.int_array_get_length)){
5147 Type iet = InstanceExpression.Type;
5150 // System.Array.Length can be called, but the Type does not
5151 // support invoking GetArrayRank, so test for that case first
5153 if (iet != TypeManager.array_type && (iet.GetArrayRank () == 1)) {
5155 EmitInstance (ec, false);
5156 ec.ig.Emit (OpCodes.Ldlen);
5157 ec.ig.Emit (OpCodes.Conv_I4);
5162 Invocation.EmitCall (ec, IsBase, InstanceExpression, getter, null, loc, prepared, false);
5165 ec.ig.Emit (OpCodes.Dup);
5167 temp = new LocalTemporary (this.Type);
5174 // Implements the IAssignMethod interface for assignments
5176 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5178 Expression my_source = source;
5180 if (prepare_for_load) {
5181 if (source is StringConcat)
5182 EmitInstance (ec, false);
5190 ec.ig.Emit (OpCodes.Dup);
5192 temp = new LocalTemporary (this.Type);
5196 } else if (leave_copy) {
5198 temp = new LocalTemporary (this.Type);
5203 ArrayList args = new ArrayList (1);
5204 args.Add (new Argument (my_source, Argument.AType.Expression));
5206 Invocation.EmitCall (ec, IsBase, InstanceExpression, setter, args, loc, false, prepared);
5216 /// Fully resolved expression that evaluates to an Event
5218 public class EventExpr : MemberExpr {
5219 public readonly EventInfo EventInfo;
5222 MethodInfo add_accessor, remove_accessor;
5224 public EventExpr (EventInfo ei, Location loc)
5228 eclass = ExprClass.EventAccess;
5230 add_accessor = TypeManager.GetAddMethod (ei);
5231 remove_accessor = TypeManager.GetRemoveMethod (ei);
5232 if (add_accessor.IsStatic || remove_accessor.IsStatic)
5235 if (EventInfo is MyEventBuilder){
5236 MyEventBuilder eb = (MyEventBuilder) EventInfo;
5237 type = eb.EventType;
5240 type = EventInfo.EventHandlerType;
5243 public override string Name {
5245 return EventInfo.Name;
5249 public override bool IsInstance {
5255 public override bool IsStatic {
5261 public override Type DeclaringType {
5263 return EventInfo.DeclaringType;
5267 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
5268 SimpleName original)
5271 // If the event is local to this class, we transform ourselves into a FieldExpr
5274 if (EventInfo.DeclaringType == ec.ContainerType ||
5275 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
5276 EventField mi = TypeManager.GetEventField (EventInfo);
5279 if (!ec.IsInObsoleteScope)
5280 mi.CheckObsoleteness (loc);
5282 FieldExpr ml = new FieldExpr (mi.FieldBuilder, loc);
5284 InstanceExpression = null;
5286 return ml.ResolveMemberAccess (ec, left, loc, original);
5290 return base.ResolveMemberAccess (ec, left, loc, original);
5294 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
5297 InstanceExpression = null;
5301 if (InstanceExpression == null) {
5302 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5306 InstanceExpression = InstanceExpression.DoResolve (ec);
5307 if (InstanceExpression == null)
5310 if (IsBase && add_accessor.IsAbstract) {
5311 Error_CannotCallAbstractBase(TypeManager.CSharpSignature(add_accessor));
5316 // This is using the same mechanism as the CS1540 check in PropertyExpr.
5317 // However, in the Event case, we reported a CS0122 instead.
5319 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
5320 InstanceExpression.Type != ec.ContainerType &&
5321 ec.ContainerType.IsSubclassOf (InstanceExpression.Type)) {
5322 Report.SymbolRelatedToPreviousError (EventInfo);
5323 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5330 public bool IsAccessibleFrom (Type invocation_type)
5333 return IsAccessorAccessible (invocation_type, add_accessor, out dummy) &&
5334 IsAccessorAccessible (invocation_type, remove_accessor, out dummy);
5337 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5339 return DoResolve (ec);
5342 public override Expression DoResolve (EmitContext ec)
5344 bool must_do_cs1540_check;
5345 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
5346 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
5347 Report.SymbolRelatedToPreviousError (EventInfo);
5348 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5352 if (!InstanceResolve (ec, must_do_cs1540_check))
5358 public override void Emit (EmitContext ec)
5360 if (InstanceExpression is This)
5361 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of += or -=", GetSignatureForError ());
5363 Report.Error (70, loc, "The event `{0}' can only appear on the left hand side of += or -= "+
5364 "(except on the defining type)", Name);
5367 public override string GetSignatureForError ()
5369 return TypeManager.CSharpSignature (EventInfo);
5372 public void EmitAddOrRemove (EmitContext ec, Expression source)
5374 BinaryDelegate source_del = source as BinaryDelegate;
5375 if (source_del == null) {
5379 Expression handler = source_del.Right;
5381 Argument arg = new Argument (handler, Argument.AType.Expression);
5382 ArrayList args = new ArrayList ();
5386 if (source_del.IsAddition)
5387 Invocation.EmitCall (
5388 ec, IsBase, InstanceExpression, add_accessor, args, loc);
5390 Invocation.EmitCall (
5391 ec, IsBase, InstanceExpression, remove_accessor, args, loc);
5395 public class TemporaryVariable : Expression, IMemoryLocation
5400 public TemporaryVariable (Type type, Location loc)
5404 eclass = ExprClass.Value;
5407 public override Expression DoResolve (EmitContext ec)
5412 TypeExpr te = new TypeExpression (type, loc);
5413 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
5414 if (!li.Resolve (ec))
5417 if (ec.MustCaptureVariable (li)) {
5418 ScopeInfo scope = li.Block.CreateScopeInfo ();
5419 var = scope.AddLocal (li);
5426 public Variable Variable {
5427 get { return var != null ? var : li.Variable; }
5430 public override void Emit (EmitContext ec)
5432 Variable.EmitInstance (ec);
5436 public void EmitLoadAddress (EmitContext ec)
5438 Variable.EmitInstance (ec);
5439 Variable.EmitAddressOf (ec);
5442 public void Store (EmitContext ec, Expression right_side)
5444 Variable.EmitInstance (ec);
5445 right_side.Emit (ec);
5446 Variable.EmitAssign (ec);
5449 public void EmitThis (EmitContext ec)
5451 Variable.EmitInstance (ec);
5454 public void EmitStore (EmitContext ec)
5456 Variable.EmitAssign (ec);
5459 public void AddressOf (EmitContext ec, AddressOp mode)
5461 EmitLoadAddress (ec);
5466 /// Handles `var' contextual keyword; var becomes a keyword only
5467 /// if no type called var exists in a variable scope
5469 public class VarExpr : SimpleName
5471 // Used for error reporting only
5472 ArrayList initializer;
5474 public VarExpr (Location loc)
5479 public ArrayList VariableInitializer {
5481 this.initializer = value;
5485 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5488 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
5490 type = right_side.Type;
5491 if (type == TypeManager.null_type || type == TypeManager.void_type || type == TypeManager.anonymous_method_type) {
5492 Report.Error (815, loc, "An implicitly typed local variable declaration cannot be initialized with `{0}'",
5493 right_side.GetSignatureForError ());
5497 eclass = ExprClass.Variable;
5501 protected override void Error_TypeOrNamespaceNotFound (IResolveContext ec)
5503 Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");
5506 public override TypeExpr ResolveAsContextualType (IResolveContext rc, bool silent)
5508 TypeExpr te = base.ResolveAsContextualType (rc, true);
5512 if (initializer == null)
5515 if (initializer.Count > 1) {
5516 Location loc = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [1]).Location;
5517 Report.Error (819, loc, "An implicitly typed local variable declaration cannot include multiple declarators");
5522 Expression variable_initializer = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [0]).expression_or_array_initializer;
5523 if (variable_initializer == null) {
5524 Report.Error (818, loc, "An implicitly typed local variable declarator must include an initializer");