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);
891 protected virtual void Error_NegativeArrayIndex (Location loc)
893 throw new NotImplementedException ();
897 /// Returns an expression that can be used to invoke operator true
898 /// on the expression if it exists.
900 static public Expression GetOperatorTrue (EmitContext ec, Expression e, Location loc)
902 return GetOperatorTrueOrFalse (ec, e, true, loc);
906 /// Returns an expression that can be used to invoke operator false
907 /// on the expression if it exists.
909 static public Expression GetOperatorFalse (EmitContext ec, Expression e, Location loc)
911 return GetOperatorTrueOrFalse (ec, e, false, loc);
914 static Expression GetOperatorTrueOrFalse (EmitContext ec, Expression e, bool is_true, Location loc)
916 MethodGroupExpr operator_group;
919 if (TypeManager.IsNullableType (e.Type))
920 return new Nullable.OperatorTrueOrFalse (e, is_true, loc).Resolve (ec);
923 operator_group = MethodLookup (ec.ContainerType, e.Type, is_true ? "op_True" : "op_False", loc) as MethodGroupExpr;
924 if (operator_group == null)
927 ArrayList arguments = new ArrayList (1);
928 arguments.Add (new Argument (e, Argument.AType.Expression));
929 operator_group = operator_group.OverloadResolve (
930 ec, arguments, false, loc);
932 if (operator_group == null)
935 return new StaticCallExpr ((MethodInfo) operator_group, arguments, loc);
939 /// Resolves the expression `e' into a boolean expression: either through
940 /// an implicit conversion, or through an `operator true' invocation
942 public static Expression ResolveBoolean (EmitContext ec, Expression e, Location loc)
948 if (e.Type == TypeManager.bool_type)
951 Expression converted = Convert.ImplicitConversion (ec, e, TypeManager.bool_type, Location.Null);
953 if (converted != null)
957 // If no implicit conversion to bool exists, try using `operator true'
959 converted = Expression.GetOperatorTrue (ec, e, loc);
960 if (converted == null){
961 e.Error_ValueCannotBeConverted (ec, loc, TypeManager.bool_type, false);
967 public virtual string ExprClassName
971 case ExprClass.Invalid:
973 case ExprClass.Value:
975 case ExprClass.Variable:
977 case ExprClass.Namespace:
981 case ExprClass.MethodGroup:
982 return "method group";
983 case ExprClass.PropertyAccess:
984 return "property access";
985 case ExprClass.EventAccess:
986 return "event access";
987 case ExprClass.IndexerAccess:
988 return "indexer access";
989 case ExprClass.Nothing:
992 throw new Exception ("Should not happen");
997 /// Reports that we were expecting `expr' to be of class `expected'
999 public void Error_UnexpectedKind (DeclSpace ds, string expected, Location loc)
1001 Error_UnexpectedKind (ds, expected, ExprClassName, loc);
1004 public void Error_UnexpectedKind (DeclSpace ds, string expected, string was, Location loc)
1006 string name = GetSignatureForError ();
1008 name = ds.GetSignatureForError () + '.' + name;
1010 Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
1011 name, was, expected);
1014 public void Error_UnexpectedKind (ResolveFlags flags, Location loc)
1016 string [] valid = new string [4];
1019 if ((flags & ResolveFlags.VariableOrValue) != 0) {
1020 valid [count++] = "variable";
1021 valid [count++] = "value";
1024 if ((flags & ResolveFlags.Type) != 0)
1025 valid [count++] = "type";
1027 if ((flags & ResolveFlags.MethodGroup) != 0)
1028 valid [count++] = "method group";
1031 valid [count++] = "unknown";
1033 StringBuilder sb = new StringBuilder (valid [0]);
1034 for (int i = 1; i < count - 1; i++) {
1036 sb.Append (valid [i]);
1039 sb.Append ("' or `");
1040 sb.Append (valid [count - 1]);
1043 Report.Error (119, loc,
1044 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1047 public static void UnsafeError (Location loc)
1049 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1053 // Load the object from the pointer.
1055 public static void LoadFromPtr (ILGenerator ig, Type t)
1057 if (t == TypeManager.int32_type)
1058 ig.Emit (OpCodes.Ldind_I4);
1059 else if (t == TypeManager.uint32_type)
1060 ig.Emit (OpCodes.Ldind_U4);
1061 else if (t == TypeManager.short_type)
1062 ig.Emit (OpCodes.Ldind_I2);
1063 else if (t == TypeManager.ushort_type)
1064 ig.Emit (OpCodes.Ldind_U2);
1065 else if (t == TypeManager.char_type)
1066 ig.Emit (OpCodes.Ldind_U2);
1067 else if (t == TypeManager.byte_type)
1068 ig.Emit (OpCodes.Ldind_U1);
1069 else if (t == TypeManager.sbyte_type)
1070 ig.Emit (OpCodes.Ldind_I1);
1071 else if (t == TypeManager.uint64_type)
1072 ig.Emit (OpCodes.Ldind_I8);
1073 else if (t == TypeManager.int64_type)
1074 ig.Emit (OpCodes.Ldind_I8);
1075 else if (t == TypeManager.float_type)
1076 ig.Emit (OpCodes.Ldind_R4);
1077 else if (t == TypeManager.double_type)
1078 ig.Emit (OpCodes.Ldind_R8);
1079 else if (t == TypeManager.bool_type)
1080 ig.Emit (OpCodes.Ldind_I1);
1081 else if (t == TypeManager.intptr_type)
1082 ig.Emit (OpCodes.Ldind_I);
1083 else if (TypeManager.IsEnumType (t)) {
1084 if (t == TypeManager.enum_type)
1085 ig.Emit (OpCodes.Ldind_Ref);
1087 LoadFromPtr (ig, TypeManager.EnumToUnderlying (t));
1088 } else if (t.IsValueType || TypeManager.IsGenericParameter (t))
1089 ig.Emit (OpCodes.Ldobj, t);
1090 else if (t.IsPointer)
1091 ig.Emit (OpCodes.Ldind_I);
1093 ig.Emit (OpCodes.Ldind_Ref);
1097 // The stack contains the pointer and the value of type `type'
1099 public static void StoreFromPtr (ILGenerator ig, Type type)
1101 if (TypeManager.IsEnumType (type))
1102 type = TypeManager.EnumToUnderlying (type);
1103 if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
1104 ig.Emit (OpCodes.Stind_I4);
1105 else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
1106 ig.Emit (OpCodes.Stind_I8);
1107 else if (type == TypeManager.char_type || type == TypeManager.short_type ||
1108 type == TypeManager.ushort_type)
1109 ig.Emit (OpCodes.Stind_I2);
1110 else if (type == TypeManager.float_type)
1111 ig.Emit (OpCodes.Stind_R4);
1112 else if (type == TypeManager.double_type)
1113 ig.Emit (OpCodes.Stind_R8);
1114 else if (type == TypeManager.byte_type || type == TypeManager.sbyte_type ||
1115 type == TypeManager.bool_type)
1116 ig.Emit (OpCodes.Stind_I1);
1117 else if (type == TypeManager.intptr_type)
1118 ig.Emit (OpCodes.Stind_I);
1119 else if (type.IsValueType || TypeManager.IsGenericParameter (type))
1120 ig.Emit (OpCodes.Stobj, type);
1122 ig.Emit (OpCodes.Stind_Ref);
1126 // Returns the size of type `t' if known, otherwise, 0
1128 public static int GetTypeSize (Type t)
1130 t = TypeManager.TypeToCoreType (t);
1131 if (t == TypeManager.int32_type ||
1132 t == TypeManager.uint32_type ||
1133 t == TypeManager.float_type)
1135 else if (t == TypeManager.int64_type ||
1136 t == TypeManager.uint64_type ||
1137 t == TypeManager.double_type)
1139 else if (t == TypeManager.byte_type ||
1140 t == TypeManager.sbyte_type ||
1141 t == TypeManager.bool_type)
1143 else if (t == TypeManager.short_type ||
1144 t == TypeManager.char_type ||
1145 t == TypeManager.ushort_type)
1147 else if (t == TypeManager.decimal_type)
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 ConvertExpressionToArrayIndex (EmitContext ec, Expression source)
1175 Expression converted;
1177 using (ec.With (EmitContext.Flags.CheckState, true)) {
1178 converted = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, source.loc);
1179 if (converted == null)
1180 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, source.loc);
1181 if (converted == null)
1182 converted = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, source.loc);
1183 if (converted == null)
1184 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, source.loc);
1186 if (converted == null) {
1187 source.Error_ValueCannotBeConverted (ec, source.loc, TypeManager.int32_type, false);
1193 // Only positive constants are allowed at compile time
1195 Constant c = converted as Constant;
1198 Error_NegativeArrayIndex (source.loc);
1203 return new ArrayIndexCast (converted).Resolve (ec);
1207 // Derived classes implement this method by cloning the fields that
1208 // could become altered during the Resolve stage
1210 // Only expressions that are created for the parser need to implement
1213 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1215 throw new NotImplementedException (
1217 "CloneTo not implemented for expression {0}", this.GetType ()));
1221 // Clones an expression created by the parser.
1223 // We only support expressions created by the parser so far, not
1224 // expressions that have been resolved (many more classes would need
1225 // to implement CloneTo).
1227 // This infrastructure is here merely for Lambda expressions which
1228 // compile the same code using different type values for the same
1229 // arguments to find the correct overload
1231 public Expression Clone (CloneContext clonectx)
1233 Expression cloned = (Expression) MemberwiseClone ();
1234 CloneTo (clonectx, cloned);
1239 public virtual Expression CreateExpressionTree (EmitContext ec)
1241 throw new NotImplementedException (
1242 "Expression tree conversion not implemented for " + GetType ());
1245 protected Expression CreateExpressionFactoryCall (string name, ArrayList args)
1247 return CreateExpressionFactoryCall (name, null, args, loc);
1250 protected Expression CreateExpressionFactoryCall (string name, TypeArguments typeArguments, ArrayList args)
1252 return CreateExpressionFactoryCall (name, typeArguments, args, loc);
1255 public static Expression CreateExpressionFactoryCall (string name, TypeArguments typeArguments, ArrayList args, Location loc)
1257 return new Invocation (
1258 new MemberAccess (ExpressionTreeManager.Type, name, typeArguments, loc),
1264 /// This is just a base class for expressions that can
1265 /// appear on statements (invocations, object creation,
1266 /// assignments, post/pre increment and decrement). The idea
1267 /// being that they would support an extra Emition interface that
1268 /// does not leave a result on the stack.
1270 public abstract class ExpressionStatement : Expression {
1272 public virtual ExpressionStatement ResolveStatement (EmitContext ec)
1274 Expression e = Resolve (ec);
1278 ExpressionStatement es = e as ExpressionStatement;
1280 Error_InvalidExpressionStatement ();
1286 /// Requests the expression to be emitted in a `statement'
1287 /// context. This means that no new value is left on the
1288 /// stack after invoking this method (constrasted with
1289 /// Emit that will always leave a value on the stack).
1291 public abstract void EmitStatement (EmitContext ec);
1295 /// This kind of cast is used to encapsulate the child
1296 /// whose type is child.Type into an expression that is
1297 /// reported to return "return_type". This is used to encapsulate
1298 /// expressions which have compatible types, but need to be dealt
1299 /// at higher levels with.
1301 /// For example, a "byte" expression could be encapsulated in one
1302 /// of these as an "unsigned int". The type for the expression
1303 /// would be "unsigned int".
1306 public class EmptyCast : Expression
1308 protected Expression child;
1310 protected EmptyCast (Expression child, Type return_type)
1312 eclass = child.eclass;
1313 loc = child.Location;
1318 public static Expression Create (Expression child, Type type)
1320 Constant c = child as Constant;
1322 return new EmptyConstantCast (c, type);
1324 return new EmptyCast (child, type);
1327 public override Expression DoResolve (EmitContext ec)
1329 // This should never be invoked, we are born in fully
1330 // initialized state.
1335 public override void Emit (EmitContext ec)
1340 public override bool GetAttributableValue (Type value_type, out object value)
1342 return child.GetAttributableValue (value_type, out value);
1345 protected override void CloneTo (CloneContext clonectx, Expression t)
1347 EmptyCast target = (EmptyCast) t;
1349 target.child = child.Clone (clonectx);
1354 /// Performs a cast using an operator (op_Explicit or op_Implicit)
1356 public class OperatorCast : EmptyCast {
1357 MethodInfo conversion_operator;
1360 public OperatorCast (Expression child, Type target_type) : this (child, target_type, false) {}
1362 public OperatorCast (Expression child, Type target_type, bool find_explicit)
1363 : base (child, target_type)
1365 this.find_explicit = find_explicit;
1368 // Returns the implicit operator that converts from
1369 // 'child.Type' to our target type (type)
1370 MethodInfo GetConversionOperator (bool find_explicit)
1372 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1376 mi = TypeManager.MemberLookup (child.Type, child.Type, child.Type, MemberTypes.Method,
1377 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1380 mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1381 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1384 foreach (MethodInfo oper in mi) {
1385 ParameterData pd = TypeManager.GetParameterData (oper);
1387 if (pd.ParameterType (0) == child.Type && oper.ReturnType == type)
1395 public override void Emit (EmitContext ec)
1397 ILGenerator ig = ec.ig;
1400 conversion_operator = GetConversionOperator (find_explicit);
1402 if (conversion_operator == null)
1403 throw new InternalErrorException ("Outer conversion routine is out of sync");
1405 ig.Emit (OpCodes.Call, conversion_operator);
1411 /// This is a numeric cast to a Decimal
1413 public class CastToDecimal : EmptyCast {
1414 MethodInfo conversion_operator;
1416 public CastToDecimal (Expression child)
1417 : this (child, false)
1421 public CastToDecimal (Expression child, bool find_explicit)
1422 : base (child, TypeManager.decimal_type)
1424 conversion_operator = GetConversionOperator (find_explicit);
1426 if (conversion_operator == null)
1427 throw new InternalErrorException ("Outer conversion routine is out of sync");
1430 // Returns the implicit operator that converts from
1431 // 'child.Type' to System.Decimal.
1432 MethodInfo GetConversionOperator (bool find_explicit)
1434 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1436 MemberInfo [] mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1437 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1439 foreach (MethodInfo oper in mi) {
1440 ParameterData pd = TypeManager.GetParameterData (oper);
1442 if (pd.ParameterType (0) == child.Type && oper.ReturnType == type)
1448 public override void Emit (EmitContext ec)
1450 ILGenerator ig = ec.ig;
1453 ig.Emit (OpCodes.Call, conversion_operator);
1458 /// This is an explicit numeric cast from a Decimal
1460 public class CastFromDecimal : EmptyCast
1462 static IDictionary operators;
1464 public CastFromDecimal (Expression child, Type return_type)
1465 : base (child, return_type)
1467 if (child.Type != TypeManager.decimal_type)
1468 throw new InternalErrorException (
1469 "The expected type is Decimal, instead it is " + child.Type.FullName);
1472 // Returns the explicit operator that converts from an
1473 // express of type System.Decimal to 'type'.
1474 public Expression Resolve ()
1476 if (operators == null) {
1477 MemberInfo[] all_oper = TypeManager.MemberLookup (TypeManager.decimal_type,
1478 TypeManager.decimal_type, TypeManager.decimal_type, MemberTypes.Method,
1479 BindingFlags.Static | BindingFlags.Public, "op_Explicit", null);
1481 operators = new System.Collections.Specialized.HybridDictionary ();
1482 foreach (MethodInfo oper in all_oper) {
1483 ParameterData pd = TypeManager.GetParameterData (oper);
1484 if (pd.ParameterType (0) == TypeManager.decimal_type)
1485 operators.Add (oper.ReturnType, oper);
1489 return operators.Contains (type) ? this : null;
1492 public override void Emit (EmitContext ec)
1494 ILGenerator ig = ec.ig;
1497 ig.Emit (OpCodes.Call, (MethodInfo)operators [type]);
1503 // Constant specialization of EmptyCast.
1504 // We need to special case this since an empty cast of
1505 // a constant is still a constant.
1507 public class EmptyConstantCast : Constant
1509 public readonly Constant child;
1511 public EmptyConstantCast(Constant child, Type type)
1512 : base (child.Location)
1514 eclass = child.eclass;
1519 public override string AsString ()
1521 return child.AsString ();
1524 public override object GetValue ()
1526 return child.GetValue ();
1529 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
1531 // FIXME: check that 'type' can be converted to 'target_type' first
1532 return child.ConvertExplicitly (in_checked_context, target_type);
1535 public override Constant Increment ()
1537 return child.Increment ();
1540 public override bool IsDefaultValue {
1541 get { return child.IsDefaultValue; }
1544 public override bool IsNegative {
1545 get { return child.IsNegative; }
1548 public override bool IsNull {
1549 get { return child.IsNull; }
1552 public override bool IsZeroInteger {
1553 get { return child.IsZeroInteger; }
1556 public override void Emit (EmitContext ec)
1561 public override Constant ConvertImplicitly (Type target_type)
1563 // FIXME: Do we need to check user conversions?
1564 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1566 return child.ConvertImplicitly (target_type);
1572 /// This class is used to wrap literals which belong inside Enums
1574 public class EnumConstant : Constant {
1575 public Constant Child;
1577 public EnumConstant (Constant child, Type enum_type):
1578 base (child.Location)
1580 eclass = child.eclass;
1585 public override Expression DoResolve (EmitContext ec)
1587 // This should never be invoked, we are born in fully
1588 // initialized state.
1593 public override void Emit (EmitContext ec)
1598 public override bool GetAttributableValue (Type value_type, out object value)
1600 value = GetTypedValue ();
1604 public override string GetSignatureForError()
1606 return TypeManager.CSharpName (Type);
1609 public override object GetValue ()
1611 return Child.GetValue ();
1614 public override object GetTypedValue ()
1616 // FIXME: runtime is not ready to work with just emited enums
1617 if (!RootContext.StdLib) {
1618 return Child.GetValue ();
1621 return System.Enum.ToObject (type, Child.GetValue ());
1624 public override string AsString ()
1626 return TypeManager.CSharpEnumValue (type, Child.GetValue ());
1629 public override Constant Increment()
1631 return new EnumConstant (Child.Increment (), type);
1634 public override bool IsDefaultValue {
1636 return Child.IsDefaultValue;
1640 public override bool IsZeroInteger {
1641 get { return Child.IsZeroInteger; }
1644 public override bool IsNegative {
1646 return Child.IsNegative;
1650 public override Constant ConvertExplicitly(bool in_checked_context, Type target_type)
1652 if (Child.Type == target_type)
1655 return Child.ConvertExplicitly (in_checked_context, target_type);
1658 public override Constant ConvertImplicitly (Type type)
1660 Type this_type = TypeManager.DropGenericTypeArguments (Type);
1661 type = TypeManager.DropGenericTypeArguments (type);
1663 if (this_type == type) {
1664 // This is workaround of mono bug. It can be removed when the latest corlib spreads enough
1665 if (TypeManager.IsEnumType (type.UnderlyingSystemType))
1668 Type child_type = TypeManager.DropGenericTypeArguments (Child.Type);
1669 if (type.UnderlyingSystemType != child_type)
1670 Child = Child.ConvertImplicitly (type.UnderlyingSystemType);
1674 if (!Convert.ImplicitStandardConversionExists (this, type)){
1678 return Child.ConvertImplicitly(type);
1684 /// This kind of cast is used to encapsulate Value Types in objects.
1686 /// The effect of it is to box the value type emitted by the previous
1689 public class BoxedCast : EmptyCast {
1691 public BoxedCast (Expression expr, Type target_type)
1692 : base (expr, target_type)
1694 eclass = ExprClass.Value;
1697 public override Expression DoResolve (EmitContext ec)
1699 // This should never be invoked, we are born in fully
1700 // initialized state.
1705 public override void Emit (EmitContext ec)
1709 ec.ig.Emit (OpCodes.Box, child.Type);
1713 public class UnboxCast : EmptyCast {
1714 public UnboxCast (Expression expr, Type return_type)
1715 : base (expr, return_type)
1719 public override Expression DoResolve (EmitContext ec)
1721 // This should never be invoked, we are born in fully
1722 // initialized state.
1727 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1729 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
1730 Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
1731 return base.DoResolveLValue (ec, right_side);
1734 public override void Emit (EmitContext ec)
1737 ILGenerator ig = ec.ig;
1741 if (t.IsGenericParameter || t.IsGenericType && t.IsValueType)
1742 ig.Emit (OpCodes.Unbox_Any, t);
1746 ig.Emit (OpCodes.Unbox, t);
1748 LoadFromPtr (ig, t);
1754 /// This is used to perform explicit numeric conversions.
1756 /// Explicit numeric conversions might trigger exceptions in a checked
1757 /// context, so they should generate the conv.ovf opcodes instead of
1760 public class ConvCast : EmptyCast {
1761 public enum Mode : byte {
1762 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1764 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1765 U2_I1, U2_U1, U2_I2, U2_CH,
1766 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1767 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1768 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH,
1769 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH,
1770 CH_I1, CH_U1, CH_I2,
1771 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1772 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4
1777 public ConvCast (Expression child, Type return_type, Mode m)
1778 : base (child, return_type)
1783 public override Expression DoResolve (EmitContext ec)
1785 // This should never be invoked, we are born in fully
1786 // initialized state.
1791 public override string ToString ()
1793 return String.Format ("ConvCast ({0}, {1})", mode, child);
1796 public override void Emit (EmitContext ec)
1798 ILGenerator ig = ec.ig;
1804 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1805 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1806 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1807 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1808 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1810 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1811 case Mode.U1_CH: /* nothing */ break;
1813 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1814 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1815 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1816 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1817 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1818 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1820 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1821 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1822 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1823 case Mode.U2_CH: /* nothing */ break;
1825 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1826 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1827 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1828 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1829 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1830 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1831 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1833 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1834 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1835 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1836 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1837 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1838 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1840 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1841 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1842 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1843 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1844 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1845 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1846 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1847 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1849 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1850 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1851 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1852 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1853 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1854 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1855 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1856 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1858 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1859 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1860 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1862 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1863 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1864 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1865 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1866 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1867 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1868 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1869 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1870 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1872 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1873 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1874 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1875 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1876 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1877 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1878 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1879 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1880 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1881 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1885 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
1886 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
1887 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
1888 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
1889 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
1891 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
1892 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
1894 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
1895 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
1896 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
1897 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
1898 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
1899 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
1901 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
1902 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
1903 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
1904 case Mode.U2_CH: /* nothing */ break;
1906 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
1907 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
1908 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
1909 case Mode.I4_U4: /* nothing */ break;
1910 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
1911 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
1912 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
1914 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
1915 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
1916 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
1917 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
1918 case Mode.U4_I4: /* nothing */ break;
1919 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
1921 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
1922 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
1923 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
1924 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
1925 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
1926 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
1927 case Mode.I8_U8: /* nothing */ break;
1928 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
1930 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
1931 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
1932 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
1933 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
1934 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
1935 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
1936 case Mode.U8_I8: /* nothing */ break;
1937 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
1939 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
1940 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
1941 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
1943 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
1944 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
1945 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
1946 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
1947 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
1948 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
1949 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
1950 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
1951 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
1953 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
1954 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
1955 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
1956 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
1957 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
1958 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
1959 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
1960 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
1961 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
1962 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1968 public class OpcodeCast : EmptyCast {
1972 public OpcodeCast (Expression child, Type return_type, OpCode op)
1973 : base (child, return_type)
1977 second_valid = false;
1980 public OpcodeCast (Expression child, Type return_type, OpCode op, OpCode op2)
1981 : base (child, return_type)
1986 second_valid = true;
1989 public override Expression DoResolve (EmitContext ec)
1991 // This should never be invoked, we are born in fully
1992 // initialized state.
1997 public override void Emit (EmitContext ec)
2008 /// This kind of cast is used to encapsulate a child and cast it
2009 /// to the class requested
2011 public class ClassCast : EmptyCast {
2012 public ClassCast (Expression child, Type return_type)
2013 : base (child, return_type)
2018 public override Expression DoResolve (EmitContext ec)
2020 // This should never be invoked, we are born in fully
2021 // initialized state.
2026 public override void Emit (EmitContext ec)
2030 if (TypeManager.IsGenericParameter (child.Type))
2031 ec.ig.Emit (OpCodes.Box, child.Type);
2034 if (type.IsGenericParameter)
2035 ec.ig.Emit (OpCodes.Unbox_Any, type);
2038 ec.ig.Emit (OpCodes.Castclass, type);
2043 /// SimpleName expressions are formed of a single word and only happen at the beginning
2044 /// of a dotted-name.
2046 public class SimpleName : Expression {
2047 public readonly string Name;
2048 public readonly TypeArguments Arguments;
2051 public SimpleName (string name, Location l)
2057 public SimpleName (string name, TypeArguments args, Location l)
2064 public SimpleName (string name, TypeParameter[] type_params, Location l)
2069 Arguments = new TypeArguments (l);
2070 foreach (TypeParameter type_param in type_params)
2071 Arguments.Add (new TypeParameterExpr (type_param, l));
2074 public static string RemoveGenericArity (string name)
2077 StringBuilder sb = null;
2079 int pos = name.IndexOf ('`', start);
2084 sb.Append (name.Substring (start));
2089 sb = new StringBuilder ();
2090 sb.Append (name.Substring (start, pos-start));
2093 while ((pos < name.Length) && Char.IsNumber (name [pos]))
2097 } while (start < name.Length);
2099 return sb.ToString ();
2102 public SimpleName GetMethodGroup ()
2104 return new SimpleName (RemoveGenericArity (Name), Arguments, loc);
2107 public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
2109 if (ec.IsInFieldInitializer)
2110 Report.Error (236, l,
2111 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2115 120, l, "`{0}': An object reference is required for the nonstatic field, method or property",
2119 public bool IdenticalNameAndTypeName (EmitContext ec, Expression resolved_to, Location loc)
2121 return resolved_to != null && resolved_to.Type != null &&
2122 resolved_to.Type.Name == Name &&
2123 (ec.DeclContainer.LookupNamespaceOrType (Name, loc, /* ignore_cs0104 = */ true) != null);
2126 public override Expression DoResolve (EmitContext ec)
2128 return SimpleNameResolve (ec, null, false);
2131 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
2133 return SimpleNameResolve (ec, right_side, false);
2137 public Expression DoResolve (EmitContext ec, bool intermediate)
2139 return SimpleNameResolve (ec, null, intermediate);
2142 static bool IsNestedChild (Type t, Type parent)
2144 while (parent != null) {
2145 if (TypeManager.IsNestedChildOf (t, TypeManager.DropGenericTypeArguments (parent)))
2148 parent = parent.BaseType;
2154 FullNamedExpression ResolveNested (IResolveContext ec, Type t)
2156 if (!TypeManager.IsGenericTypeDefinition (t) && !TypeManager.IsGenericType (t))
2159 DeclSpace ds = ec.DeclContainer;
2160 while (ds != null && !IsNestedChild (t, ds.TypeBuilder))
2166 Type[] gen_params = TypeManager.GetTypeArguments (t);
2168 int arg_count = Arguments != null ? Arguments.Count : 0;
2170 for (; (ds != null) && ds.IsGeneric; ds = ds.Parent) {
2171 if (arg_count + ds.CountTypeParameters == gen_params.Length) {
2172 TypeArguments new_args = new TypeArguments (loc);
2173 foreach (TypeParameter param in ds.TypeParameters)
2174 new_args.Add (new TypeParameterExpr (param, loc));
2176 if (Arguments != null)
2177 new_args.Add (Arguments);
2179 return new ConstructedType (t, new_args, loc);
2186 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2188 FullNamedExpression fne = ec.GenericDeclContainer.LookupGeneric (Name, loc);
2190 return fne.ResolveAsTypeStep (ec, silent);
2192 int errors = Report.Errors;
2193 fne = ec.DeclContainer.LookupNamespaceOrType (Name, loc, /*ignore_cs0104=*/ false);
2196 if (fne.Type == null)
2199 FullNamedExpression nested = ResolveNested (ec, fne.Type);
2201 return nested.ResolveAsTypeStep (ec, false);
2203 if (Arguments != null) {
2204 ConstructedType ct = new ConstructedType (fne, Arguments, loc);
2205 return ct.ResolveAsTypeStep (ec, false);
2211 if (silent || errors != Report.Errors)
2214 Error_TypeOrNamespaceNotFound (ec);
2218 protected virtual void Error_TypeOrNamespaceNotFound (IResolveContext ec)
2220 MemberCore mc = ec.DeclContainer.GetDefinition (Name);
2222 Error_UnexpectedKind (ec.DeclContainer, "type", GetMemberType (mc), loc);
2226 string ns = ec.DeclContainer.NamespaceEntry.NS.Name;
2227 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2228 foreach (Assembly a in RootNamespace.Global.Assemblies) {
2229 Type type = a.GetType (fullname);
2231 Report.SymbolRelatedToPreviousError (type);
2232 Expression.ErrorIsInaccesible (loc, TypeManager.CSharpName (type));
2237 Type t = ec.DeclContainer.LookupAnyGeneric (Name);
2239 Namespace.Error_InvalidNumberOfTypeArguments (t, loc);
2243 if (Arguments != null) {
2244 FullNamedExpression retval = ec.DeclContainer.LookupNamespaceOrType (SimpleName.RemoveGenericArity (Name), loc, true);
2245 if (retval != null) {
2246 Namespace.Error_TypeArgumentsCannotBeUsed (retval.Type, loc);
2251 NamespaceEntry.Error_NamespaceNotFound (loc, Name);
2254 // TODO: I am still not convinced about this. If someone else will need it
2255 // implement this as virtual property in MemberCore hierarchy
2256 public static string GetMemberType (MemberCore mc)
2262 if (mc is FieldBase)
2264 if (mc is MethodCore)
2266 if (mc is EnumMember)
2274 Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2280 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2286 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2293 /// 7.5.2: Simple Names.
2295 /// Local Variables and Parameters are handled at
2296 /// parse time, so they never occur as SimpleNames.
2298 /// The `intermediate' flag is used by MemberAccess only
2299 /// and it is used to inform us that it is ok for us to
2300 /// avoid the static check, because MemberAccess might end
2301 /// up resolving the Name as a Type name and the access as
2302 /// a static type access.
2304 /// ie: Type Type; .... { Type.GetType (""); }
2306 /// Type is both an instance variable and a Type; Type.GetType
2307 /// is the static method not an instance method of type.
2309 Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2311 Expression e = null;
2314 // Stage 1: Performed by the parser (binding to locals or parameters).
2316 Block current_block = ec.CurrentBlock;
2317 if (current_block != null){
2318 LocalInfo vi = current_block.GetLocalInfo (Name);
2320 if (Arguments != null) {
2321 Report.Error (307, loc,
2322 "The variable `{0}' cannot be used with type arguments",
2327 LocalVariableReference var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2328 if (right_side != null) {
2329 return var.ResolveLValue (ec, right_side, loc);
2331 ResolveFlags rf = ResolveFlags.VariableOrValue;
2333 rf |= ResolveFlags.DisableFlowAnalysis;
2334 return var.Resolve (ec, rf);
2338 ParameterReference pref = current_block.Toplevel.GetParameterReference (Name, loc);
2340 if (Arguments != null) {
2341 Report.Error (307, loc,
2342 "The variable `{0}' cannot be used with type arguments",
2347 if (right_side != null)
2348 return pref.ResolveLValue (ec, right_side, loc);
2350 return pref.Resolve (ec);
2353 Expression expr = current_block.Toplevel.GetTransparentIdentifier (Name);
2355 if (right_side != null)
2356 return expr.ResolveLValue (ec, right_side, loc);
2357 return expr.Resolve (ec);
2362 // Stage 2: Lookup members
2365 Type almost_matched_type = null;
2366 ArrayList almost_matched = null;
2367 for (DeclSpace lookup_ds = ec.DeclContainer; lookup_ds != null; lookup_ds = lookup_ds.Parent) {
2368 // either RootDeclSpace or GenericMethod
2369 if (lookup_ds.TypeBuilder == null)
2372 e = MemberLookup (ec.ContainerType, lookup_ds.TypeBuilder, Name, loc);
2374 if (e is PropertyExpr) {
2375 // since TypeManager.MemberLookup doesn't know if we're doing a lvalue access or not,
2376 // it doesn't know which accessor to check permissions against
2377 if (((PropertyExpr) e).IsAccessibleFrom (ec.ContainerType, right_side != null))
2379 } else if (e is EventExpr) {
2380 if (((EventExpr) e).IsAccessibleFrom (ec.ContainerType))
2388 if (almost_matched == null && almost_matched_members.Count > 0) {
2389 almost_matched_type = lookup_ds.TypeBuilder;
2390 almost_matched = (ArrayList) almost_matched_members.Clone ();
2395 if (almost_matched == null && almost_matched_members.Count > 0) {
2396 almost_matched_type = ec.ContainerType;
2397 almost_matched = (ArrayList) almost_matched_members.Clone ();
2399 e = ResolveAsTypeStep (ec, true);
2403 if (current_block != null) {
2404 IKnownVariable ikv = current_block.Explicit.GetKnownVariable (Name);
2406 LocalInfo li = ikv as LocalInfo;
2407 // Supress CS0219 warning
2411 Error_VariableIsUsedBeforeItIsDeclared (Name);
2416 if (almost_matched != null)
2417 almost_matched_members = almost_matched;
2418 if (almost_matched_type == null)
2419 almost_matched_type = ec.ContainerType;
2420 Error_MemberLookupFailed (ec.ContainerType, null, almost_matched_type, Name,
2421 ec.DeclContainer.Name, AllMemberTypes, AllBindingFlags);
2425 if (e is TypeExpr) {
2426 if (Arguments == null)
2429 ConstructedType ct = new ConstructedType (
2430 (FullNamedExpression) e, Arguments, loc);
2431 return ct.ResolveAsTypeStep (ec, false);
2434 if (e is MemberExpr) {
2435 MemberExpr me = (MemberExpr) e;
2438 if (me.IsInstance) {
2439 if (ec.IsStatic || ec.IsInFieldInitializer) {
2441 // Note that an MemberExpr can be both IsInstance and IsStatic.
2442 // An unresolved MethodGroupExpr can contain both kinds of methods
2443 // and each predicate is true if the MethodGroupExpr contains
2444 // at least one of that kind of method.
2448 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2449 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2450 return EmptyExpression.Null;
2454 // Pass the buck to MemberAccess and Invocation.
2456 left = EmptyExpression.Null;
2458 left = ec.GetThis (loc);
2461 left = new TypeExpression (ec.ContainerType, loc);
2464 me = me.ResolveMemberAccess (ec, left, loc, null);
2468 if (Arguments != null) {
2469 Arguments.Resolve (ec);
2470 me.SetTypeArguments (Arguments);
2473 if (!me.IsStatic && (me.InstanceExpression != null) &&
2474 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2475 me.InstanceExpression.Type != me.DeclaringType &&
2476 !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2477 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2478 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2479 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2483 return (right_side != null)
2484 ? me.DoResolveLValue (ec, right_side)
2485 : me.DoResolve (ec);
2491 public override void Emit (EmitContext ec)
2493 throw new InternalErrorException ("The resolve phase was not executed");
2496 public override string ToString ()
2501 public override string GetSignatureForError ()
2503 if (Arguments != null) {
2504 return TypeManager.RemoveGenericArity (Name) + "<" +
2505 Arguments.GetSignatureForError () + ">";
2511 protected override void CloneTo (CloneContext clonectx, Expression target)
2513 // CloneTo: Nothing, we do not keep any state on this expression
2518 /// Represents a namespace or a type. The name of the class was inspired by
2519 /// section 10.8.1 (Fully Qualified Names).
2521 public abstract class FullNamedExpression : Expression {
2522 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2527 public abstract string FullName {
2533 /// Expression that evaluates to a type
2535 public abstract class TypeExpr : FullNamedExpression {
2536 override public FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2538 TypeExpr t = DoResolveAsTypeStep (ec);
2542 eclass = ExprClass.Type;
2546 override public Expression DoResolve (EmitContext ec)
2548 return ResolveAsTypeTerminal (ec, false);
2551 override public void Emit (EmitContext ec)
2553 throw new Exception ("Should never be called");
2556 public virtual bool CheckAccessLevel (DeclSpace ds)
2558 return ds.CheckAccessLevel (Type);
2561 public virtual bool AsAccessible (DeclSpace ds, int flags)
2563 return ds.AsAccessible (Type, flags);
2566 public virtual bool IsClass {
2567 get { return Type.IsClass; }
2570 public virtual bool IsValueType {
2571 get { return Type.IsValueType; }
2574 public virtual bool IsInterface {
2575 get { return Type.IsInterface; }
2578 public virtual bool IsSealed {
2579 get { return Type.IsSealed; }
2582 public virtual bool CanInheritFrom ()
2584 if (Type == TypeManager.enum_type ||
2585 (Type == TypeManager.value_type && RootContext.StdLib) ||
2586 Type == TypeManager.multicast_delegate_type ||
2587 Type == TypeManager.delegate_type ||
2588 Type == TypeManager.array_type)
2594 protected abstract TypeExpr DoResolveAsTypeStep (IResolveContext ec);
2596 public abstract string Name {
2600 public override bool Equals (object obj)
2602 TypeExpr tobj = obj as TypeExpr;
2606 return Type == tobj.Type;
2609 public override int GetHashCode ()
2611 return Type.GetHashCode ();
2614 public override string ToString ()
2621 /// Fully resolved Expression that already evaluated to a type
2623 public class TypeExpression : TypeExpr {
2624 public TypeExpression (Type t, Location l)
2627 eclass = ExprClass.Type;
2631 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2636 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2641 public override string Name {
2642 get { return Type.ToString (); }
2645 public override string FullName {
2646 get { return Type.FullName; }
2651 /// Used to create types from a fully qualified name. These are just used
2652 /// by the parser to setup the core types. A TypeLookupExpression is always
2653 /// classified as a type.
2655 public sealed class TypeLookupExpression : TypeExpr {
2656 readonly string name;
2658 public TypeLookupExpression (string name)
2661 eclass = ExprClass.Type;
2664 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2666 // It's null for corlib compilation only
2668 return DoResolveAsTypeStep (ec);
2673 private class UnexpectedType
2677 // This performes recursive type lookup, providing support for generic types.
2678 // For example, given the type:
2680 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]]
2682 // The types will be checked in the following order:
2685 // System.Collections |
2686 // System.Collections.Generic |
2688 // System | recursive call 1 |
2689 // System.Int32 _| | main method call
2691 // System | recursive call 2 |
2692 // System.String _| |
2694 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]] _|
2696 private Type TypeLookup (IResolveContext ec, string name)
2701 FullNamedExpression resolved = null;
2703 Type recursive_type = null;
2704 while (index < name.Length) {
2705 if (name[index] == '[') {
2710 if (name[index] == '[')
2712 else if (name[index] == ']')
2714 } while (braces > 0);
2715 recursive_type = TypeLookup (ec, name.Substring (open + 1, index - open - 1));
2716 if (recursive_type == null || (recursive_type == typeof(UnexpectedType)))
2717 return recursive_type;
2720 if (name[index] == ',')
2722 else if ((name[index] == '.' && !done) || (index == name.Length && name[0] != '[')) {
2723 string substring = name.Substring(dot, index - dot);
2725 if (resolved == null)
2726 resolved = RootNamespace.Global.Lookup (ec.DeclContainer, substring, Location.Null);
2727 else if (resolved is Namespace)
2728 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
2729 else if (type != null)
2730 type = TypeManager.GetNestedType (type, substring);
2734 if (resolved == null)
2736 else if (type == null && resolved is TypeExpr)
2737 type = resolved.Type;
2744 if (name[0] != '[') {
2745 string substring = name.Substring(dot, index - dot);
2748 return TypeManager.GetNestedType (type, substring);
2750 if (resolved != null) {
2751 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
2752 if (resolved is TypeExpr)
2753 return resolved.Type;
2755 if (resolved == null)
2758 resolved.Error_UnexpectedKind (ec.DeclContainer, "type", loc);
2759 return typeof (UnexpectedType);
2765 return recursive_type;
2768 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2770 Type t = TypeLookup (ec, name);
2772 NamespaceEntry.Error_NamespaceNotFound (loc, name);
2775 if (t == typeof(UnexpectedType))
2781 public override string Name {
2782 get { return name; }
2785 public override string FullName {
2786 get { return name; }
2789 protected override void CloneTo (CloneContext clonectx, Expression target)
2791 // CloneTo: Nothing, we do not keep any state on this expression
2794 public override string GetSignatureForError ()
2797 return TypeManager.CSharpName (name);
2799 return base.GetSignatureForError ();
2804 /// Represents an "unbound generic type", ie. typeof (Foo<>).
2807 public class UnboundTypeExpression : TypeExpr
2811 public UnboundTypeExpression (MemberName name, Location l)
2817 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2820 if (name.Left != null) {
2821 Expression lexpr = name.Left.GetTypeExpression ();
2822 expr = new MemberAccess (lexpr, name.Basename);
2824 expr = new SimpleName (name.Basename, loc);
2827 FullNamedExpression fne = expr.ResolveAsTypeStep (ec, false);
2832 return new TypeExpression (type, loc);
2835 public override string Name {
2836 get { return name.FullName; }
2839 public override string FullName {
2840 get { return name.FullName; }
2844 public class TypeAliasExpression : TypeExpr {
2845 FullNamedExpression alias;
2850 public TypeAliasExpression (FullNamedExpression alias, TypeArguments args, Location l)
2856 eclass = ExprClass.Type;
2858 name = alias.FullName + "<" + args.ToString () + ">";
2860 name = alias.FullName;
2863 public override string Name {
2864 get { return alias.FullName; }
2867 public override string FullName {
2868 get { return name; }
2871 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2873 texpr = alias.ResolveAsTypeTerminal (ec, false);
2877 Type type = texpr.Type;
2878 int num_args = TypeManager.GetNumberOfTypeArguments (type);
2881 if (num_args == 0) {
2882 Report.Error (308, loc,
2883 "The non-generic type `{0}' cannot " +
2884 "be used with type arguments.",
2885 TypeManager.CSharpName (type));
2889 ConstructedType ctype = new ConstructedType (type, args, loc);
2890 return ctype.ResolveAsTypeTerminal (ec, false);
2891 } else if (num_args > 0) {
2892 Report.Error (305, loc,
2893 "Using the generic type `{0}' " +
2894 "requires {1} type arguments",
2895 TypeManager.CSharpName (type), num_args.ToString ());
2902 public override bool CheckAccessLevel (DeclSpace ds)
2904 return texpr.CheckAccessLevel (ds);
2907 public override bool AsAccessible (DeclSpace ds, int flags)
2909 return texpr.AsAccessible (ds, flags);
2912 public override bool IsClass {
2913 get { return texpr.IsClass; }
2916 public override bool IsValueType {
2917 get { return texpr.IsValueType; }
2920 public override bool IsInterface {
2921 get { return texpr.IsInterface; }
2924 public override bool IsSealed {
2925 get { return texpr.IsSealed; }
2930 /// This class denotes an expression which evaluates to a member
2931 /// of a struct or a class.
2933 public abstract class MemberExpr : Expression
2935 protected bool is_base;
2938 /// The name of this member.
2940 public abstract string Name {
2945 // When base.member is used
2947 public bool IsBase {
2948 get { return is_base; }
2949 set { is_base = value; }
2953 /// Whether this is an instance member.
2955 public abstract bool IsInstance {
2960 /// Whether this is a static member.
2962 public abstract bool IsStatic {
2967 /// The type which declares this member.
2969 public abstract Type DeclaringType {
2974 /// The instance expression associated with this member, if it's a
2975 /// non-static member.
2977 public Expression InstanceExpression;
2979 public static void error176 (Location loc, string name)
2981 Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
2982 "with an instance reference, qualify it with a type name instead", name);
2985 // TODO: possible optimalization
2986 // Cache resolved constant result in FieldBuilder <-> expression map
2987 public virtual MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
2988 SimpleName original)
2992 // original == null || original.Resolve (...) ==> left
2995 if (left is TypeExpr) {
2996 left = left.ResolveAsTypeTerminal (ec, true);
3001 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3009 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3012 return ResolveExtensionMemberAccess (left);
3015 InstanceExpression = left;
3019 protected virtual MemberExpr ResolveExtensionMemberAccess (Expression left)
3021 error176 (loc, GetSignatureForError ());
3025 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3030 if (InstanceExpression == EmptyExpression.Null) {
3031 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3035 if (InstanceExpression.Type.IsValueType) {
3036 if (InstanceExpression is IMemoryLocation) {
3037 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
3039 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
3040 InstanceExpression.Emit (ec);
3042 t.AddressOf (ec, AddressOp.Store);
3045 InstanceExpression.Emit (ec);
3047 if (prepare_for_load)
3048 ec.ig.Emit (OpCodes.Dup);
3051 public virtual void SetTypeArguments (TypeArguments ta)
3053 // TODO: need to get correct member type
3054 Report.Error (307, loc, "The property `{0}' cannot be used with type arguments",
3055 GetSignatureForError ());
3060 /// Represents group of extension methods
3062 public class ExtensionMethodGroupExpr : MethodGroupExpr
3064 readonly NamespaceEntry namespace_entry;
3065 public Expression ExtensionExpression;
3066 Argument extension_argument;
3068 public ExtensionMethodGroupExpr (ArrayList list, NamespaceEntry n, Type extensionType, Location l)
3069 : base (list, extensionType, l)
3071 this.namespace_entry = n;
3074 public override bool IsStatic {
3075 get { return true; }
3078 public bool IsTopLevel {
3079 get { return namespace_entry == null; }
3082 public override void EmitArguments (EmitContext ec, ArrayList arguments)
3084 if (arguments == null)
3085 arguments = new ArrayList (1);
3086 arguments.Insert (0, extension_argument);
3087 base.EmitArguments (ec, arguments);
3090 public override void EmitCall (EmitContext ec, ArrayList arguments)
3092 if (arguments == null)
3093 arguments = new ArrayList (1);
3094 arguments.Insert (0, extension_argument);
3095 base.EmitCall (ec, arguments);
3098 public override MethodGroupExpr OverloadResolve (EmitContext ec, ArrayList arguments, bool may_fail, Location loc)
3100 if ((ExtensionExpression.eclass & (ExprClass.Value | ExprClass.Variable)) == 0)
3101 return base.OverloadResolve (ec, arguments, may_fail, loc);
3103 if (arguments == null)
3104 arguments = new ArrayList (1);
3106 arguments.Insert (0, new Argument (ExtensionExpression));
3107 MethodGroupExpr mg = ResolveOverloadExtensions (ec, arguments, namespace_entry, loc);
3109 // Store resolved argument and restore original arguments
3111 ((ExtensionMethodGroupExpr)mg).extension_argument = (Argument)arguments [0];
3112 arguments.RemoveAt (0);
3117 MethodGroupExpr ResolveOverloadExtensions (EmitContext ec, ArrayList arguments, NamespaceEntry ns, Location loc)
3119 // Use normal resolve rules
3120 MethodGroupExpr mg = base.OverloadResolve (ec, arguments, ns != null, loc);
3128 ExtensionMethodGroupExpr e = ns.LookupExtensionMethod (type, null, Name);
3130 return base.OverloadResolve (ec, arguments, false, loc);
3132 e.ExtensionExpression = ExtensionExpression;
3133 return e.ResolveOverloadExtensions (ec, arguments, e.namespace_entry, loc);
3138 /// MethodGroupExpr represents a group of method candidates which
3139 /// can be resolved to the best method overload
3141 public class MethodGroupExpr : MemberExpr
3143 public interface IErrorHandler
3145 bool NoExactMatch (EmitContext ec, MethodBase method);
3148 public IErrorHandler CustomErrorHandler;
3149 public MethodBase [] Methods;
3150 MethodBase best_candidate;
3151 // TODO: make private
3152 public TypeArguments type_arguments;
3153 bool identical_type_name;
3156 public MethodGroupExpr (MemberInfo [] mi, Type type, Location l)
3159 Methods = new MethodBase [mi.Length];
3160 mi.CopyTo (Methods, 0);
3163 public MethodGroupExpr (ArrayList list, Type type, Location l)
3167 Methods = (MethodBase[])list.ToArray (typeof (MethodBase));
3169 foreach (MemberInfo m in list){
3170 if (!(m is MethodBase)){
3171 Console.WriteLine ("Name " + m.Name);
3172 Console.WriteLine ("Found a: " + m.GetType ().FullName);
3181 protected MethodGroupExpr (Type type, Location loc)
3184 eclass = ExprClass.MethodGroup;
3188 public override Type DeclaringType {
3191 // We assume that the top-level type is in the end
3193 return Methods [Methods.Length - 1].DeclaringType;
3194 //return Methods [0].DeclaringType;
3198 public Type DelegateType {
3200 delegate_type = value;
3204 public bool IdenticalTypeName {
3206 return identical_type_name;
3210 identical_type_name = value;
3214 public override string GetSignatureForError ()
3216 if (best_candidate != null)
3217 return TypeManager.CSharpSignature (best_candidate);
3219 return TypeManager.CSharpSignature (Methods [0]);
3222 public override string Name {
3224 return Methods [0].Name;
3228 public override bool IsInstance {
3230 if (best_candidate != null)
3231 return !best_candidate.IsStatic;
3233 foreach (MethodBase mb in Methods)
3241 public override bool IsStatic {
3243 if (best_candidate != null)
3244 return best_candidate.IsStatic;
3246 foreach (MethodBase mb in Methods)
3254 public static explicit operator ConstructorInfo (MethodGroupExpr mg)
3256 return (ConstructorInfo)mg.best_candidate;
3259 public static explicit operator MethodInfo (MethodGroupExpr mg)
3261 return (MethodInfo)mg.best_candidate;
3265 /// Determines "better conversion" as specified in 14.4.2.3
3267 /// Returns : p if a->p is better,
3268 /// q if a->q is better,
3269 /// null if neither is better
3271 static Type BetterConversion (EmitContext ec, Argument a, Type p, Type q)
3273 Type argument_type = TypeManager.TypeToCoreType (a.Type);
3274 Expression argument_expr = a.Expr;
3276 if (argument_type == null)
3277 throw new Exception ("Expression of type " + a.Expr +
3278 " does not resolve its type");
3280 if (p == null || q == null)
3281 throw new InternalErrorException ("BetterConversion Got a null conversion");
3286 if (argument_expr is NullLiteral)
3289 // If the argument is null and one of the types to compare is 'object' and
3290 // the other is a reference type, we prefer the other.
3292 // This follows from the usual rules:
3293 // * There is an implicit conversion from 'null' to type 'object'
3294 // * There is an implicit conversion from 'null' to any reference type
3295 // * There is an implicit conversion from any reference type to type 'object'
3296 // * There is no implicit conversion from type 'object' to other reference types
3297 // => Conversion of 'null' to a reference type is better than conversion to 'object'
3299 // FIXME: This probably isn't necessary, since the type of a NullLiteral is the
3300 // null type. I think it used to be 'object' and thus needed a special
3301 // case to avoid the immediately following two checks.
3303 if (!p.IsValueType && q == TypeManager.object_type)
3305 if (!q.IsValueType && p == TypeManager.object_type)
3309 if (argument_type == p)
3312 if (argument_type == q)
3315 Expression p_tmp = new EmptyExpression (p);
3316 Expression q_tmp = new EmptyExpression (q);
3318 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3319 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3321 if (p_to_q && !q_to_p)
3324 if (q_to_p && !p_to_q)
3327 if (p == TypeManager.sbyte_type)
3328 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3329 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3331 if (q == TypeManager.sbyte_type)
3332 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3333 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3336 if (p == TypeManager.short_type)
3337 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3338 q == TypeManager.uint64_type)
3340 if (q == TypeManager.short_type)
3341 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3342 p == TypeManager.uint64_type)
3345 if (p == TypeManager.int32_type)
3346 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3348 if (q == TypeManager.int32_type)
3349 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3352 if (p == TypeManager.int64_type)
3353 if (q == TypeManager.uint64_type)
3355 if (q == TypeManager.int64_type)
3356 if (p == TypeManager.uint64_type)
3363 /// Determines "Better function" between candidate
3364 /// and the current best match
3367 /// Returns a boolean indicating :
3368 /// false if candidate ain't better
3369 /// true if candidate is better than the current best match
3371 static bool BetterFunction (EmitContext ec, ArrayList args, int argument_count,
3372 MethodBase candidate, bool candidate_params,
3373 MethodBase best, bool best_params)
3375 ParameterData candidate_pd = TypeManager.GetParameterData (candidate);
3376 ParameterData best_pd = TypeManager.GetParameterData (best);
3378 bool better_at_least_one = false;
3380 for (int j = 0, c_idx = 0, b_idx = 0; j < argument_count; ++j, ++c_idx, ++b_idx)
3382 Argument a = (Argument) args [j];
3384 Type ct = TypeManager.TypeToCoreType (candidate_pd.ParameterType (c_idx));
3385 Type bt = TypeManager.TypeToCoreType (best_pd.ParameterType (b_idx));
3387 if (candidate_params && candidate_pd.ParameterModifier (c_idx) == Parameter.Modifier.PARAMS)
3389 ct = TypeManager.GetElementType (ct);
3393 if (best_params && best_pd.ParameterModifier (b_idx) == Parameter.Modifier.PARAMS)
3395 bt = TypeManager.GetElementType (bt);
3403 Type better = BetterConversion (ec, a, ct, bt);
3405 // for each argument, the conversion to 'ct' should be no worse than
3406 // the conversion to 'bt'.
3410 // for at least one argument, the conversion to 'ct' should be better than
3411 // the conversion to 'bt'.
3413 better_at_least_one = true;
3416 if (better_at_least_one)
3420 // This handles the case
3422 // Add (float f1, float f2, float f3);
3423 // Add (params decimal [] foo);
3425 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3426 // first candidate would've chosen as better.
3432 // The two methods have equal parameter types. Now apply tie-breaking rules
3434 if (TypeManager.IsGenericMethod (best) && !TypeManager.IsGenericMethod (candidate))
3436 if (!TypeManager.IsGenericMethod (best) && TypeManager.IsGenericMethod (candidate))
3440 // This handles the following cases:
3442 // Trim () is better than Trim (params char[] chars)
3443 // Concat (string s1, string s2, string s3) is better than
3444 // Concat (string s1, params string [] srest)
3445 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3447 if (!candidate_params && best_params)
3449 if (candidate_params && !best_params)
3452 int candidate_param_count = candidate_pd.Count;
3453 int best_param_count = best_pd.Count;
3455 if (candidate_param_count != best_param_count)
3456 // can only happen if (candidate_params && best_params)
3457 return candidate_param_count > best_param_count;
3460 // now, both methods have the same number of parameters, and the parameters have the same types
3461 // Pick the "more specific" signature
3464 MethodBase orig_candidate = TypeManager.DropGenericMethodArguments (candidate);
3465 MethodBase orig_best = TypeManager.DropGenericMethodArguments (best);
3467 ParameterData orig_candidate_pd = TypeManager.GetParameterData (orig_candidate);
3468 ParameterData orig_best_pd = TypeManager.GetParameterData (orig_best);
3470 bool specific_at_least_once = false;
3471 for (int j = 0; j < candidate_param_count; ++j)
3473 Type ct = TypeManager.TypeToCoreType (orig_candidate_pd.ParameterType (j));
3474 Type bt = TypeManager.TypeToCoreType (orig_best_pd.ParameterType (j));
3477 Type specific = MoreSpecific (ct, bt);
3481 specific_at_least_once = true;
3484 if (specific_at_least_once)
3487 // FIXME: handle lifted operators
3493 protected override MemberExpr ResolveExtensionMemberAccess (Expression left)
3496 return base.ResolveExtensionMemberAccess (left);
3499 // When left side is an expression and at least one candidate method is
3500 // static, it can be extension method
3502 InstanceExpression = left;
3506 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3507 SimpleName original)
3509 if (!(left is TypeExpr) &&
3510 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3511 IdenticalTypeName = true;
3513 return base.ResolveMemberAccess (ec, left, loc, original);
3516 override public Expression DoResolve (EmitContext ec)
3518 if (InstanceExpression != null) {
3519 InstanceExpression = InstanceExpression.DoResolve (ec);
3520 if (InstanceExpression == null)
3527 public void ReportUsageError ()
3529 Report.Error (654, loc, "Method `" + DeclaringType + "." +
3530 Name + "()' is referenced without parentheses");
3533 override public void Emit (EmitContext ec)
3535 ReportUsageError ();
3538 public virtual void EmitArguments (EmitContext ec, ArrayList arguments)
3540 Invocation.EmitArguments (ec, best_candidate, arguments, false, null);
3543 public virtual void EmitCall (EmitContext ec, ArrayList arguments)
3545 Invocation.EmitCall (ec, IsBase, InstanceExpression, best_candidate, arguments, loc);
3548 protected virtual void Error_InvalidArguments (EmitContext ec, Location loc, int idx, MethodBase method,
3549 Argument a, ParameterData expected_par, Type paramType)
3551 if (a is CollectionElementInitializer.ElementInitializerArgument) {
3552 Report.SymbolRelatedToPreviousError (method);
3553 if ((expected_par.ParameterModifier (idx) & Parameter.Modifier.ISBYREF) != 0) {
3554 Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
3555 TypeManager.CSharpSignature (method));
3558 Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
3559 TypeManager.CSharpSignature (method));
3560 } else if (delegate_type == null) {
3561 Report.SymbolRelatedToPreviousError (method);
3562 Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
3563 TypeManager.CSharpSignature (method));
3565 Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
3566 TypeManager.CSharpName (delegate_type));
3568 Parameter.Modifier mod = expected_par.ParameterModifier (idx);
3570 string index = (idx + 1).ToString ();
3571 if ((mod & Parameter.Modifier.ISBYREF) != (a.Modifier & Parameter.Modifier.ISBYREF) ||
3572 (mod & Parameter.Modifier.ISBYREF) != 0) {
3573 if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) == 0)
3574 Report.Error (1615, loc, "Argument `{0}' should not be passed with the `{1}' keyword",
3575 index, Parameter.GetModifierSignature (a.Modifier));
3577 Report.Error (1620, loc, "Argument `{0}' must be passed with the `{1}' keyword",
3578 index, Parameter.GetModifierSignature (mod));
3580 string p1 = Argument.FullDesc (a);
3581 string p2 = TypeManager.CSharpName (paramType);
3584 Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
3585 Report.SymbolRelatedToPreviousError (a.Expr.Type);
3586 Report.SymbolRelatedToPreviousError (paramType);
3588 Report.Error (1503, loc, "Argument {0}: Cannot convert type `{1}' to `{2}'", index, p1, p2);
3592 protected virtual int GetApplicableParametersCount (MethodBase method, ParameterData parameters)
3594 return parameters.Count;
3597 public static bool IsAncestralType (Type first_type, Type second_type)
3599 return first_type != second_type &&
3600 (TypeManager.IsSubclassOf (second_type, first_type) ||
3601 TypeManager.ImplementsInterface (second_type, first_type));
3605 /// Determines if the candidate method is applicable (section 14.4.2.1)
3606 /// to the given set of arguments
3607 /// A return value rates candidate method compatibility,
3608 /// 0 = the best, int.MaxValue = the worst
3610 public int IsApplicable (EmitContext ec,
3611 ArrayList arguments, int arg_count, ref MethodBase method, ref bool params_expanded_form)
3613 MethodBase candidate = method;
3615 ParameterData pd = TypeManager.GetParameterData (candidate);
3616 int param_count = GetApplicableParametersCount (candidate, pd);
3618 if (arg_count != param_count) {
3620 return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
3621 if (arg_count < param_count - 1)
3622 return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
3627 // 1. Handle generic method using type arguments when specified or type inference
3629 if (TypeManager.IsGenericMethod (candidate)) {
3630 if (type_arguments != null) {
3631 Type [] g_args = candidate.GetGenericArguments ();
3632 if (g_args.Length != type_arguments.Count)
3633 return int.MaxValue - 20000 + Math.Abs (type_arguments.Count - g_args.Length);
3635 // TODO: Don't create new method, create Parameters only
3636 method = ((MethodInfo) candidate).MakeGenericMethod (type_arguments.Arguments);
3638 pd = TypeManager.GetParameterData (candidate);
3640 int score = TypeManager.InferTypeArguments (ec, arguments, ref candidate);
3642 return score - 20000;
3644 if (TypeManager.IsGenericMethodDefinition (candidate))
3645 throw new InternalErrorException ("a generic method definition took part in overload resolution");
3647 pd = TypeManager.GetParameterData (candidate);
3650 if (type_arguments != null)
3651 return int.MaxValue - 15000;
3656 // 2. Each argument has to be implicitly convertible to method parameter
3658 Parameter.Modifier p_mod = 0;
3660 for (int i = 0; i < arg_count; i++) {
3661 Argument a = (Argument) arguments [i];
3662 Parameter.Modifier a_mod = a.Modifier &
3663 ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3665 if (p_mod != Parameter.Modifier.PARAMS) {
3666 p_mod = pd.ParameterModifier (i) & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3668 if (p_mod == Parameter.Modifier.ARGLIST) {
3669 if (a.Type == TypeManager.runtime_argument_handle_type)
3675 pt = pd.ParameterType (i);
3677 params_expanded_form = true;
3681 if (!params_expanded_form)
3682 score = IsArgumentCompatible (ec, a_mod, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
3684 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0) {
3685 // It can be applicable in expanded form
3686 score = IsArgumentCompatible (ec, a_mod, a, 0, pt.GetElementType ());
3688 params_expanded_form = true;
3692 return (arg_count - i) * 2 + score;
3695 if (arg_count != param_count)
3696 params_expanded_form = true;
3702 int IsArgumentCompatible (EmitContext ec, Parameter.Modifier arg_mod, Argument argument, Parameter.Modifier param_mod, Type parameter)
3705 // Types have to be identical when ref or out modifer is used
3707 if (arg_mod != 0 || param_mod != 0) {
3708 if (TypeManager.HasElementType (parameter))
3709 parameter = parameter.GetElementType ();
3711 Type a_type = argument.Type;
3712 if (TypeManager.HasElementType (a_type))
3713 a_type = a_type.GetElementType ();
3715 if (a_type != parameter)
3721 // FIXME: Kill this abomination (EmitContext.TempEc)
3722 EmitContext prevec = EmitContext.TempEc;
3723 EmitContext.TempEc = ec;
3725 if (delegate_type != null ?
3726 !Delegate.IsTypeCovariant (argument.Expr, parameter) :
3727 !Convert.ImplicitConversionExists (ec, argument.Expr, parameter))
3730 if (arg_mod != param_mod)
3734 EmitContext.TempEc = prevec;
3740 public static bool IsOverride (MethodBase cand_method, MethodBase base_method)
3742 if (!IsAncestralType (base_method.DeclaringType, cand_method.DeclaringType))
3745 ParameterData cand_pd = TypeManager.GetParameterData (cand_method);
3746 ParameterData base_pd = TypeManager.GetParameterData (base_method);
3748 if (cand_pd.Count != base_pd.Count)
3751 for (int j = 0; j < cand_pd.Count; ++j)
3753 Parameter.Modifier cm = cand_pd.ParameterModifier (j);
3754 Parameter.Modifier bm = base_pd.ParameterModifier (j);
3755 Type ct = TypeManager.TypeToCoreType (cand_pd.ParameterType (j));
3756 Type bt = TypeManager.TypeToCoreType (base_pd.ParameterType (j));
3758 if (cm != bm || ct != bt)
3765 public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2, Location loc)
3767 MemberInfo [] miset;
3768 MethodGroupExpr union;
3773 return (MethodGroupExpr) mg2;
3776 return (MethodGroupExpr) mg1;
3779 MethodGroupExpr left_set = null, right_set = null;
3780 int length1 = 0, length2 = 0;
3782 left_set = (MethodGroupExpr) mg1;
3783 length1 = left_set.Methods.Length;
3785 right_set = (MethodGroupExpr) mg2;
3786 length2 = right_set.Methods.Length;
3788 ArrayList common = new ArrayList ();
3790 foreach (MethodBase r in right_set.Methods){
3791 if (TypeManager.ArrayContainsMethod (left_set.Methods, r))
3795 miset = new MemberInfo [length1 + length2 - common.Count];
3796 left_set.Methods.CopyTo (miset, 0);
3800 foreach (MethodBase r in right_set.Methods) {
3801 if (!common.Contains (r))
3805 union = new MethodGroupExpr (miset, mg1.Type, loc);
3810 static Type MoreSpecific (Type p, Type q)
3812 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
3814 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
3817 if (TypeManager.HasElementType (p))
3819 Type pe = TypeManager.GetElementType (p);
3820 Type qe = TypeManager.GetElementType (q);
3821 Type specific = MoreSpecific (pe, qe);
3827 else if (TypeManager.IsGenericType (p))
3829 Type[] pargs = TypeManager.GetTypeArguments (p);
3830 Type[] qargs = TypeManager.GetTypeArguments (q);
3832 bool p_specific_at_least_once = false;
3833 bool q_specific_at_least_once = false;
3835 for (int i = 0; i < pargs.Length; i++)
3837 Type specific = MoreSpecific (pargs [i], qargs [i]);
3838 if (specific == pargs [i])
3839 p_specific_at_least_once = true;
3840 if (specific == qargs [i])
3841 q_specific_at_least_once = true;
3844 if (p_specific_at_least_once && !q_specific_at_least_once)
3846 if (!p_specific_at_least_once && q_specific_at_least_once)
3854 /// Find the Applicable Function Members (7.4.2.1)
3856 /// me: Method Group expression with the members to select.
3857 /// it might contain constructors or methods (or anything
3858 /// that maps to a method).
3860 /// Arguments: ArrayList containing resolved Argument objects.
3862 /// loc: The location if we want an error to be reported, or a Null
3863 /// location for "probing" purposes.
3865 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3866 /// that is the best match of me on Arguments.
3869 public virtual MethodGroupExpr OverloadResolve (EmitContext ec, ArrayList Arguments,
3870 bool may_fail, Location loc)
3872 bool method_params = false;
3873 Type applicable_type = null;
3875 ArrayList candidates = new ArrayList (2);
3876 ArrayList candidate_overrides = null;
3879 // Used to keep a map between the candidate
3880 // and whether it is being considered in its
3881 // normal or expanded form
3883 // false is normal form, true is expanded form
3885 Hashtable candidate_to_form = null;
3887 if (Arguments != null)
3888 arg_count = Arguments.Count;
3890 if (RootContext.Version == LanguageVersion.ISO_1 && Name == "Invoke" && TypeManager.IsDelegateType (DeclaringType)) {
3892 Report.Error (1533, loc, "Invoke cannot be called directly on a delegate");
3896 int nmethods = Methods.Length;
3900 // Methods marked 'override' don't take part in 'applicable_type'
3901 // computation, nor in the actual overload resolution.
3902 // However, they still need to be emitted instead of a base virtual method.
3903 // So, we salt them away into the 'candidate_overrides' array.
3905 // In case of reflected methods, we replace each overriding method with
3906 // its corresponding base virtual method. This is to improve compatibility
3907 // with non-C# libraries which change the visibility of overrides (#75636)
3910 for (int i = 0; i < Methods.Length; ++i) {
3911 MethodBase m = Methods [i];
3912 if (TypeManager.IsOverride (m)) {
3913 if (candidate_overrides == null)
3914 candidate_overrides = new ArrayList ();
3915 candidate_overrides.Add (m);
3916 m = TypeManager.TryGetBaseDefinition (m);
3925 // Enable message recording, it's used mainly by lambda expressions
3927 Report.IMessageRecorder msg_recorder = new Report.MessageRecorder ();
3928 Report.IMessageRecorder prev_recorder = Report.SetMessageRecorder (msg_recorder);
3931 // First we construct the set of applicable methods
3933 bool is_sorted = true;
3934 int best_candidate_rate = int.MaxValue;
3935 for (int i = 0; i < nmethods; i++) {
3936 Type decl_type = Methods [i].DeclaringType;
3939 // If we have already found an applicable method
3940 // we eliminate all base types (Section 14.5.5.1)
3942 if (applicable_type != null && IsAncestralType (decl_type, applicable_type))
3946 // Check if candidate is applicable (section 14.4.2.1)
3948 bool params_expanded_form = false;
3949 int candidate_rate = IsApplicable (ec, Arguments, arg_count, ref Methods [i], ref params_expanded_form);
3951 if (candidate_rate < best_candidate_rate) {
3952 best_candidate_rate = candidate_rate;
3953 best_candidate = Methods [i];
3956 if (params_expanded_form) {
3957 if (candidate_to_form == null)
3958 candidate_to_form = new PtrHashtable ();
3959 MethodBase candidate = Methods [i];
3960 candidate_to_form [candidate] = candidate;
3963 if (candidate_rate != 0) {
3964 if (msg_recorder != null)
3965 msg_recorder.EndSession ();
3969 msg_recorder = null;
3970 candidates.Add (Methods [i]);
3972 if (applicable_type == null)
3973 applicable_type = decl_type;
3974 else if (applicable_type != decl_type) {
3976 if (IsAncestralType (applicable_type, decl_type))
3977 applicable_type = decl_type;
3981 Report.SetMessageRecorder (prev_recorder);
3982 if (msg_recorder != null && msg_recorder.PrintMessages ())
3985 int candidate_top = candidates.Count;
3987 if (applicable_type == null) {
3989 // When we found a top level method which does not match and it's
3990 // not an extension method. We start extension methods lookup from here
3992 if (InstanceExpression != null) {
3993 ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (type, Name);
3994 if (ex_method_lookup != null) {
3995 ex_method_lookup.ExtensionExpression = InstanceExpression;
3996 ex_method_lookup.SetTypeArguments (type_arguments);
3997 return ex_method_lookup.OverloadResolve (ec, Arguments, may_fail, loc);
4005 // Okay so we have failed to find exact match so we
4006 // return error info about the closest match
4008 if (best_candidate != null) {
4009 if (CustomErrorHandler != null) {
4010 if (CustomErrorHandler.NoExactMatch (ec, best_candidate))
4014 ParameterData pd = TypeManager.GetParameterData (best_candidate);
4015 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4016 if (arg_count == pd.Count || pd.HasParams) {
4017 if (TypeManager.IsGenericMethod (best_candidate)) {
4018 if (type_arguments == null) {
4019 Report.Error (411, loc,
4020 "The type arguments for method `{0}' cannot be inferred from " +
4021 "the usage. Try specifying the type arguments explicitly",
4022 TypeManager.CSharpSignature (best_candidate));
4026 Type [] g_args = TypeManager.GetGenericArguments (best_candidate);
4027 if (type_arguments.Count != g_args.Length) {
4028 Report.SymbolRelatedToPreviousError (best_candidate);
4029 Report.Error (305, loc, "Using the generic method `{0}' requires `{1}' type argument(s)",
4030 TypeManager.CSharpSignature (best_candidate),
4031 g_args.Length.ToString ());
4035 if (type_arguments != null) {
4036 Namespace.Error_TypeArgumentsCannotBeUsed (best_candidate, loc);
4041 if (VerifyArgumentsCompat (ec, Arguments, arg_count, best_candidate, cand_params, may_fail, loc))
4042 throw new InternalErrorException ("Overload verification expected failure");
4047 if (almost_matched_members.Count != 0) {
4048 Error_MemberLookupFailed (ec.ContainerType, type, type, ".ctor",
4049 null, MemberTypes.Constructor, AllBindingFlags);
4054 // We failed to find any method with correct argument count
4056 if (Name == ConstructorInfo.ConstructorName) {
4057 Report.SymbolRelatedToPreviousError (type);
4058 Report.Error (1729, loc,
4059 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4060 TypeManager.CSharpName (type), arg_count);
4062 Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4063 Name, arg_count.ToString ());
4071 // At this point, applicable_type is _one_ of the most derived types
4072 // in the set of types containing the methods in this MethodGroup.
4073 // Filter the candidates so that they only contain methods from the
4074 // most derived types.
4077 int finalized = 0; // Number of finalized candidates
4080 // Invariant: applicable_type is a most derived type
4082 // We'll try to complete Section 14.5.5.1 for 'applicable_type' by
4083 // eliminating all it's base types. At the same time, we'll also move
4084 // every unrelated type to the end of the array, and pick the next
4085 // 'applicable_type'.
4087 Type next_applicable_type = null;
4088 int j = finalized; // where to put the next finalized candidate
4089 int k = finalized; // where to put the next undiscarded candidate
4090 for (int i = finalized; i < candidate_top; ++i) {
4091 MethodBase candidate = (MethodBase) candidates [i];
4092 Type decl_type = candidate.DeclaringType;
4094 if (decl_type == applicable_type) {
4095 candidates [k++] = candidates [j];
4096 candidates [j++] = candidates [i];
4100 if (IsAncestralType (decl_type, applicable_type))
4103 if (next_applicable_type != null &&
4104 IsAncestralType (decl_type, next_applicable_type))
4107 candidates [k++] = candidates [i];
4109 if (next_applicable_type == null ||
4110 IsAncestralType (next_applicable_type, decl_type))
4111 next_applicable_type = decl_type;
4114 applicable_type = next_applicable_type;
4117 } while (applicable_type != null);
4121 // Now we actually find the best method
4124 best_candidate = (MethodBase) candidates [0];
4125 method_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4126 for (int ix = 1; ix < candidate_top; ix++) {
4127 MethodBase candidate = (MethodBase) candidates [ix];
4129 if (candidate == best_candidate)
4132 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4134 if (BetterFunction (ec, Arguments, arg_count,
4135 candidate, cand_params,
4136 best_candidate, method_params)) {
4137 best_candidate = candidate;
4138 method_params = cand_params;
4142 // Now check that there are no ambiguities i.e the selected method
4143 // should be better than all the others
4145 MethodBase ambiguous = null;
4146 for (int ix = 0; ix < candidate_top; ix++) {
4147 MethodBase candidate = (MethodBase) candidates [ix];
4149 if (candidate == best_candidate)
4152 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4153 if (!BetterFunction (ec, Arguments, arg_count,
4154 best_candidate, method_params,
4155 candidate, cand_params))
4158 Report.SymbolRelatedToPreviousError (candidate);
4159 ambiguous = candidate;
4163 if (ambiguous != null) {
4164 Report.SymbolRelatedToPreviousError (best_candidate);
4165 Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4166 TypeManager.CSharpSignature (ambiguous), TypeManager.CSharpSignature (best_candidate));
4171 // If the method is a virtual function, pick an override closer to the LHS type.
4173 if (!IsBase && best_candidate.IsVirtual) {
4174 if (TypeManager.IsOverride (best_candidate))
4175 throw new InternalErrorException (
4176 "Should not happen. An 'override' method took part in overload resolution: " + best_candidate);
4178 if (candidate_overrides != null) {
4179 Type[] gen_args = null;
4180 bool gen_override = false;
4181 if (TypeManager.IsGenericMethod (best_candidate))
4182 gen_args = TypeManager.GetGenericArguments (best_candidate);
4184 foreach (MethodBase candidate in candidate_overrides) {
4185 if (TypeManager.IsGenericMethod (candidate)) {
4186 if (gen_args == null)
4189 if (gen_args.Length != TypeManager.GetGenericArguments (candidate).Length)
4192 if (gen_args != null)
4196 if (IsOverride (candidate, best_candidate)) {
4197 gen_override = true;
4198 best_candidate = candidate;
4202 if (gen_override && gen_args != null) {
4204 best_candidate = ((MethodInfo) best_candidate).MakeGenericMethod (gen_args);
4211 // And now check if the arguments are all
4212 // compatible, perform conversions if
4213 // necessary etc. and return if everything is
4216 if (!VerifyArgumentsCompat (ec, Arguments, arg_count, best_candidate,
4217 method_params, may_fail, loc))
4220 if (best_candidate == null)
4223 MethodBase the_method = TypeManager.DropGenericMethodArguments (best_candidate);
4225 if (the_method.IsGenericMethodDefinition &&
4226 !ConstraintChecker.CheckConstraints (ec, the_method, best_candidate, loc))
4230 IMethodData data = TypeManager.GetMethod (the_method);
4232 data.SetMemberIsUsed ();
4237 public override void SetTypeArguments (TypeArguments ta)
4239 type_arguments = ta;
4242 public bool VerifyArgumentsCompat (EmitContext ec, ArrayList arguments,
4243 int arg_count, MethodBase method,
4244 bool chose_params_expanded,
4245 bool may_fail, Location loc)
4247 ParameterData pd = TypeManager.GetParameterData (method);
4249 int errors = Report.Errors;
4250 Parameter.Modifier p_mod = 0;
4254 for (; a_idx < arg_count; a_idx++) {
4255 a = (Argument) arguments [a_idx];
4256 if (p_mod != Parameter.Modifier.PARAMS) {
4257 p_mod = pd.ParameterModifier (a_idx);
4258 pt = pd.ParameterType (a_idx);
4260 if (p_mod == Parameter.Modifier.ARGLIST) {
4261 if (a.Type != TypeManager.runtime_argument_handle_type)
4266 if (pt.IsPointer && !ec.InUnsafe) {
4273 if (p_mod == Parameter.Modifier.PARAMS) {
4274 if (chose_params_expanded)
4275 pt = TypeManager.GetElementType (pt);
4276 } else if (p_mod != 0) {
4277 pt = TypeManager.GetElementType (pt);
4282 // Types have to be identical when ref or out modifer is used
4284 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4285 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4288 if (!TypeManager.IsEqual (a.Expr.Type, pt))
4294 if (TypeManager.IsEqual (a.Type, pt))
4297 Expression conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4301 if (!chose_params_expanded && (p_mod & Parameter.Modifier.PARAMS) != 0 && a.Type == TypeManager.null_type)
4302 conv.Type = pd.ParameterType (a_idx);
4304 // Update the argument with the implicit conversion
4308 if (a_idx == arg_count)
4311 if (!may_fail && Report.Errors == errors)
4312 Error_InvalidArguments (ec, loc, a_idx, method, a, pd, pt);
4317 public class ConstantExpr : MemberExpr
4321 public ConstantExpr (FieldInfo constant, Location loc)
4323 this.constant = constant;
4327 public override string Name {
4328 get { throw new NotImplementedException (); }
4331 public override bool IsInstance {
4332 get { return !IsStatic; }
4335 public override bool IsStatic {
4336 get { return constant.IsStatic; }
4339 public override Type DeclaringType {
4340 get { return constant.DeclaringType; }
4343 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc, SimpleName original)
4345 constant = TypeManager.GetGenericFieldDefinition (constant);
4347 IConstant ic = TypeManager.GetConstant (constant);
4349 if (constant.IsLiteral) {
4350 ic = new ExternalConstant (constant);
4352 ic = ExternalConstant.CreateDecimal (constant);
4353 // HACK: decimal field was not resolved as constant
4355 return new FieldExpr (constant, loc).ResolveMemberAccess (ec, left, loc, original);
4357 TypeManager.RegisterConstant (constant, ic);
4360 return base.ResolveMemberAccess (ec, left, loc, original);
4363 public override Expression DoResolve (EmitContext ec)
4365 IConstant ic = TypeManager.GetConstant (constant);
4366 if (ic.ResolveValue ()) {
4367 if (!ec.IsInObsoleteScope)
4368 ic.CheckObsoleteness (loc);
4371 return ic.CreateConstantReference (loc);
4374 public override void Emit (EmitContext ec)
4376 throw new NotSupportedException ();
4379 public override string GetSignatureForError ()
4381 return TypeManager.GetFullNameSignature (constant);
4386 /// Fully resolved expression that evaluates to a Field
4388 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariable {
4389 public readonly FieldInfo FieldInfo;
4390 VariableInfo variable_info;
4392 LocalTemporary temp;
4394 bool in_initializer;
4396 public FieldExpr (FieldInfo fi, Location l, bool in_initializer):
4399 this.in_initializer = in_initializer;
4402 public FieldExpr (FieldInfo fi, Location l)
4405 eclass = ExprClass.Variable;
4406 type = TypeManager.TypeToCoreType (fi.FieldType);
4410 public override string Name {
4412 return FieldInfo.Name;
4416 public override bool IsInstance {
4418 return !FieldInfo.IsStatic;
4422 public override bool IsStatic {
4424 return FieldInfo.IsStatic;
4428 public override Type DeclaringType {
4430 return FieldInfo.DeclaringType;
4434 public override string GetSignatureForError ()
4436 return TypeManager.GetFullNameSignature (FieldInfo);
4439 public VariableInfo VariableInfo {
4441 return variable_info;
4445 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
4446 SimpleName original)
4448 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
4449 Type t = fi.FieldType;
4451 if (t.IsPointer && !ec.InUnsafe) {
4455 return base.ResolveMemberAccess (ec, left, loc, original);
4458 override public Expression DoResolve (EmitContext ec)
4460 return DoResolve (ec, false, false);
4463 Expression DoResolve (EmitContext ec, bool lvalue_instance, bool out_access)
4465 if (!FieldInfo.IsStatic){
4466 if (InstanceExpression == null){
4468 // This can happen when referencing an instance field using
4469 // a fully qualified type expression: TypeName.InstanceField = xxx
4471 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4475 // Resolve the field's instance expression while flow analysis is turned
4476 // off: when accessing a field "a.b", we must check whether the field
4477 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4479 if (lvalue_instance) {
4480 using (ec.With (EmitContext.Flags.DoFlowAnalysis, false)) {
4481 Expression right_side =
4482 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4483 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side, loc);
4486 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
4487 InstanceExpression = InstanceExpression.Resolve (ec, rf);
4490 if (InstanceExpression == null)
4493 using (ec.Set (EmitContext.Flags.OmitStructFlowAnalysis)) {
4494 InstanceExpression.CheckMarshalByRefAccess (ec);
4498 if (!in_initializer && !ec.IsInFieldInitializer) {
4499 ObsoleteAttribute oa;
4500 FieldBase f = TypeManager.GetField (FieldInfo);
4502 if (!ec.IsInObsoleteScope)
4503 f.CheckObsoleteness (loc);
4505 // To be sure that type is external because we do not register generated fields
4506 } else if (!(FieldInfo.DeclaringType is TypeBuilder)) {
4507 oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
4509 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
4513 AnonymousContainer am = ec.CurrentAnonymousMethod;
4515 if (!FieldInfo.IsStatic){
4516 if (!am.IsIterator && (ec.TypeContainer is Struct)){
4517 Report.Error (1673, loc,
4518 "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",
4525 IFixedBuffer fb = AttributeTester.GetFixedBuffer (FieldInfo);
4527 if (!ec.InFixedInitializer && ec.ContainerType.IsValueType) {
4528 Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4531 if (InstanceExpression.eclass != ExprClass.Variable) {
4532 Report.SymbolRelatedToPreviousError (FieldInfo);
4533 Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4534 TypeManager.GetFullNameSignature (FieldInfo));
4537 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4540 // If the instance expression is a local variable or parameter.
4541 IVariable var = InstanceExpression as IVariable;
4542 if ((var == null) || (var.VariableInfo == null))
4545 VariableInfo vi = var.VariableInfo;
4546 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
4549 variable_info = vi.GetSubStruct (FieldInfo.Name);
4553 static readonly int [] codes = {
4554 191, // instance, write access
4555 192, // instance, out access
4556 198, // static, write access
4557 199, // static, out access
4558 1648, // member of value instance, write access
4559 1649, // member of value instance, out access
4560 1650, // member of value static, write access
4561 1651 // member of value static, out access
4564 static readonly string [] msgs = {
4565 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4566 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4567 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4568 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4569 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4570 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4571 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4572 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4575 // The return value is always null. Returning a value simplifies calling code.
4576 Expression Report_AssignToReadonly (Expression right_side)
4579 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4583 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4585 Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4590 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4592 IVariable var = InstanceExpression as IVariable;
4593 if ((var != null) && (var.VariableInfo != null))
4594 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
4596 bool lvalue_instance = !FieldInfo.IsStatic && FieldInfo.DeclaringType.IsValueType;
4597 bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
4599 Expression e = DoResolve (ec, lvalue_instance, out_access);
4604 FieldBase fb = TypeManager.GetField (FieldInfo);
4608 if (FieldInfo.IsInitOnly) {
4609 // InitOnly fields can only be assigned in constructors or initializers
4610 if (!ec.IsInFieldInitializer && !ec.IsConstructor)
4611 return Report_AssignToReadonly (right_side);
4613 if (ec.IsConstructor) {
4614 Type ctype = ec.TypeContainer.CurrentType;
4616 ctype = ec.ContainerType;
4618 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4619 if (!TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
4620 return Report_AssignToReadonly (right_side);
4621 // static InitOnly fields cannot be assigned-to in an instance constructor
4622 if (IsStatic && !ec.IsStatic)
4623 return Report_AssignToReadonly (right_side);
4624 // instance constructors can't modify InitOnly fields of other instances of the same type
4625 if (!IsStatic && !(InstanceExpression is This))
4626 return Report_AssignToReadonly (right_side);
4630 if (right_side == EmptyExpression.OutAccess &&
4631 !IsStatic && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
4632 Report.SymbolRelatedToPreviousError (DeclaringType);
4633 Report.Warning (197, 1, loc,
4634 "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",
4635 GetSignatureForError ());
4641 public override void CheckMarshalByRefAccess (EmitContext ec)
4643 if (!IsStatic && Type.IsValueType && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
4644 Report.SymbolRelatedToPreviousError (DeclaringType);
4645 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",
4646 GetSignatureForError ());
4650 public bool VerifyFixed ()
4652 IVariable variable = InstanceExpression as IVariable;
4653 // A variable of the form V.I is fixed when V is a fixed variable of a struct type.
4654 // We defer the InstanceExpression check after the variable check to avoid a
4655 // separate null check on InstanceExpression.
4656 return variable != null && InstanceExpression.Type.IsValueType && variable.VerifyFixed ();
4659 public override int GetHashCode ()
4661 return FieldInfo.GetHashCode ();
4664 public override bool Equals (object obj)
4666 FieldExpr fe = obj as FieldExpr;
4670 if (FieldInfo != fe.FieldInfo)
4673 if (InstanceExpression == null || fe.InstanceExpression == null)
4676 return InstanceExpression.Equals (fe.InstanceExpression);
4679 public void Emit (EmitContext ec, bool leave_copy)
4681 ILGenerator ig = ec.ig;
4682 bool is_volatile = false;
4684 FieldBase f = TypeManager.GetField (FieldInfo);
4686 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4689 f.SetMemberIsUsed ();
4692 if (FieldInfo.IsStatic){
4694 ig.Emit (OpCodes.Volatile);
4696 ig.Emit (OpCodes.Ldsfld, FieldInfo);
4699 EmitInstance (ec, false);
4701 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
4703 ig.Emit (OpCodes.Ldflda, FieldInfo);
4704 ig.Emit (OpCodes.Ldflda, ff.Element);
4707 ig.Emit (OpCodes.Volatile);
4709 ig.Emit (OpCodes.Ldfld, FieldInfo);
4714 ec.ig.Emit (OpCodes.Dup);
4715 if (!FieldInfo.IsStatic) {
4716 temp = new LocalTemporary (this.Type);
4722 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4724 FieldAttributes fa = FieldInfo.Attributes;
4725 bool is_static = (fa & FieldAttributes.Static) != 0;
4726 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
4727 ILGenerator ig = ec.ig;
4729 if (is_readonly && !ec.IsConstructor){
4730 Report_AssignToReadonly (source);
4735 // String concatenation creates a new string instance
4737 prepared = prepare_for_load && !(source is StringConcat);
4738 EmitInstance (ec, prepared);
4742 ec.ig.Emit (OpCodes.Dup);
4743 if (!FieldInfo.IsStatic) {
4744 temp = new LocalTemporary (this.Type);
4749 FieldBase f = TypeManager.GetField (FieldInfo);
4751 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4752 ig.Emit (OpCodes.Volatile);
4758 ig.Emit (OpCodes.Stsfld, FieldInfo);
4760 ig.Emit (OpCodes.Stfld, FieldInfo);
4768 public override void Emit (EmitContext ec)
4773 public void AddressOf (EmitContext ec, AddressOp mode)
4775 ILGenerator ig = ec.ig;
4777 FieldBase f = TypeManager.GetField (FieldInfo);
4779 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
4780 Report.Warning (420, 1, loc, "`{0}': A volatile field references will not be treated as volatile",
4781 f.GetSignatureForError ());
4784 if ((mode & AddressOp.Store) != 0)
4786 if ((mode & AddressOp.Load) != 0)
4787 f.SetMemberIsUsed ();
4791 // Handle initonly fields specially: make a copy and then
4792 // get the address of the copy.
4795 if (FieldInfo.IsInitOnly){
4797 if (ec.IsConstructor){
4798 if (FieldInfo.IsStatic){
4810 local = ig.DeclareLocal (type);
4811 ig.Emit (OpCodes.Stloc, local);
4812 ig.Emit (OpCodes.Ldloca, local);
4817 if (FieldInfo.IsStatic){
4818 ig.Emit (OpCodes.Ldsflda, FieldInfo);
4821 EmitInstance (ec, false);
4822 ig.Emit (OpCodes.Ldflda, FieldInfo);
4829 /// Expression that evaluates to a Property. The Assign class
4830 /// might set the `Value' expression if we are in an assignment.
4832 /// This is not an LValue because we need to re-write the expression, we
4833 /// can not take data from the stack and store it.
4835 public class PropertyExpr : MemberExpr, IAssignMethod {
4836 public readonly PropertyInfo PropertyInfo;
4837 MethodInfo getter, setter;
4842 LocalTemporary temp;
4845 public PropertyExpr (Type container_type, PropertyInfo pi, Location l)
4848 eclass = ExprClass.PropertyAccess;
4852 type = TypeManager.TypeToCoreType (pi.PropertyType);
4854 ResolveAccessors (container_type);
4857 public override string Name {
4859 return PropertyInfo.Name;
4863 public override bool IsInstance {
4869 public override bool IsStatic {
4875 public override Type DeclaringType {
4877 return PropertyInfo.DeclaringType;
4881 public override string GetSignatureForError ()
4883 return TypeManager.GetFullNameSignature (PropertyInfo);
4886 void FindAccessors (Type invocation_type)
4888 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
4889 BindingFlags.Static | BindingFlags.Instance |
4890 BindingFlags.DeclaredOnly;
4892 Type current = PropertyInfo.DeclaringType;
4893 for (; current != null; current = current.BaseType) {
4894 MemberInfo[] group = TypeManager.MemberLookup (
4895 invocation_type, invocation_type, current,
4896 MemberTypes.Property, flags, PropertyInfo.Name, null);
4901 if (group.Length != 1)
4902 // Oooops, can this ever happen ?
4905 PropertyInfo pi = (PropertyInfo) group [0];
4908 getter = pi.GetGetMethod (true);
4911 setter = pi.GetSetMethod (true);
4913 MethodInfo accessor = getter != null ? getter : setter;
4915 if (!accessor.IsVirtual)
4921 // We also perform the permission checking here, as the PropertyInfo does not
4922 // hold the information for the accessibility of its setter/getter
4924 // TODO: Refactor to use some kind of cache together with GetPropertyFromAccessor
4925 void ResolveAccessors (Type container_type)
4927 FindAccessors (container_type);
4929 if (getter != null) {
4930 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
4931 IMethodData md = TypeManager.GetMethod (the_getter);
4933 md.SetMemberIsUsed ();
4935 is_static = getter.IsStatic;
4938 if (setter != null) {
4939 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
4940 IMethodData md = TypeManager.GetMethod (the_setter);
4942 md.SetMemberIsUsed ();
4944 is_static = setter.IsStatic;
4948 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
4951 InstanceExpression = null;
4955 if (InstanceExpression == null) {
4956 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4960 InstanceExpression = InstanceExpression.DoResolve (ec);
4961 if (lvalue_instance && InstanceExpression != null)
4962 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
4964 if (InstanceExpression == null)
4967 InstanceExpression.CheckMarshalByRefAccess (ec);
4969 if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) &&
4970 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
4971 !TypeManager.IsNestedChildOf (ec.ContainerType, InstanceExpression.Type) &&
4972 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.ContainerType)) {
4973 Report.SymbolRelatedToPreviousError (PropertyInfo);
4974 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
4981 void Error_PropertyNotFound (MethodInfo mi, bool getter)
4983 // TODO: correctly we should compare arguments but it will lead to bigger changes
4984 if (mi is MethodBuilder) {
4985 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
4989 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
4991 ParameterData iparams = TypeManager.GetParameterData (mi);
4992 sig.Append (getter ? "get_" : "set_");
4994 sig.Append (iparams.GetSignatureForError ());
4996 Report.SymbolRelatedToPreviousError (mi);
4997 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
4998 Name, sig.ToString ());
5001 public bool IsAccessibleFrom (Type invocation_type, bool lvalue)
5004 MethodInfo accessor = lvalue ? setter : getter;
5005 if (accessor == null && lvalue)
5007 return accessor != null && IsAccessorAccessible (invocation_type, accessor, out dummy);
5010 override public Expression DoResolve (EmitContext ec)
5015 if (getter != null){
5016 if (TypeManager.GetParameterData (getter).Count != 0){
5017 Error_PropertyNotFound (getter, true);
5022 if (getter == null){
5024 // The following condition happens if the PropertyExpr was
5025 // created, but is invalid (ie, the property is inaccessible),
5026 // and we did not want to embed the knowledge about this in
5027 // the caller routine. This only avoids double error reporting.
5032 if (InstanceExpression != EmptyExpression.Null) {
5033 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5034 TypeManager.GetFullNameSignature (PropertyInfo));
5039 bool must_do_cs1540_check = false;
5040 if (getter != null &&
5041 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
5042 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
5043 if (pm != null && pm.HasCustomAccessModifier) {
5044 Report.SymbolRelatedToPreviousError (pm);
5045 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5046 TypeManager.CSharpSignature (getter));
5049 Report.SymbolRelatedToPreviousError (getter);
5050 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
5055 if (!InstanceResolve (ec, false, must_do_cs1540_check))
5059 // Only base will allow this invocation to happen.
5061 if (IsBase && getter.IsAbstract) {
5062 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5066 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
5076 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
5078 if (right_side == EmptyExpression.OutAccess) {
5079 if (ec.CurrentBlock.Toplevel.GetTransparentIdentifier (PropertyInfo.Name) != null) {
5080 Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5083 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as `ref' or `out' parameter",
5084 GetSignatureForError ());
5089 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5090 Error_CannotModifyIntermediateExpressionValue (ec);
5093 if (setter == null){
5095 // The following condition happens if the PropertyExpr was
5096 // created, but is invalid (ie, the property is inaccessible),
5097 // and we did not want to embed the knowledge about this in
5098 // the caller routine. This only avoids double error reporting.
5102 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
5103 GetSignatureForError ());
5107 if (TypeManager.GetParameterData (setter).Count != 1){
5108 Error_PropertyNotFound (setter, false);
5112 bool must_do_cs1540_check;
5113 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
5114 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
5115 if (pm != null && pm.HasCustomAccessModifier) {
5116 Report.SymbolRelatedToPreviousError (pm);
5117 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5118 TypeManager.CSharpSignature (setter));
5121 Report.SymbolRelatedToPreviousError (setter);
5122 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
5127 if (!InstanceResolve (ec, PropertyInfo.DeclaringType.IsValueType, must_do_cs1540_check))
5131 // Only base will allow this invocation to happen.
5133 if (IsBase && setter.IsAbstract){
5134 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5141 public override void Emit (EmitContext ec)
5146 public void Emit (EmitContext ec, bool leave_copy)
5149 // Special case: length of single dimension array property is turned into ldlen
5151 if ((getter == TypeManager.system_int_array_get_length) ||
5152 (getter == TypeManager.int_array_get_length)){
5153 Type iet = InstanceExpression.Type;
5156 // System.Array.Length can be called, but the Type does not
5157 // support invoking GetArrayRank, so test for that case first
5159 if (iet != TypeManager.array_type && (iet.GetArrayRank () == 1)) {
5161 EmitInstance (ec, false);
5162 ec.ig.Emit (OpCodes.Ldlen);
5163 ec.ig.Emit (OpCodes.Conv_I4);
5168 Invocation.EmitCall (ec, IsBase, InstanceExpression, getter, null, loc, prepared, false);
5171 ec.ig.Emit (OpCodes.Dup);
5173 temp = new LocalTemporary (this.Type);
5180 // Implements the IAssignMethod interface for assignments
5182 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5184 Expression my_source = source;
5186 if (prepare_for_load) {
5187 if (source is StringConcat)
5188 EmitInstance (ec, false);
5196 ec.ig.Emit (OpCodes.Dup);
5198 temp = new LocalTemporary (this.Type);
5202 } else if (leave_copy) {
5204 temp = new LocalTemporary (this.Type);
5209 ArrayList args = new ArrayList (1);
5210 args.Add (new Argument (my_source, Argument.AType.Expression));
5212 Invocation.EmitCall (ec, IsBase, InstanceExpression, setter, args, loc, false, prepared);
5222 /// Fully resolved expression that evaluates to an Event
5224 public class EventExpr : MemberExpr {
5225 public readonly EventInfo EventInfo;
5228 MethodInfo add_accessor, remove_accessor;
5230 public EventExpr (EventInfo ei, Location loc)
5234 eclass = ExprClass.EventAccess;
5236 add_accessor = TypeManager.GetAddMethod (ei);
5237 remove_accessor = TypeManager.GetRemoveMethod (ei);
5238 if (add_accessor.IsStatic || remove_accessor.IsStatic)
5241 if (EventInfo is MyEventBuilder){
5242 MyEventBuilder eb = (MyEventBuilder) EventInfo;
5243 type = eb.EventType;
5246 type = EventInfo.EventHandlerType;
5249 public override string Name {
5251 return EventInfo.Name;
5255 public override bool IsInstance {
5261 public override bool IsStatic {
5267 public override Type DeclaringType {
5269 return EventInfo.DeclaringType;
5273 void Error_AssignmentEventOnly ()
5275 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5276 GetSignatureForError ());
5279 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
5280 SimpleName original)
5283 // If the event is local to this class, we transform ourselves into a FieldExpr
5286 if (EventInfo.DeclaringType == ec.ContainerType ||
5287 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
5288 EventField mi = TypeManager.GetEventField (EventInfo);
5291 if (!ec.IsInObsoleteScope)
5292 mi.CheckObsoleteness (loc);
5294 if ((mi.ModFlags & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0 && !ec.IsInCompoundAssignment)
5295 Error_AssignmentEventOnly ();
5297 FieldExpr ml = new FieldExpr (mi.FieldBuilder, loc);
5299 InstanceExpression = null;
5301 return ml.ResolveMemberAccess (ec, left, loc, original);
5305 if (left is This && !ec.IsInCompoundAssignment)
5306 Error_AssignmentEventOnly ();
5308 return base.ResolveMemberAccess (ec, left, loc, original);
5312 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
5315 InstanceExpression = null;
5319 if (InstanceExpression == null) {
5320 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5324 InstanceExpression = InstanceExpression.DoResolve (ec);
5325 if (InstanceExpression == null)
5328 if (IsBase && add_accessor.IsAbstract) {
5329 Error_CannotCallAbstractBase(TypeManager.CSharpSignature(add_accessor));
5334 // This is using the same mechanism as the CS1540 check in PropertyExpr.
5335 // However, in the Event case, we reported a CS0122 instead.
5337 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
5338 InstanceExpression.Type != ec.ContainerType &&
5339 ec.ContainerType.IsSubclassOf (InstanceExpression.Type)) {
5340 Report.SymbolRelatedToPreviousError (EventInfo);
5341 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5348 public bool IsAccessibleFrom (Type invocation_type)
5351 return IsAccessorAccessible (invocation_type, add_accessor, out dummy) &&
5352 IsAccessorAccessible (invocation_type, remove_accessor, out dummy);
5355 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5357 return DoResolve (ec);
5360 public override Expression DoResolve (EmitContext ec)
5362 bool must_do_cs1540_check;
5363 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
5364 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
5365 Report.SymbolRelatedToPreviousError (EventInfo);
5366 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5370 if (!InstanceResolve (ec, must_do_cs1540_check))
5376 public override void Emit (EmitContext ec)
5378 Report.Error (70, loc, "The event `{0}' can only appear on the left hand side of += or -= "+
5379 "(except on the defining type)", GetSignatureForError ());
5382 public override string GetSignatureForError ()
5384 return TypeManager.CSharpSignature (EventInfo);
5387 public void EmitAddOrRemove (EmitContext ec, Expression source)
5389 BinaryDelegate source_del = source as BinaryDelegate;
5390 if (source_del == null) {
5394 Expression handler = source_del.Right;
5396 Argument arg = new Argument (handler, Argument.AType.Expression);
5397 ArrayList args = new ArrayList ();
5401 if (source_del.IsAddition)
5402 Invocation.EmitCall (
5403 ec, IsBase, InstanceExpression, add_accessor, args, loc);
5405 Invocation.EmitCall (
5406 ec, IsBase, InstanceExpression, remove_accessor, args, loc);
5410 public class TemporaryVariable : Expression, IMemoryLocation
5415 public TemporaryVariable (Type type, Location loc)
5419 eclass = ExprClass.Value;
5422 public override Expression DoResolve (EmitContext ec)
5427 TypeExpr te = new TypeExpression (type, loc);
5428 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
5429 if (!li.Resolve (ec))
5432 if (ec.MustCaptureVariable (li)) {
5433 ScopeInfo scope = li.Block.CreateScopeInfo ();
5434 var = scope.AddLocal (li);
5441 public Variable Variable {
5442 get { return var != null ? var : li.Variable; }
5445 public override void Emit (EmitContext ec)
5447 Variable.EmitInstance (ec);
5451 public void EmitLoadAddress (EmitContext ec)
5453 Variable.EmitInstance (ec);
5454 Variable.EmitAddressOf (ec);
5457 public void Store (EmitContext ec, Expression right_side)
5459 Variable.EmitInstance (ec);
5460 right_side.Emit (ec);
5461 Variable.EmitAssign (ec);
5464 public void EmitThis (EmitContext ec)
5466 Variable.EmitInstance (ec);
5469 public void EmitStore (EmitContext ec)
5471 Variable.EmitAssign (ec);
5474 public void AddressOf (EmitContext ec, AddressOp mode)
5476 EmitLoadAddress (ec);
5481 /// Handles `var' contextual keyword; var becomes a keyword only
5482 /// if no type called var exists in a variable scope
5484 public class VarExpr : SimpleName
5486 // Used for error reporting only
5487 ArrayList initializer;
5489 public VarExpr (Location loc)
5494 public ArrayList VariableInitializer {
5496 this.initializer = value;
5500 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5503 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
5505 type = right_side.Type;
5506 if (type == TypeManager.null_type || type == TypeManager.void_type || type == TypeManager.anonymous_method_type) {
5507 Report.Error (815, loc, "An implicitly typed local variable declaration cannot be initialized with `{0}'",
5508 right_side.GetSignatureForError ());
5512 eclass = ExprClass.Variable;
5516 protected override void Error_TypeOrNamespaceNotFound (IResolveContext ec)
5518 Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");
5521 public override TypeExpr ResolveAsContextualType (IResolveContext rc, bool silent)
5523 TypeExpr te = base.ResolveAsContextualType (rc, true);
5527 if (initializer == null)
5530 if (initializer.Count > 1) {
5531 Location loc = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [1]).Location;
5532 Report.Error (819, loc, "An implicitly typed local variable declaration cannot include multiple declarators");
5537 Expression variable_initializer = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [0]).expression_or_array_initializer;
5538 if (variable_initializer == null) {
5539 Report.Error (818, loc, "An implicitly typed local variable declarator must include an initializer");