2 // ecore.cs: Core of the Expression representation for the intermediate tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@seznam.cz)
8 // (C) 2001, 2002, 2003 Ximian, Inc.
12 namespace Mono.CSharp {
14 using System.Collections;
15 using System.Diagnostics;
16 using System.Reflection;
17 using System.Reflection.Emit;
21 /// The ExprClass class contains the is used to pass the
22 /// classification of an expression (value, variable, namespace,
23 /// type, method group, property access, event access, indexer access,
26 public enum ExprClass : byte {
41 /// This is used to tell Resolve in which types of expressions we're
45 public enum ResolveFlags {
46 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
49 // Returns a type expression.
52 // Returns a method group.
55 // Mask of all the expression class flags.
58 // Disable control flow analysis while resolving the expression.
59 // This is used when resolving the instance expression of a field expression.
60 DisableFlowAnalysis = 8,
62 // Set if this is resolving the first part of a MemberAccess.
65 // Disable control flow analysis _of struct_ while resolving the expression.
66 // This is used when resolving the instance expression of a field expression.
67 DisableStructFlowAnalysis = 32,
72 // This is just as a hint to AddressOf of what will be done with the
75 public enum AddressOp {
82 /// This interface is implemented by variables
84 public interface IMemoryLocation {
86 /// The AddressOf method should generate code that loads
87 /// the address of the object and leaves it on the stack.
89 /// The `mode' argument is used to notify the expression
90 /// of whether this will be used to read from the address or
91 /// write to the address.
93 /// This is just a hint that can be used to provide good error
94 /// reporting, and should have no other side effects.
96 void AddressOf (EmitContext ec, AddressOp mode);
100 /// This interface is implemented by variables
102 public interface IVariable {
103 VariableInfo VariableInfo {
111 /// Base class for expressions
113 public abstract class Expression {
114 public ExprClass eclass;
116 protected Location loc;
120 set { type = value; }
123 public virtual Location Location {
128 /// Utility wrapper routine for Error, just to beautify the code
130 public void Error (int error, string s)
132 Report.Error (error, loc, s);
135 // Not nice but we have broken hierarchy.
136 public virtual void CheckMarshalByRefAccess ()
140 public virtual bool GetAttributableValue (Type valueType, out object value)
142 Attribute.Error_AttributeArgumentNotValid (loc);
147 public virtual string GetSignatureForError ()
149 return TypeManager.CSharpName (type);
152 public static bool IsAccessorAccessible (Type invocation_type, MethodInfo mi, out bool must_do_cs1540_check)
154 MethodAttributes ma = mi.Attributes & MethodAttributes.MemberAccessMask;
156 must_do_cs1540_check = false; // by default we do not check for this
158 if (ma == MethodAttributes.Public)
162 // If only accessible to the current class or children
164 if (ma == MethodAttributes.Private)
165 return TypeManager.IsPrivateAccessible (invocation_type, mi.DeclaringType) ||
166 TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType);
168 if (mi.DeclaringType.Assembly == invocation_type.Assembly ||
169 TypeManager.IsFriendAssembly (mi.DeclaringType.Assembly)) {
170 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamORAssem)
173 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamANDAssem)
177 // Family and FamANDAssem require that we derive.
178 // FamORAssem requires that we derive if in different assemblies.
179 if (!TypeManager.IsNestedFamilyAccessible (invocation_type, mi.DeclaringType))
182 if (!TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType))
183 must_do_cs1540_check = true;
189 /// Performs semantic analysis on the Expression
193 /// The Resolve method is invoked to perform the semantic analysis
196 /// The return value is an expression (it can be the
197 /// same expression in some cases) or a new
198 /// expression that better represents this node.
200 /// For example, optimizations of Unary (LiteralInt)
201 /// would return a new LiteralInt with a negated
204 /// If there is an error during semantic analysis,
205 /// then an error should be reported (using Report)
206 /// and a null value should be returned.
208 /// There are two side effects expected from calling
209 /// Resolve(): the the field variable "eclass" should
210 /// be set to any value of the enumeration
211 /// `ExprClass' and the type variable should be set
212 /// to a valid type (this is the type of the
215 public abstract Expression DoResolve (EmitContext ec);
217 public virtual Expression DoResolveLValue (EmitContext ec, Expression right_side)
223 // This is used if the expression should be resolved as a type or namespace name.
224 // the default implementation fails.
226 public virtual FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
232 // This is used to resolve the expression as a type, a null
233 // value will be returned if the expression is not a type
236 public virtual TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
238 TypeExpr te = ResolveAsBaseTerminal (ec, silent);
243 ObsoleteAttribute obsolete_attr = AttributeTester.GetObsoleteAttribute (te.Type);
244 if (obsolete_attr != null && !ec.IsInObsoleteScope) {
245 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location);
249 // Constrains don't need to be checked for overrides
250 GenericMethod gm = ec.GenericDeclContainer as GenericMethod;
251 if (gm != null && (gm.ModFlags & Modifiers.OVERRIDE) != 0) {
256 ConstructedType ct = te as ConstructedType;
257 if ((ct != null) && !ct.CheckConstraints (ec))
263 public TypeExpr ResolveAsBaseTerminal (IResolveContext ec, bool silent)
265 int errors = Report.Errors;
267 FullNamedExpression fne = ResolveAsTypeStep (ec, silent);
272 if (fne.eclass != ExprClass.Type) {
273 if (!silent && errors == Report.Errors)
274 fne.Error_UnexpectedKind (null, "type", loc);
278 TypeExpr te = fne as TypeExpr;
280 if (!te.CheckAccessLevel (ec.DeclContainer)) {
281 Report.SymbolRelatedToPreviousError (te.Type);
282 ErrorIsInaccesible (loc, TypeManager.CSharpName (te.Type));
290 public static void ErrorIsInaccesible (Location loc, string name)
292 Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", name);
295 protected static void Error_CannotAccessProtected (Location loc, MemberInfo m, Type qualifier, Type container)
297 Report.Error (1540, loc, "Cannot access protected member `{0}' via a qualifier of type `{1}'."
298 + " The qualifier must be of type `{2}' or derived from it",
299 TypeManager.GetFullNameSignature (m),
300 TypeManager.CSharpName (qualifier),
301 TypeManager.CSharpName (container));
305 protected void Error_CannotAssign (string to, string roContext)
307 Report.Error (1656, loc, "Cannot assign to `{0}' because it is a `{1}'",
311 public static void Error_VoidInvalidInTheContext (Location loc)
313 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
316 public virtual void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl)
318 if (Type.FullName == target.FullName){
319 Report.ExtraInformation (loc,
321 "The type {0} has two conflicting definitions, one comes from {1} and the other from {2}",
322 Type.FullName, Type.Assembly.FullName, target.Assembly.FullName));
327 Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
328 GetSignatureForError (), TypeManager.CSharpName (target));
332 Expression e = (this is EnumConstant) ? ((EnumConstant)this).Child : this;
333 bool b = Convert.ExplicitNumericConversion (e, target) != null;
336 Convert.ExplicitReferenceConversionExists (Type, target) ||
337 Convert.ExplicitUnsafe (e, target) != null ||
338 (ec != null && Convert.UserDefinedConversion (ec, this, target, Location.Null, true) != null))
340 Report.Error (266, loc, "Cannot implicitly convert type `{0}' to `{1}'. " +
341 "An explicit conversion exists (are you missing a cast?)",
342 TypeManager.CSharpName (Type), TypeManager.CSharpName (target));
346 if (Type != TypeManager.string_type && this is Constant && !(this is EmptyConstantCast)) {
347 Report.Error (31, loc, "Constant value `{0}' cannot be converted to a `{1}'",
348 ((Constant)(this)).GetValue ().ToString (), TypeManager.CSharpName (target));
352 Report.Error (29, loc, "Cannot implicitly convert type {0} to `{1}'",
353 Type == TypeManager.anonymous_method_type ?
354 "anonymous method" : "`" + GetSignatureForError () + "'",
355 TypeManager.CSharpName (target));
358 protected static void Error_TypeDoesNotContainDefinition (Location loc, Type type, string name)
360 Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
361 TypeManager.CSharpName (type), name);
364 protected static void Error_ValueAssignment (Location loc)
366 Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
369 ResolveFlags ExprClassToResolveFlags
374 case ExprClass.Namespace:
375 return ResolveFlags.Type;
377 case ExprClass.MethodGroup:
378 return ResolveFlags.MethodGroup;
380 case ExprClass.Value:
381 case ExprClass.Variable:
382 case ExprClass.PropertyAccess:
383 case ExprClass.EventAccess:
384 case ExprClass.IndexerAccess:
385 return ResolveFlags.VariableOrValue;
388 throw new Exception ("Expression " + GetType () +
389 " ExprClass is Invalid after resolve");
395 /// Resolves an expression and performs semantic analysis on it.
399 /// Currently Resolve wraps DoResolve to perform sanity
400 /// checking and assertion checking on what we expect from Resolve.
402 public Expression Resolve (EmitContext ec, ResolveFlags flags)
404 if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type)
405 return ResolveAsTypeStep (ec, false);
407 bool do_flow_analysis = ec.DoFlowAnalysis;
408 bool omit_struct_analysis = ec.OmitStructFlowAnalysis;
409 if ((flags & ResolveFlags.DisableFlowAnalysis) != 0)
410 do_flow_analysis = false;
411 if ((flags & ResolveFlags.DisableStructFlowAnalysis) != 0)
412 omit_struct_analysis = true;
415 using (ec.WithFlowAnalysis (do_flow_analysis, omit_struct_analysis)) {
416 if (this is SimpleName) {
417 bool intermediate = (flags & ResolveFlags.Intermediate) == ResolveFlags.Intermediate;
418 e = ((SimpleName) this).DoResolve (ec, intermediate);
427 if ((flags & e.ExprClassToResolveFlags) == 0) {
428 e.Error_UnexpectedKind (flags, loc);
432 if (e.type == null && !(e is Namespace)) {
433 throw new Exception (
434 "Expression " + e.GetType () +
435 " did not set its type after Resolve\n" +
436 "called from: " + this.GetType ());
443 /// Resolves an expression and performs semantic analysis on it.
445 public Expression Resolve (EmitContext ec)
447 Expression e = Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
449 if (e != null && e.eclass == ExprClass.MethodGroup && RootContext.Version == LanguageVersion.ISO_1) {
450 ((MethodGroupExpr) e).ReportUsageError ();
456 public Constant ResolveAsConstant (EmitContext ec, MemberCore mc)
458 Expression e = Resolve (ec);
462 Constant c = e as Constant;
466 Const.Error_ExpressionMustBeConstant (loc, mc.GetSignatureForError ());
471 /// Resolves an expression for LValue assignment
475 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
476 /// checking and assertion checking on what we expect from Resolve
478 public Expression ResolveLValue (EmitContext ec, Expression right_side, Location loc)
480 int errors = Report.Errors;
481 bool out_access = right_side == EmptyExpression.OutAccess;
483 Expression e = DoResolveLValue (ec, right_side);
485 if (e != null && out_access && !(e is IMemoryLocation)) {
486 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
487 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
489 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
490 // e.GetType () + " " + e.GetSignatureForError ());
495 if (errors == Report.Errors) {
497 Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
499 Error_ValueAssignment (loc);
504 if (e.eclass == ExprClass.Invalid)
505 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
507 if (e.eclass == ExprClass.MethodGroup) {
508 ((MethodGroupExpr) e).ReportUsageError ();
512 if ((e.type == null) && !(e is ConstructedType))
513 throw new Exception ("Expression " + e + " did not set its type after Resolve");
519 /// Emits the code for the expression
523 /// The Emit method is invoked to generate the code
524 /// for the expression.
526 public abstract void Emit (EmitContext ec);
528 public virtual void EmitBranchable (EmitContext ec, Label target, bool onTrue)
531 ec.ig.Emit (onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target);
535 /// Protected constructor. Only derivate types should
536 /// be able to be created
539 protected Expression ()
541 eclass = ExprClass.Invalid;
546 /// Returns a fully formed expression after a MemberLookup
549 public static Expression ExprClassFromMemberInfo (Type containerType, MemberInfo mi, Location loc)
552 return new EventExpr ((EventInfo) mi, loc);
553 else if (mi is FieldInfo)
554 return new FieldExpr ((FieldInfo) mi, loc);
555 else if (mi is PropertyInfo)
556 return new PropertyExpr (containerType, (PropertyInfo) mi, loc);
557 else if (mi is Type){
558 return new TypeExpression ((System.Type) mi, loc);
564 protected static ArrayList almostMatchedMembers = new ArrayList (4);
567 // FIXME: Probably implement a cache for (t,name,current_access_set)?
569 // This code could use some optimizations, but we need to do some
570 // measurements. For example, we could use a delegate to `flag' when
571 // something can not any longer be a method-group (because it is something
575 // If the return value is an Array, then it is an array of
578 // If the return value is an MemberInfo, it is anything, but a Method
582 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
583 // the arguments here and have MemberLookup return only the methods that
584 // match the argument count/type, unlike we are doing now (we delay this
587 // This is so we can catch correctly attempts to invoke instance methods
588 // from a static body (scan for error 120 in ResolveSimpleName).
591 // FIXME: Potential optimization, have a static ArrayList
594 public static Expression MemberLookup (Type container_type, Type queried_type, string name,
595 MemberTypes mt, BindingFlags bf, Location loc)
597 return MemberLookup (container_type, null, queried_type, name, mt, bf, loc);
601 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
602 // `qualifier_type' or null to lookup members in the current class.
605 public static Expression MemberLookup (Type container_type,
606 Type qualifier_type, Type queried_type,
607 string name, MemberTypes mt,
608 BindingFlags bf, Location loc)
610 almostMatchedMembers.Clear ();
612 MemberInfo [] mi = TypeManager.MemberLookup (container_type, qualifier_type,
613 queried_type, mt, bf, name, almostMatchedMembers);
619 bool is_interface = qualifier_type != null && qualifier_type.IsInterface;
620 MemberInfo non_method = null;
621 ArrayList methods = new ArrayList (2);
623 foreach (MemberInfo m in mi) {
624 if (m is MethodBase) {
629 if (non_method == null) {
634 Report.SymbolRelatedToPreviousError (m);
635 Report.SymbolRelatedToPreviousError (non_method);
636 Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
637 TypeManager.GetFullNameSignature (m), TypeManager.GetFullNameSignature (non_method));
641 if (methods.Count == 0)
644 if (non_method != null) {
645 MethodBase method = (MethodBase) methods [0];
647 if (method.DeclaringType == non_method.DeclaringType) {
648 // Cannot happen with C# code, but is valid in IL
649 Report.SymbolRelatedToPreviousError (method);
650 Report.SymbolRelatedToPreviousError (non_method);
651 Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
652 TypeManager.GetFullNameSignature (non_method),
653 TypeManager.CSharpSignature (method));
658 Report.SymbolRelatedToPreviousError (method);
659 Report.SymbolRelatedToPreviousError (non_method);
660 Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and non-method `{1}'. Using method `{0}'",
661 TypeManager.CSharpSignature (method), TypeManager.GetFullNameSignature (non_method));
665 return new MethodGroupExpr (methods, loc);
668 if (mi [0] is MethodBase)
669 return new MethodGroupExpr (mi, loc);
671 return ExprClassFromMemberInfo (container_type, mi [0], loc);
674 public const MemberTypes AllMemberTypes =
675 MemberTypes.Constructor |
679 MemberTypes.NestedType |
680 MemberTypes.Property;
682 public const BindingFlags AllBindingFlags =
683 BindingFlags.Public |
684 BindingFlags.Static |
685 BindingFlags.Instance;
687 public static Expression MemberLookup (Type container_type, Type queried_type,
688 string name, Location loc)
690 return MemberLookup (container_type, null, queried_type, name,
691 AllMemberTypes, AllBindingFlags, loc);
694 public static Expression MemberLookup (Type container_type, Type qualifier_type,
695 Type queried_type, string name, Location loc)
697 return MemberLookup (container_type, qualifier_type, queried_type,
698 name, AllMemberTypes, AllBindingFlags, loc);
701 public static Expression MethodLookup (Type container_type, Type queried_type,
702 string name, Location loc)
704 return MemberLookup (container_type, null, queried_type, name,
705 MemberTypes.Method, AllBindingFlags, loc);
709 /// This is a wrapper for MemberLookup that is not used to "probe", but
710 /// to find a final definition. If the final definition is not found, we
711 /// look for private members and display a useful debugging message if we
714 public static Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
715 Type queried_type, string name, Location loc)
717 return MemberLookupFinal (ec, qualifier_type, queried_type, name,
718 AllMemberTypes, AllBindingFlags, loc);
721 public static Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
722 Type queried_type, string name,
723 MemberTypes mt, BindingFlags bf,
728 int errors = Report.Errors;
730 e = MemberLookup (ec.ContainerType, qualifier_type, queried_type, name, mt, bf, loc);
732 if (e == null && errors == Report.Errors)
733 // No errors were reported by MemberLookup, but there was an error.
734 MemberLookupFailed (ec.ContainerType, qualifier_type, queried_type, name, null, true, loc);
739 public static void MemberLookupFailed (Type container_type, Type qualifier_type,
740 Type queried_type, string name,
741 string class_name, bool complain_if_none_found,
744 if (almostMatchedMembers.Count != 0) {
745 for (int i = 0; i < almostMatchedMembers.Count; ++i) {
746 MemberInfo m = (MemberInfo) almostMatchedMembers [i];
747 for (int j = 0; j < i; ++j) {
748 if (m == almostMatchedMembers [j]) {
756 Type declaring_type = m.DeclaringType;
758 Report.SymbolRelatedToPreviousError (m);
759 if (qualifier_type == null) {
760 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
761 TypeManager.CSharpName (m.DeclaringType),
762 TypeManager.CSharpName (container_type));
764 } else if (qualifier_type != container_type &&
765 TypeManager.IsNestedFamilyAccessible (container_type, declaring_type)) {
766 // Although a derived class can access protected members of
767 // its base class it cannot do so through an instance of the
768 // base class (CS1540). If the qualifier_type is a base of the
769 // ec.ContainerType and the lookup succeeds with the latter one,
770 // then we are in this situation.
771 Error_CannotAccessProtected (loc, m, qualifier_type, container_type);
773 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (m));
776 almostMatchedMembers.Clear ();
780 MemberInfo[] lookup = null;
781 if (queried_type == null) {
782 class_name = "global::";
784 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
785 AllMemberTypes, AllBindingFlags |
786 BindingFlags.NonPublic, name, null);
789 if (lookup == null) {
790 if (!complain_if_none_found)
793 if (class_name != null)
794 Report.Error (103, loc, "The name `{0}' does not exist in the context of `{1}'",
797 Error_TypeDoesNotContainDefinition (loc, queried_type, name);
801 if (TypeManager.MemberLookup (queried_type, null, queried_type,
802 AllMemberTypes, AllBindingFlags |
803 BindingFlags.NonPublic, name, null) == null) {
804 if ((lookup.Length == 1) && (lookup [0] is Type)) {
805 Type t = (Type) lookup [0];
807 Report.Error (305, loc,
808 "Using the generic type `{0}' " +
809 "requires {1} type arguments",
810 TypeManager.CSharpName (t),
811 TypeManager.GetNumberOfTypeArguments (t).ToString ());
816 MemberList ml = TypeManager.FindMembers (queried_type, MemberTypes.Constructor,
817 BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly, null, null);
818 if (name == ".ctor" && ml.Count == 0)
820 Report.Error (143, loc, "The type `{0}' has no constructors defined", TypeManager.CSharpName (queried_type));
824 Report.SymbolRelatedToPreviousError (lookup [0]);
825 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (lookup [0]));
829 /// Returns an expression that can be used to invoke operator true
830 /// on the expression if it exists.
832 static public Expression GetOperatorTrue (EmitContext ec, Expression e, Location loc)
834 return GetOperatorTrueOrFalse (ec, e, true, loc);
838 /// Returns an expression that can be used to invoke operator false
839 /// on the expression if it exists.
841 static public Expression GetOperatorFalse (EmitContext ec, Expression e, Location loc)
843 return GetOperatorTrueOrFalse (ec, e, false, loc);
846 static Expression GetOperatorTrueOrFalse (EmitContext ec, Expression e, bool is_true, Location loc)
849 Expression operator_group;
852 if (TypeManager.IsNullableType (e.Type))
853 return new Nullable.OperatorTrueOrFalse (e, is_true, loc).Resolve (ec);
856 operator_group = MethodLookup (ec.ContainerType, e.Type, is_true ? "op_True" : "op_False", loc);
857 if (operator_group == null)
860 ArrayList arguments = new ArrayList ();
861 arguments.Add (new Argument (e, Argument.AType.Expression));
862 method = Invocation.OverloadResolve (
863 ec, (MethodGroupExpr) operator_group, arguments, false, loc);
868 return new StaticCallExpr ((MethodInfo) method, arguments, loc);
872 /// Resolves the expression `e' into a boolean expression: either through
873 /// an implicit conversion, or through an `operator true' invocation
875 public static Expression ResolveBoolean (EmitContext ec, Expression e, Location loc)
881 if (e.Type == TypeManager.bool_type)
884 Expression converted = Convert.ImplicitConversion (ec, e, TypeManager.bool_type, Location.Null);
886 if (converted != null)
890 // If no implicit conversion to bool exists, try using `operator true'
892 converted = Expression.GetOperatorTrue (ec, e, loc);
893 if (converted == null){
894 e.Error_ValueCannotBeConverted (ec, loc, TypeManager.bool_type, false);
900 public virtual string ExprClassName
904 case ExprClass.Invalid:
906 case ExprClass.Value:
908 case ExprClass.Variable:
910 case ExprClass.Namespace:
914 case ExprClass.MethodGroup:
915 return "method group";
916 case ExprClass.PropertyAccess:
917 return "property access";
918 case ExprClass.EventAccess:
919 return "event access";
920 case ExprClass.IndexerAccess:
921 return "indexer access";
922 case ExprClass.Nothing:
925 throw new Exception ("Should not happen");
930 /// Reports that we were expecting `expr' to be of class `expected'
932 public void Error_UnexpectedKind (DeclSpace ds, string expected, Location loc)
934 Error_UnexpectedKind (ds, expected, ExprClassName, loc);
937 public void Error_UnexpectedKind (DeclSpace ds, string expected, string was, Location loc)
939 string name = GetSignatureForError ();
941 name = ds.GetSignatureForError () + '.' + name;
943 Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
944 name, was, expected);
947 public void Error_UnexpectedKind (ResolveFlags flags, Location loc)
949 string [] valid = new string [4];
952 if ((flags & ResolveFlags.VariableOrValue) != 0) {
953 valid [count++] = "variable";
954 valid [count++] = "value";
957 if ((flags & ResolveFlags.Type) != 0)
958 valid [count++] = "type";
960 if ((flags & ResolveFlags.MethodGroup) != 0)
961 valid [count++] = "method group";
964 valid [count++] = "unknown";
966 StringBuilder sb = new StringBuilder (valid [0]);
967 for (int i = 1; i < count - 1; i++) {
969 sb.Append (valid [i]);
972 sb.Append ("' or `");
973 sb.Append (valid [count - 1]);
976 Report.Error (119, loc,
977 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
980 public static void UnsafeError (Location loc)
982 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
986 // Load the object from the pointer.
988 public static void LoadFromPtr (ILGenerator ig, Type t)
990 if (t == TypeManager.int32_type)
991 ig.Emit (OpCodes.Ldind_I4);
992 else if (t == TypeManager.uint32_type)
993 ig.Emit (OpCodes.Ldind_U4);
994 else if (t == TypeManager.short_type)
995 ig.Emit (OpCodes.Ldind_I2);
996 else if (t == TypeManager.ushort_type)
997 ig.Emit (OpCodes.Ldind_U2);
998 else if (t == TypeManager.char_type)
999 ig.Emit (OpCodes.Ldind_U2);
1000 else if (t == TypeManager.byte_type)
1001 ig.Emit (OpCodes.Ldind_U1);
1002 else if (t == TypeManager.sbyte_type)
1003 ig.Emit (OpCodes.Ldind_I1);
1004 else if (t == TypeManager.uint64_type)
1005 ig.Emit (OpCodes.Ldind_I8);
1006 else if (t == TypeManager.int64_type)
1007 ig.Emit (OpCodes.Ldind_I8);
1008 else if (t == TypeManager.float_type)
1009 ig.Emit (OpCodes.Ldind_R4);
1010 else if (t == TypeManager.double_type)
1011 ig.Emit (OpCodes.Ldind_R8);
1012 else if (t == TypeManager.bool_type)
1013 ig.Emit (OpCodes.Ldind_I1);
1014 else if (t == TypeManager.intptr_type)
1015 ig.Emit (OpCodes.Ldind_I);
1016 else if (TypeManager.IsEnumType (t)) {
1017 if (t == TypeManager.enum_type)
1018 ig.Emit (OpCodes.Ldind_Ref);
1020 LoadFromPtr (ig, TypeManager.EnumToUnderlying (t));
1021 } else if (t.IsValueType || TypeManager.IsGenericParameter (t))
1022 ig.Emit (OpCodes.Ldobj, t);
1023 else if (t.IsPointer)
1024 ig.Emit (OpCodes.Ldind_I);
1026 ig.Emit (OpCodes.Ldind_Ref);
1030 // The stack contains the pointer and the value of type `type'
1032 public static void StoreFromPtr (ILGenerator ig, Type type)
1034 if (TypeManager.IsEnumType (type))
1035 type = TypeManager.EnumToUnderlying (type);
1036 if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
1037 ig.Emit (OpCodes.Stind_I4);
1038 else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
1039 ig.Emit (OpCodes.Stind_I8);
1040 else if (type == TypeManager.char_type || type == TypeManager.short_type ||
1041 type == TypeManager.ushort_type)
1042 ig.Emit (OpCodes.Stind_I2);
1043 else if (type == TypeManager.float_type)
1044 ig.Emit (OpCodes.Stind_R4);
1045 else if (type == TypeManager.double_type)
1046 ig.Emit (OpCodes.Stind_R8);
1047 else if (type == TypeManager.byte_type || type == TypeManager.sbyte_type ||
1048 type == TypeManager.bool_type)
1049 ig.Emit (OpCodes.Stind_I1);
1050 else if (type == TypeManager.intptr_type)
1051 ig.Emit (OpCodes.Stind_I);
1052 else if (type.IsValueType || TypeManager.IsGenericParameter (type))
1053 ig.Emit (OpCodes.Stobj, type);
1055 ig.Emit (OpCodes.Stind_Ref);
1059 // Returns the size of type `t' if known, otherwise, 0
1061 public static int GetTypeSize (Type t)
1063 t = TypeManager.TypeToCoreType (t);
1064 if (t == TypeManager.int32_type ||
1065 t == TypeManager.uint32_type ||
1066 t == TypeManager.float_type)
1068 else if (t == TypeManager.int64_type ||
1069 t == TypeManager.uint64_type ||
1070 t == TypeManager.double_type)
1072 else if (t == TypeManager.byte_type ||
1073 t == TypeManager.sbyte_type ||
1074 t == TypeManager.bool_type)
1076 else if (t == TypeManager.short_type ||
1077 t == TypeManager.char_type ||
1078 t == TypeManager.ushort_type)
1080 else if (t == TypeManager.decimal_type)
1086 public static void Error_NegativeArrayIndex (Location loc)
1088 Report.Error (248, loc, "Cannot create an array with a negative size");
1091 protected void Error_CannotCallAbstractBase (string name)
1093 Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
1097 // Converts `source' to an int, uint, long or ulong.
1099 public Expression ExpressionToArrayArgument (EmitContext ec, Expression source, Location loc)
1103 using (ec.With (EmitContext.Flags.CheckState, true)) {
1104 target = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, loc);
1106 target = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, loc);
1108 target = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, loc);
1110 target = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, loc);
1112 if (target == null) {
1113 source.Error_ValueCannotBeConverted (ec, loc, TypeManager.int32_type, false);
1119 // Only positive constants are allowed at compile time
1121 if (target is Constant){
1122 if (target is IntConstant){
1123 if (((IntConstant) target).Value < 0){
1124 Error_NegativeArrayIndex (loc);
1129 if (target is LongConstant){
1130 if (((LongConstant) target).Value < 0){
1131 Error_NegativeArrayIndex (loc);
1144 /// This is just a base class for expressions that can
1145 /// appear on statements (invocations, object creation,
1146 /// assignments, post/pre increment and decrement). The idea
1147 /// being that they would support an extra Emition interface that
1148 /// does not leave a result on the stack.
1150 public abstract class ExpressionStatement : Expression {
1152 public virtual ExpressionStatement ResolveStatement (EmitContext ec)
1154 Expression e = Resolve (ec);
1158 ExpressionStatement es = e as ExpressionStatement;
1160 Error (201, "Only assignment, call, increment, decrement and new object " +
1161 "expressions can be used as a statement");
1167 /// Requests the expression to be emitted in a `statement'
1168 /// context. This means that no new value is left on the
1169 /// stack after invoking this method (constrasted with
1170 /// Emit that will always leave a value on the stack).
1172 public abstract void EmitStatement (EmitContext ec);
1176 /// This kind of cast is used to encapsulate the child
1177 /// whose type is child.Type into an expression that is
1178 /// reported to return "return_type". This is used to encapsulate
1179 /// expressions which have compatible types, but need to be dealt
1180 /// at higher levels with.
1182 /// For example, a "byte" expression could be encapsulated in one
1183 /// of these as an "unsigned int". The type for the expression
1184 /// would be "unsigned int".
1187 public class EmptyCast : Expression {
1188 protected readonly Expression child;
1190 public EmptyCast (Expression child, Type return_type)
1192 eclass = child.eclass;
1193 loc = child.Location;
1198 public override Expression DoResolve (EmitContext ec)
1200 // This should never be invoked, we are born in fully
1201 // initialized state.
1206 public override void Emit (EmitContext ec)
1211 public override bool GetAttributableValue (Type valueType, out object value)
1213 return child.GetAttributableValue (valueType, out value);
1219 /// Performs a cast using an operator (op_Explicit or op_Implicit)
1221 public class OperatorCast : EmptyCast {
1222 MethodInfo conversion_operator;
1225 public OperatorCast (Expression child, Type target_type) : this (child, target_type, false) {}
1227 public OperatorCast (Expression child, Type target_type, bool find_explicit)
1228 : base (child, target_type)
1230 this.find_explicit = find_explicit;
1233 // Returns the implicit operator that converts from
1234 // 'child.Type' to our target type (type)
1235 MethodInfo GetConversionOperator (bool find_explicit)
1237 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1241 mi = TypeManager.MemberLookup (child.Type, child.Type, child.Type, MemberTypes.Method,
1242 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1245 mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1246 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1249 foreach (MethodInfo oper in mi) {
1250 ParameterData pd = TypeManager.GetParameterData (oper);
1252 if (pd.ParameterType (0) == child.Type && oper.ReturnType == type)
1260 public override void Emit (EmitContext ec)
1262 ILGenerator ig = ec.ig;
1265 conversion_operator = GetConversionOperator (find_explicit);
1267 if (conversion_operator == null)
1268 throw new InternalErrorException ("Outer conversion routine is out of sync");
1270 ig.Emit (OpCodes.Call, conversion_operator);
1276 /// This is a numeric cast to a Decimal
1278 public class CastToDecimal : EmptyCast {
1279 MethodInfo conversion_operator;
1281 public CastToDecimal (Expression child)
1282 : this (child, false)
1286 public CastToDecimal (Expression child, bool find_explicit)
1287 : base (child, TypeManager.decimal_type)
1289 conversion_operator = GetConversionOperator (find_explicit);
1291 if (conversion_operator == null)
1292 throw new InternalErrorException ("Outer conversion routine is out of sync");
1295 // Returns the implicit operator that converts from
1296 // 'child.Type' to System.Decimal.
1297 MethodInfo GetConversionOperator (bool find_explicit)
1299 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1301 MemberInfo [] mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1302 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1304 foreach (MethodInfo oper in mi) {
1305 ParameterData pd = TypeManager.GetParameterData (oper);
1307 if (pd.ParameterType (0) == child.Type && oper.ReturnType == type)
1313 public override void Emit (EmitContext ec)
1315 ILGenerator ig = ec.ig;
1318 ig.Emit (OpCodes.Call, conversion_operator);
1323 /// This is an explicit numeric cast from a Decimal
1325 public class CastFromDecimal : EmptyCast
1327 static IDictionary operators;
1329 public CastFromDecimal (Expression child, Type return_type)
1330 : base (child, return_type)
1332 if (child.Type != TypeManager.decimal_type)
1333 throw new InternalErrorException (
1334 "The expected type is Decimal, instead it is " + child.Type.FullName);
1337 // Returns the explicit operator that converts from an
1338 // express of type System.Decimal to 'type'.
1339 public Expression Resolve ()
1341 if (operators == null) {
1342 MemberInfo[] all_oper = TypeManager.MemberLookup (TypeManager.decimal_type,
1343 TypeManager.decimal_type, TypeManager.decimal_type, MemberTypes.Method,
1344 BindingFlags.Static | BindingFlags.Public, "op_Explicit", null);
1346 operators = new System.Collections.Specialized.HybridDictionary ();
1347 foreach (MethodInfo oper in all_oper) {
1348 ParameterData pd = TypeManager.GetParameterData (oper);
1349 if (pd.ParameterType (0) == TypeManager.decimal_type)
1350 operators.Add (oper.ReturnType, oper);
1354 return operators.Contains (type) ? this : null;
1357 public override void Emit (EmitContext ec)
1359 ILGenerator ig = ec.ig;
1362 ig.Emit (OpCodes.Call, (MethodInfo)operators [type]);
1368 // Constant specialization of EmptyCast.
1369 // We need to special case this since an empty cast of
1370 // a constant is still a constant.
1372 public class EmptyConstantCast : Constant
1374 public readonly Constant child;
1376 public EmptyConstantCast(Constant child, Type type)
1377 : base (child.Location)
1379 eclass = child.eclass;
1384 public override string AsString ()
1386 return child.AsString ();
1389 public override object GetValue ()
1391 return child.GetValue ();
1394 public override Constant ConvertExplicitly (bool inCheckedContext, Type target_type)
1396 return child.ConvertExplicitly (inCheckedContext, target_type);
1399 public override Constant Increment ()
1401 return child.Increment ();
1404 public override bool IsDefaultValue
1406 get { return child.IsDefaultValue; }
1409 public override bool IsNegative
1411 get { return child.IsNegative; }
1414 public override void Emit (EmitContext ec)
1419 public override Constant ConvertImplicitly (Type type)
1421 return child.ConvertImplicitly (type);
1427 /// This class is used to wrap literals which belong inside Enums
1429 public class EnumConstant : Constant {
1430 public Constant Child;
1432 public EnumConstant (Constant child, Type enum_type):
1433 base (child.Location)
1435 eclass = child.eclass;
1440 public override Expression DoResolve (EmitContext ec)
1442 // This should never be invoked, we are born in fully
1443 // initialized state.
1448 public override void Emit (EmitContext ec)
1453 public override bool GetAttributableValue (Type valueType, out object value)
1455 value = GetTypedValue ();
1459 public override string GetSignatureForError()
1461 return TypeManager.CSharpName (Type);
1464 public override object GetValue ()
1466 return Child.GetValue ();
1469 public override object GetTypedValue ()
1471 // FIXME: runtime is not ready to work with just emited enums
1472 if (!RootContext.StdLib) {
1473 return Child.GetValue ();
1476 return System.Enum.ToObject (type, Child.GetValue ());
1479 public override string AsString ()
1481 string value = System.Enum.GetName (type, Child.GetValue ());
1482 return value == null ? "0" : value;
1485 public override Constant Increment()
1487 return new EnumConstant (Child.Increment (), type);
1490 public override bool IsDefaultValue {
1492 return Child.IsDefaultValue;
1496 public override bool IsZeroInteger {
1497 get { return Child.IsZeroInteger; }
1500 public override bool IsNegative {
1502 return Child.IsNegative;
1506 public override Constant ConvertExplicitly(bool inCheckedContext, Type target_type)
1508 if (Child.Type == target_type)
1511 return Child.ConvertExplicitly (inCheckedContext, target_type);
1514 public override Constant ConvertImplicitly (Type type)
1517 // This is workaround of mono bug. It can be removed when the latest corlib spreads enough
1518 if (TypeManager.IsEnumType (type.UnderlyingSystemType))
1521 if (type.UnderlyingSystemType != Child.Type)
1522 Child = Child.ConvertImplicitly (type.UnderlyingSystemType);
1526 if (!Convert.ImplicitStandardConversionExists (this, type)){
1530 return Child.ConvertImplicitly(type);
1536 /// This kind of cast is used to encapsulate Value Types in objects.
1538 /// The effect of it is to box the value type emitted by the previous
1541 public class BoxedCast : EmptyCast {
1543 public BoxedCast (Expression expr, Type target_type)
1544 : base (expr, target_type)
1546 eclass = ExprClass.Value;
1549 public override Expression DoResolve (EmitContext ec)
1551 // This should never be invoked, we are born in fully
1552 // initialized state.
1557 public override void Emit (EmitContext ec)
1561 ec.ig.Emit (OpCodes.Box, child.Type);
1565 public class UnboxCast : EmptyCast {
1566 public UnboxCast (Expression expr, Type return_type)
1567 : base (expr, return_type)
1571 public override Expression DoResolve (EmitContext ec)
1573 // This should never be invoked, we are born in fully
1574 // initialized state.
1579 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1581 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
1582 Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
1583 return base.DoResolveLValue (ec, right_side);
1586 public override void Emit (EmitContext ec)
1589 ILGenerator ig = ec.ig;
1593 if (t.IsGenericParameter || t.IsGenericType && t.IsValueType)
1594 ig.Emit (OpCodes.Unbox_Any, t);
1598 ig.Emit (OpCodes.Unbox, t);
1600 LoadFromPtr (ig, t);
1606 /// This is used to perform explicit numeric conversions.
1608 /// Explicit numeric conversions might trigger exceptions in a checked
1609 /// context, so they should generate the conv.ovf opcodes instead of
1612 public class ConvCast : EmptyCast {
1613 public enum Mode : byte {
1614 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1616 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1617 U2_I1, U2_U1, U2_I2, U2_CH,
1618 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1619 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1620 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH,
1621 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH,
1622 CH_I1, CH_U1, CH_I2,
1623 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1624 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4
1629 public ConvCast (Expression child, Type return_type, Mode m)
1630 : base (child, return_type)
1635 public override Expression DoResolve (EmitContext ec)
1637 // This should never be invoked, we are born in fully
1638 // initialized state.
1643 public override string ToString ()
1645 return String.Format ("ConvCast ({0}, {1})", mode, child);
1648 public override void Emit (EmitContext ec)
1650 ILGenerator ig = ec.ig;
1656 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1657 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1658 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1659 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1660 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1662 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1663 case Mode.U1_CH: /* nothing */ break;
1665 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1666 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1667 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1668 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1669 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1670 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1672 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1673 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1674 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1675 case Mode.U2_CH: /* nothing */ break;
1677 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1678 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1679 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1680 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1681 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1682 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1683 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1685 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1686 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1687 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1688 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1689 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1690 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1692 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1693 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1694 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1695 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1696 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1697 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1698 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1699 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1701 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1702 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1703 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1704 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1705 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1706 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1707 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1708 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1710 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1711 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1712 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1714 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1715 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1716 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1717 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1718 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1719 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1720 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1721 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1722 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1724 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1725 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1726 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1727 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1728 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1729 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1730 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1731 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1732 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1733 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1737 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
1738 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
1739 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
1740 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
1741 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
1743 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
1744 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
1746 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
1747 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
1748 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
1749 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
1750 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
1751 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
1753 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
1754 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
1755 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
1756 case Mode.U2_CH: /* nothing */ break;
1758 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
1759 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
1760 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
1761 case Mode.I4_U4: /* nothing */ break;
1762 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
1763 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
1764 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
1766 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
1767 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
1768 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
1769 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
1770 case Mode.U4_I4: /* nothing */ break;
1771 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
1773 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
1774 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
1775 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
1776 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
1777 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
1778 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
1779 case Mode.I8_U8: /* nothing */ break;
1780 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
1782 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
1783 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
1784 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
1785 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
1786 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
1787 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
1788 case Mode.U8_I8: /* nothing */ break;
1789 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
1791 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
1792 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
1793 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
1795 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
1796 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
1797 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
1798 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
1799 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
1800 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
1801 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
1802 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
1803 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
1805 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
1806 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
1807 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
1808 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
1809 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
1810 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
1811 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
1812 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
1813 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
1814 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1820 public class OpcodeCast : EmptyCast {
1824 public OpcodeCast (Expression child, Type return_type, OpCode op)
1825 : base (child, return_type)
1829 second_valid = false;
1832 public OpcodeCast (Expression child, Type return_type, OpCode op, OpCode op2)
1833 : base (child, return_type)
1838 second_valid = true;
1841 public override Expression DoResolve (EmitContext ec)
1843 // This should never be invoked, we are born in fully
1844 // initialized state.
1849 public override void Emit (EmitContext ec)
1860 /// This kind of cast is used to encapsulate a child and cast it
1861 /// to the class requested
1863 public class ClassCast : EmptyCast {
1864 public ClassCast (Expression child, Type return_type)
1865 : base (child, return_type)
1870 public override Expression DoResolve (EmitContext ec)
1872 // This should never be invoked, we are born in fully
1873 // initialized state.
1878 public override void Emit (EmitContext ec)
1882 if (TypeManager.IsGenericParameter (child.Type))
1883 ec.ig.Emit (OpCodes.Box, child.Type);
1886 if (type.IsGenericParameter)
1887 ec.ig.Emit (OpCodes.Unbox_Any, type);
1890 ec.ig.Emit (OpCodes.Castclass, type);
1895 /// SimpleName expressions are formed of a single word and only happen at the beginning
1896 /// of a dotted-name.
1898 public class SimpleName : Expression {
1900 public readonly TypeArguments Arguments;
1903 public SimpleName (string name, Location l)
1909 public SimpleName (string name, TypeArguments args, Location l)
1916 public SimpleName (string name, TypeParameter[] type_params, Location l)
1921 Arguments = new TypeArguments (l);
1922 foreach (TypeParameter type_param in type_params)
1923 Arguments.Add (new TypeParameterExpr (type_param, l));
1926 public static string RemoveGenericArity (string name)
1929 StringBuilder sb = null;
1931 int pos = name.IndexOf ('`', start);
1936 sb.Append (name.Substring (start));
1941 sb = new StringBuilder ();
1942 sb.Append (name.Substring (start, pos-start));
1945 while ((pos < name.Length) && Char.IsNumber (name [pos]))
1949 } while (start < name.Length);
1951 return sb.ToString ();
1954 public SimpleName GetMethodGroup ()
1956 return new SimpleName (RemoveGenericArity (Name), Arguments, loc);
1959 public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
1961 if (ec.IsFieldInitializer)
1962 Report.Error (236, l,
1963 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
1967 120, l, "`{0}': An object reference is required for the nonstatic field, method or property",
1971 public bool IdenticalNameAndTypeName (EmitContext ec, Expression resolved_to, Location loc)
1973 return resolved_to != null && resolved_to.Type != null &&
1974 resolved_to.Type.Name == Name &&
1975 (ec.DeclContainer.LookupType (Name, loc, /* ignore_cs0104 = */ true) != null);
1978 public override Expression DoResolve (EmitContext ec)
1980 return SimpleNameResolve (ec, null, false);
1983 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1985 return SimpleNameResolve (ec, right_side, false);
1989 public Expression DoResolve (EmitContext ec, bool intermediate)
1991 return SimpleNameResolve (ec, null, intermediate);
1994 private bool IsNestedChild (Type t, Type parent)
1999 while (parent != null) {
2000 parent = TypeManager.DropGenericTypeArguments (parent);
2001 if (TypeManager.IsNestedChildOf (t, parent))
2004 parent = parent.BaseType;
2010 FullNamedExpression ResolveNested (IResolveContext ec, Type t)
2012 if (!TypeManager.IsGenericTypeDefinition (t))
2015 DeclSpace ds = ec.DeclContainer;
2016 while (ds != null) {
2017 if (IsNestedChild (t, ds.TypeBuilder))
2026 Type[] gen_params = TypeManager.GetTypeArguments (t);
2028 int arg_count = Arguments != null ? Arguments.Count : 0;
2030 for (; (ds != null) && ds.IsGeneric; ds = ds.Parent) {
2031 if (arg_count + ds.CountTypeParameters == gen_params.Length) {
2032 TypeArguments new_args = new TypeArguments (loc);
2033 foreach (TypeParameter param in ds.TypeParameters)
2034 new_args.Add (new TypeParameterExpr (param, loc));
2036 if (Arguments != null)
2037 new_args.Add (Arguments);
2039 return new ConstructedType (t, new_args, loc);
2046 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2048 FullNamedExpression fne = ec.GenericDeclContainer.LookupGeneric (Name, loc);
2050 return fne.ResolveAsTypeStep (ec, silent);
2052 int errors = Report.Errors;
2053 fne = ec.DeclContainer.LookupType (Name, loc, /*ignore_cs0104=*/ false);
2056 if (fne.Type == null)
2059 FullNamedExpression nested = ResolveNested (ec, fne.Type);
2061 return nested.ResolveAsTypeStep (ec, false);
2063 if (Arguments != null) {
2064 ConstructedType ct = new ConstructedType (fne, Arguments, loc);
2065 return ct.ResolveAsTypeStep (ec, false);
2071 if (silent || errors != Report.Errors)
2074 MemberCore mc = ec.DeclContainer.GetDefinition (Name);
2076 Error_UnexpectedKind (ec.DeclContainer, "type", GetMemberType (mc), loc);
2080 string ns = ec.DeclContainer.NamespaceEntry.NS.Name;
2081 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2082 foreach (Assembly a in RootNamespace.Global.Assemblies) {
2083 Type type = a.GetType (fullname);
2085 Report.SymbolRelatedToPreviousError (type);
2086 Expression.ErrorIsInaccesible (loc, fullname);
2091 Type t = ec.DeclContainer.NamespaceEntry.NS.LookForAnyGenericType (Name);
2093 Namespace.Error_InvalidNumberOfTypeArguments (t, loc);
2097 NamespaceEntry.Error_NamespaceNotFound (loc, Name);
2101 // TODO: I am still not convinced about this. If someone else will need it
2102 // implement this as virtual property in MemberCore hierarchy
2103 string GetMemberType (MemberCore mc)
2105 if (mc is PropertyBase)
2109 if (mc is FieldBase)
2111 if (mc is MethodCore)
2113 if (mc is EnumMember)
2119 Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2125 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2129 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2136 /// 7.5.2: Simple Names.
2138 /// Local Variables and Parameters are handled at
2139 /// parse time, so they never occur as SimpleNames.
2141 /// The `intermediate' flag is used by MemberAccess only
2142 /// and it is used to inform us that it is ok for us to
2143 /// avoid the static check, because MemberAccess might end
2144 /// up resolving the Name as a Type name and the access as
2145 /// a static type access.
2147 /// ie: Type Type; .... { Type.GetType (""); }
2149 /// Type is both an instance variable and a Type; Type.GetType
2150 /// is the static method not an instance method of type.
2152 Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2154 Expression e = null;
2157 // Stage 1: Performed by the parser (binding to locals or parameters).
2159 Block current_block = ec.CurrentBlock;
2160 if (current_block != null){
2161 LocalInfo vi = current_block.GetLocalInfo (Name);
2163 if (Arguments != null) {
2164 Report.Error (307, loc,
2165 "The variable `{0}' cannot be used with type arguments",
2170 LocalVariableReference var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2171 if (right_side != null) {
2172 return var.ResolveLValue (ec, right_side, loc);
2174 ResolveFlags rf = ResolveFlags.VariableOrValue;
2176 rf |= ResolveFlags.DisableFlowAnalysis;
2177 return var.Resolve (ec, rf);
2181 ParameterReference pref = current_block.Toplevel.GetParameterReference (Name, loc);
2183 if (Arguments != null) {
2184 Report.Error (307, loc,
2185 "The variable `{0}' cannot be used with type arguments",
2190 if (right_side != null)
2191 return pref.ResolveLValue (ec, right_side, loc);
2193 return pref.Resolve (ec);
2198 // Stage 2: Lookup members
2201 DeclSpace lookup_ds = ec.DeclContainer;
2202 Type almost_matched_type = null;
2203 ArrayList almost_matched = null;
2205 if (lookup_ds.TypeBuilder == null)
2208 e = MemberLookup (ec.ContainerType, lookup_ds.TypeBuilder, Name, loc);
2212 if (almost_matched == null && almostMatchedMembers.Count > 0) {
2213 almost_matched_type = lookup_ds.TypeBuilder;
2214 almost_matched = (ArrayList) almostMatchedMembers.Clone ();
2217 lookup_ds =lookup_ds.Parent;
2218 } while (lookup_ds != null);
2220 if (e == null && ec.ContainerType != null)
2221 e = MemberLookup (ec.ContainerType, ec.ContainerType, Name, loc);
2224 if (almost_matched == null && almostMatchedMembers.Count > 0) {
2225 almost_matched_type = ec.ContainerType;
2226 almost_matched = (ArrayList) almostMatchedMembers.Clone ();
2228 e = ResolveAsTypeStep (ec, true);
2232 if (almost_matched != null)
2233 almostMatchedMembers = almost_matched;
2234 if (almost_matched_type == null)
2235 almost_matched_type = ec.ContainerType;
2236 MemberLookupFailed (ec.ContainerType, null, almost_matched_type, ((SimpleName) this).Name, ec.DeclContainer.Name, true, loc);
2240 if (e is TypeExpr) {
2241 if (Arguments == null)
2244 ConstructedType ct = new ConstructedType (
2245 (FullNamedExpression) e, Arguments, loc);
2246 return ct.ResolveAsTypeStep (ec, false);
2249 if (e is MemberExpr) {
2250 MemberExpr me = (MemberExpr) e;
2253 if (me.IsInstance) {
2254 if (ec.IsStatic || ec.IsFieldInitializer) {
2256 // Note that an MemberExpr can be both IsInstance and IsStatic.
2257 // An unresolved MethodGroupExpr can contain both kinds of methods
2258 // and each predicate is true if the MethodGroupExpr contains
2259 // at least one of that kind of method.
2263 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2264 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2265 return EmptyExpression.Null;
2269 // Pass the buck to MemberAccess and Invocation.
2271 left = EmptyExpression.Null;
2273 left = ec.GetThis (loc);
2276 left = new TypeExpression (ec.ContainerType, loc);
2279 e = me.ResolveMemberAccess (ec, left, loc, null);
2283 me = e as MemberExpr;
2287 if (Arguments != null) {
2288 MethodGroupExpr mg = me as MethodGroupExpr;
2292 return mg.ResolveGeneric (ec, Arguments);
2295 if (!me.IsStatic && (me.InstanceExpression != null) &&
2296 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2297 me.InstanceExpression.Type != me.DeclaringType &&
2298 !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2299 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2300 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2301 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2305 return (right_side != null)
2306 ? me.DoResolveLValue (ec, right_side)
2307 : me.DoResolve (ec);
2313 public override void Emit (EmitContext ec)
2316 // If this is ever reached, then we failed to
2317 // find the name as a namespace
2320 Error (103, "The name `" + Name +
2321 "' does not exist in the class `" +
2322 ec.DeclContainer.Name + "'");
2325 public override string ToString ()
2330 public override string GetSignatureForError ()
2337 /// Represents a namespace or a type. The name of the class was inspired by
2338 /// section 10.8.1 (Fully Qualified Names).
2340 public abstract class FullNamedExpression : Expression {
2341 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2346 public abstract string FullName {
2352 /// Expression that evaluates to a type
2354 public abstract class TypeExpr : FullNamedExpression {
2355 override public FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2357 TypeExpr t = DoResolveAsTypeStep (ec);
2361 eclass = ExprClass.Type;
2365 override public Expression DoResolve (EmitContext ec)
2367 return ResolveAsTypeTerminal (ec, false);
2370 override public void Emit (EmitContext ec)
2372 throw new Exception ("Should never be called");
2375 public virtual bool CheckAccessLevel (DeclSpace ds)
2377 return ds.CheckAccessLevel (Type);
2380 public virtual bool AsAccessible (DeclSpace ds, int flags)
2382 return ds.AsAccessible (Type, flags);
2385 public virtual bool IsClass {
2386 get { return Type.IsClass; }
2389 public virtual bool IsValueType {
2390 get { return Type.IsValueType; }
2393 public virtual bool IsInterface {
2394 get { return Type.IsInterface; }
2397 public virtual bool IsSealed {
2398 get { return Type.IsSealed; }
2401 public virtual bool CanInheritFrom ()
2403 if (Type == TypeManager.enum_type ||
2404 (Type == TypeManager.value_type && RootContext.StdLib) ||
2405 Type == TypeManager.multicast_delegate_type ||
2406 Type == TypeManager.delegate_type ||
2407 Type == TypeManager.array_type)
2413 protected abstract TypeExpr DoResolveAsTypeStep (IResolveContext ec);
2415 public abstract string Name {
2419 public override bool Equals (object obj)
2421 TypeExpr tobj = obj as TypeExpr;
2425 return Type == tobj.Type;
2428 public override int GetHashCode ()
2430 return Type.GetHashCode ();
2433 public override string ToString ()
2440 /// Fully resolved Expression that already evaluated to a type
2442 public class TypeExpression : TypeExpr {
2443 public TypeExpression (Type t, Location l)
2446 eclass = ExprClass.Type;
2450 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2455 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2460 public override string Name {
2461 get { return Type.ToString (); }
2464 public override string FullName {
2465 get { return Type.FullName; }
2470 /// Used to create types from a fully qualified name. These are just used
2471 /// by the parser to setup the core types. A TypeLookupExpression is always
2472 /// classified as a type.
2474 public sealed class TypeLookupExpression : TypeExpr {
2475 readonly string name;
2477 public TypeLookupExpression (string name)
2480 eclass = ExprClass.Type;
2483 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2485 // It's null for corlib compilation only
2487 return DoResolveAsTypeStep (ec);
2492 static readonly char [] dot_array = { '.' };
2493 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2495 // If name is of the form `N.I', first lookup `N', then search a member `I' in it.
2497 string lookup_name = name;
2498 int pos = name.IndexOf ('.');
2500 rest = name.Substring (pos + 1);
2501 lookup_name = name.Substring (0, pos);
2504 FullNamedExpression resolved = RootNamespace.Global.Lookup (ec.DeclContainer, lookup_name, Location.Null);
2506 if (resolved != null && rest != null) {
2507 // Now handle the rest of the the name.
2508 string [] elements = rest.Split (dot_array);
2510 int count = elements.Length;
2512 while (i < count && resolved != null && resolved is Namespace) {
2513 Namespace ns = resolved as Namespace;
2514 element = elements [i++];
2515 lookup_name += "." + element;
2516 resolved = ns.Lookup (ec.DeclContainer, element, Location.Null);
2519 if (resolved != null && resolved is TypeExpr) {
2520 Type t = ((TypeExpr) resolved).Type;
2522 if (!ec.DeclContainer.CheckAccessLevel (t)) {
2524 lookup_name = t.FullName;
2531 t = TypeManager.GetNestedType (t, elements [i++]);
2536 if (resolved == null) {
2537 NamespaceEntry.Error_NamespaceNotFound (loc, lookup_name);
2541 if (!(resolved is TypeExpr)) {
2542 resolved.Error_UnexpectedKind (ec.DeclContainer, "type", loc);
2546 type = resolved.Type;
2550 public override string Name {
2551 get { return name; }
2554 public override string FullName {
2555 get { return name; }
2560 /// Represents an "unbound generic type", ie. typeof (Foo<>).
2563 public class UnboundTypeExpression : TypeExpr
2567 public UnboundTypeExpression (MemberName name, Location l)
2573 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2576 if (name.Left != null) {
2577 Expression lexpr = name.Left.GetTypeExpression ();
2578 expr = new MemberAccess (lexpr, name.Basename);
2580 expr = new SimpleName (name.Basename, loc);
2583 FullNamedExpression fne = expr.ResolveAsTypeStep (ec, false);
2588 return new TypeExpression (type, loc);
2591 public override string Name {
2592 get { return name.FullName; }
2595 public override string FullName {
2596 get { return name.FullName; }
2600 public class TypeAliasExpression : TypeExpr {
2601 FullNamedExpression alias;
2606 public TypeAliasExpression (FullNamedExpression alias, TypeArguments args, Location l)
2612 eclass = ExprClass.Type;
2614 name = alias.FullName + "<" + args.ToString () + ">";
2616 name = alias.FullName;
2619 public override string Name {
2620 get { return alias.FullName; }
2623 public override string FullName {
2624 get { return name; }
2627 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2629 texpr = alias.ResolveAsTypeTerminal (ec, false);
2633 Type type = texpr.Type;
2634 int num_args = TypeManager.GetNumberOfTypeArguments (type);
2637 if (num_args == 0) {
2638 Report.Error (308, loc,
2639 "The non-generic type `{0}' cannot " +
2640 "be used with type arguments.",
2641 TypeManager.CSharpName (type));
2645 ConstructedType ctype = new ConstructedType (type, args, loc);
2646 return ctype.ResolveAsTypeTerminal (ec, false);
2647 } else if (num_args > 0) {
2648 Report.Error (305, loc,
2649 "Using the generic type `{0}' " +
2650 "requires {1} type arguments",
2651 TypeManager.CSharpName (type), num_args.ToString ());
2658 public override bool CheckAccessLevel (DeclSpace ds)
2660 return texpr.CheckAccessLevel (ds);
2663 public override bool AsAccessible (DeclSpace ds, int flags)
2665 return texpr.AsAccessible (ds, flags);
2668 public override bool IsClass {
2669 get { return texpr.IsClass; }
2672 public override bool IsValueType {
2673 get { return texpr.IsValueType; }
2676 public override bool IsInterface {
2677 get { return texpr.IsInterface; }
2680 public override bool IsSealed {
2681 get { return texpr.IsSealed; }
2686 /// This class denotes an expression which evaluates to a member
2687 /// of a struct or a class.
2689 public abstract class MemberExpr : Expression
2692 /// The name of this member.
2694 public abstract string Name {
2699 /// Whether this is an instance member.
2701 public abstract bool IsInstance {
2706 /// Whether this is a static member.
2708 public abstract bool IsStatic {
2713 /// The type which declares this member.
2715 public abstract Type DeclaringType {
2720 /// The instance expression associated with this member, if it's a
2721 /// non-static member.
2723 public Expression InstanceExpression;
2725 public static void error176 (Location loc, string name)
2727 Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
2728 "with an instance reference, qualify it with a type name instead", name);
2731 // TODO: possible optimalization
2732 // Cache resolved constant result in FieldBuilder <-> expression map
2733 public virtual Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
2734 SimpleName original)
2738 // original == null || original.Resolve (...) ==> left
2741 if (left is TypeExpr) {
2743 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
2751 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
2754 error176 (loc, GetSignatureForError ());
2758 InstanceExpression = left;
2763 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
2768 if (InstanceExpression == EmptyExpression.Null) {
2769 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
2773 if (InstanceExpression.Type.IsValueType) {
2774 if (InstanceExpression is IMemoryLocation) {
2775 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
2777 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
2778 InstanceExpression.Emit (ec);
2780 t.AddressOf (ec, AddressOp.Store);
2783 InstanceExpression.Emit (ec);
2785 if (prepare_for_load)
2786 ec.ig.Emit (OpCodes.Dup);
2791 /// MethodGroup Expression.
2793 /// This is a fully resolved expression that evaluates to a type
2795 public class MethodGroupExpr : MemberExpr {
2796 public MethodBase [] Methods;
2797 bool has_type_arguments = false;
2798 bool identical_type_name = false;
2801 public MethodGroupExpr (MemberInfo [] mi, Location l)
2803 Methods = new MethodBase [mi.Length];
2804 mi.CopyTo (Methods, 0);
2805 eclass = ExprClass.MethodGroup;
2807 // Set the type to something that will never be useful, which will
2808 // trigger the proper conversions.
2809 type = typeof (MethodGroupExpr);
2813 public MethodGroupExpr (ArrayList list, Location l)
2815 Methods = new MethodBase [list.Count];
2818 list.CopyTo (Methods, 0);
2820 foreach (MemberInfo m in list){
2821 if (!(m is MethodBase)){
2822 Console.WriteLine ("Name " + m.Name);
2823 Console.WriteLine ("Found a: " + m.GetType ().FullName);
2830 eclass = ExprClass.MethodGroup;
2831 type = TypeManager.object_type;
2834 public override Type DeclaringType {
2837 // We assume that the top-level type is in the end
2839 return Methods [Methods.Length - 1].DeclaringType;
2840 //return Methods [0].DeclaringType;
2844 public bool HasTypeArguments {
2846 return has_type_arguments;
2850 has_type_arguments = value;
2854 public bool IdenticalTypeName {
2856 return identical_type_name;
2860 identical_type_name = value;
2864 public bool IsBase {
2873 public override string GetSignatureForError ()
2875 return TypeManager.CSharpSignature (Methods [0]);
2878 public override string Name {
2880 return Methods [0].Name;
2884 public override bool IsInstance {
2886 foreach (MethodBase mb in Methods)
2894 public override bool IsStatic {
2896 foreach (MethodBase mb in Methods)
2904 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
2905 SimpleName original)
2907 if (!(left is TypeExpr) &&
2908 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
2909 IdenticalTypeName = true;
2911 return base.ResolveMemberAccess (ec, left, loc, original);
2914 override public Expression DoResolve (EmitContext ec)
2917 InstanceExpression = null;
2919 if (InstanceExpression != null) {
2920 InstanceExpression = InstanceExpression.DoResolve (ec);
2921 if (InstanceExpression == null)
2928 public void ReportUsageError ()
2930 Report.Error (654, loc, "Method `" + DeclaringType + "." +
2931 Name + "()' is referenced without parentheses");
2934 override public void Emit (EmitContext ec)
2936 ReportUsageError ();
2939 bool RemoveMethods (bool keep_static)
2941 ArrayList smethods = new ArrayList ();
2943 foreach (MethodBase mb in Methods){
2944 if (mb.IsStatic == keep_static)
2948 if (smethods.Count == 0)
2951 Methods = new MethodBase [smethods.Count];
2952 smethods.CopyTo (Methods, 0);
2958 /// Removes any instance methods from the MethodGroup, returns
2959 /// false if the resulting set is empty.
2961 public bool RemoveInstanceMethods ()
2963 return RemoveMethods (true);
2967 /// Removes any static methods from the MethodGroup, returns
2968 /// false if the resulting set is empty.
2970 public bool RemoveStaticMethods ()
2972 return RemoveMethods (false);
2975 public Expression ResolveGeneric (EmitContext ec, TypeArguments args)
2978 if (args.Resolve (ec) == false)
2981 Type[] atypes = args.Arguments;
2983 int first_count = 0;
2984 MethodInfo first = null;
2986 ArrayList list = new ArrayList ();
2987 foreach (MethodBase mb in Methods) {
2988 MethodInfo mi = mb as MethodInfo;
2989 if ((mi == null) || !mi.IsGenericMethod)
2992 Type[] gen_params = mi.GetGenericArguments ();
2994 if (first == null) {
2996 first_count = gen_params.Length;
2999 if (gen_params.Length != atypes.Length)
3002 list.Add (mi.MakeGenericMethod (atypes));
3005 if (list.Count > 0) {
3006 MethodGroupExpr new_mg = new MethodGroupExpr (list, Location);
3007 new_mg.InstanceExpression = InstanceExpression;
3008 new_mg.HasTypeArguments = true;
3009 new_mg.IsBase = IsBase;
3015 305, loc, "Using the generic method `{0}' " +
3016 "requires {1} type arguments", Name,
3017 first_count.ToString ());
3020 308, loc, "The non-generic method `{0}' " +
3021 "cannot be used with type arguments", Name);
3025 throw new NotImplementedException ();
3031 /// Fully resolved expression that evaluates to a Field
3033 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariable {
3034 public readonly FieldInfo FieldInfo;
3035 VariableInfo variable_info;
3037 LocalTemporary temp;
3039 bool in_initializer;
3041 public FieldExpr (FieldInfo fi, Location l, bool in_initializer):
3044 this.in_initializer = in_initializer;
3047 public FieldExpr (FieldInfo fi, Location l)
3050 eclass = ExprClass.Variable;
3051 type = TypeManager.TypeToCoreType (fi.FieldType);
3055 public override string Name {
3057 return FieldInfo.Name;
3061 public override bool IsInstance {
3063 return !FieldInfo.IsStatic;
3067 public override bool IsStatic {
3069 return FieldInfo.IsStatic;
3073 public override Type DeclaringType {
3075 return FieldInfo.DeclaringType;
3079 public override string GetSignatureForError ()
3081 return TypeManager.GetFullNameSignature (FieldInfo);
3084 public VariableInfo VariableInfo {
3086 return variable_info;
3090 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3091 SimpleName original)
3093 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
3095 Type t = fi.FieldType;
3097 if (fi.IsLiteral || (fi.IsInitOnly && t == TypeManager.decimal_type)) {
3098 IConstant ic = TypeManager.GetConstant (fi);
3101 ic = new ExternalConstant (fi);
3103 ic = ExternalConstant.CreateDecimal (fi);
3105 return base.ResolveMemberAccess (ec, left, loc, original);
3108 TypeManager.RegisterConstant (fi, ic);
3111 bool left_is_type = left is TypeExpr;
3112 if (!left_is_type && (original == null || !original.IdenticalNameAndTypeName (ec, left, loc))) {
3113 Report.SymbolRelatedToPreviousError (FieldInfo);
3114 error176 (loc, TypeManager.GetFullNameSignature (FieldInfo));
3118 if (ic.ResolveValue ()) {
3119 if (!ec.IsInObsoleteScope)
3120 ic.CheckObsoleteness (loc);
3123 return ic.CreateConstantReference (loc);
3126 if (t.IsPointer && !ec.InUnsafe) {
3131 return base.ResolveMemberAccess (ec, left, loc, original);
3134 override public Expression DoResolve (EmitContext ec)
3136 return DoResolve (ec, false, false);
3139 Expression DoResolve (EmitContext ec, bool lvalue_instance, bool out_access)
3141 if (!FieldInfo.IsStatic){
3142 if (InstanceExpression == null){
3144 // This can happen when referencing an instance field using
3145 // a fully qualified type expression: TypeName.InstanceField = xxx
3147 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3151 // Resolve the field's instance expression while flow analysis is turned
3152 // off: when accessing a field "a.b", we must check whether the field
3153 // "a.b" is initialized, not whether the whole struct "a" is initialized.
3155 if (lvalue_instance) {
3156 using (ec.With (EmitContext.Flags.DoFlowAnalysis, false)) {
3157 Expression right_side =
3158 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
3159 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side, loc);
3162 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
3163 InstanceExpression = InstanceExpression.Resolve (ec, rf);
3166 if (InstanceExpression == null)
3169 InstanceExpression.CheckMarshalByRefAccess ();
3172 if (!in_initializer && !ec.IsFieldInitializer) {
3173 ObsoleteAttribute oa;
3174 FieldBase f = TypeManager.GetField (FieldInfo);
3176 if (!ec.IsInObsoleteScope)
3177 f.CheckObsoleteness (loc);
3179 // To be sure that type is external because we do not register generated fields
3180 } else if (!(FieldInfo.DeclaringType is TypeBuilder)) {
3181 oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
3183 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
3187 AnonymousContainer am = ec.CurrentAnonymousMethod;
3189 if (!FieldInfo.IsStatic){
3190 if (!am.IsIterator && (ec.TypeContainer is Struct)){
3191 Report.Error (1673, loc,
3192 "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",
3199 // If the instance expression is a local variable or parameter.
3200 IVariable var = InstanceExpression as IVariable;
3201 if ((var == null) || (var.VariableInfo == null))
3204 VariableInfo vi = var.VariableInfo;
3205 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
3208 variable_info = vi.GetSubStruct (FieldInfo.Name);
3212 static readonly int [] codes = {
3213 191, // instance, write access
3214 192, // instance, out access
3215 198, // static, write access
3216 199, // static, out access
3217 1648, // member of value instance, write access
3218 1649, // member of value instance, out access
3219 1650, // member of value static, write access
3220 1651 // member of value static, out access
3223 static readonly string [] msgs = {
3224 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
3225 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
3226 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
3227 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
3228 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
3229 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
3230 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
3231 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
3234 // The return value is always null. Returning a value simplifies calling code.
3235 Expression Report_AssignToReadonly (Expression right_side)
3238 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
3242 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
3244 Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
3249 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3251 IVariable var = InstanceExpression as IVariable;
3252 if ((var != null) && (var.VariableInfo != null))
3253 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
3255 bool lvalue_instance = !FieldInfo.IsStatic && FieldInfo.DeclaringType.IsValueType;
3256 bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
3258 Expression e = DoResolve (ec, lvalue_instance, out_access);
3263 FieldBase fb = TypeManager.GetField (FieldInfo);
3267 if (FieldInfo.IsInitOnly) {
3268 // InitOnly fields can only be assigned in constructors or initializers
3269 if (!ec.IsFieldInitializer && !ec.IsConstructor)
3270 return Report_AssignToReadonly (right_side);
3272 if (ec.IsConstructor) {
3273 Type ctype = ec.TypeContainer.CurrentType;
3275 ctype = ec.ContainerType;
3277 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
3278 if (!TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
3279 return Report_AssignToReadonly (right_side);
3280 // static InitOnly fields cannot be assigned-to in an instance constructor
3281 if (IsStatic && !ec.IsStatic)
3282 return Report_AssignToReadonly (right_side);
3283 // instance constructors can't modify InitOnly fields of other instances of the same type
3284 if (!IsStatic && !(InstanceExpression is This))
3285 return Report_AssignToReadonly (right_side);
3289 if (right_side == EmptyExpression.OutAccess &&
3290 !IsStatic && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
3291 Report.SymbolRelatedToPreviousError (DeclaringType);
3292 Report.Warning (197, 1, loc,
3293 "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",
3294 GetSignatureForError ());
3300 public override void CheckMarshalByRefAccess ()
3302 if (!IsStatic && Type.IsValueType && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
3303 Report.SymbolRelatedToPreviousError (DeclaringType);
3304 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",
3305 GetSignatureForError ());
3309 public bool VerifyFixed ()
3311 IVariable variable = InstanceExpression as IVariable;
3312 // A variable of the form V.I is fixed when V is a fixed variable of a struct type.
3313 // We defer the InstanceExpression check after the variable check to avoid a
3314 // separate null check on InstanceExpression.
3315 return variable != null && InstanceExpression.Type.IsValueType && variable.VerifyFixed ();
3318 public override int GetHashCode ()
3320 return FieldInfo.GetHashCode ();
3323 public override bool Equals (object obj)
3325 FieldExpr fe = obj as FieldExpr;
3329 if (FieldInfo != fe.FieldInfo)
3332 if (InstanceExpression == null || fe.InstanceExpression == null)
3335 return InstanceExpression.Equals (fe.InstanceExpression);
3338 public void Emit (EmitContext ec, bool leave_copy)
3340 ILGenerator ig = ec.ig;
3341 bool is_volatile = false;
3343 FieldBase f = TypeManager.GetField (FieldInfo);
3345 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
3348 f.SetMemberIsUsed ();
3351 if (FieldInfo.IsStatic){
3353 ig.Emit (OpCodes.Volatile);
3355 ig.Emit (OpCodes.Ldsfld, FieldInfo);
3358 EmitInstance (ec, false);
3361 ig.Emit (OpCodes.Volatile);
3363 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
3366 ig.Emit (OpCodes.Ldflda, FieldInfo);
3367 ig.Emit (OpCodes.Ldflda, ff.Element);
3370 ig.Emit (OpCodes.Ldfld, FieldInfo);
3375 ec.ig.Emit (OpCodes.Dup);
3376 if (!FieldInfo.IsStatic) {
3377 temp = new LocalTemporary (this.Type);
3383 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
3385 FieldAttributes fa = FieldInfo.Attributes;
3386 bool is_static = (fa & FieldAttributes.Static) != 0;
3387 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
3388 ILGenerator ig = ec.ig;
3389 prepared = prepare_for_load;
3391 if (is_readonly && !ec.IsConstructor){
3392 Report_AssignToReadonly (source);
3396 EmitInstance (ec, prepare_for_load);
3400 ec.ig.Emit (OpCodes.Dup);
3401 if (!FieldInfo.IsStatic) {
3402 temp = new LocalTemporary (this.Type);
3407 FieldBase f = TypeManager.GetField (FieldInfo);
3409 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
3410 ig.Emit (OpCodes.Volatile);
3416 ig.Emit (OpCodes.Stsfld, FieldInfo);
3418 ig.Emit (OpCodes.Stfld, FieldInfo);
3426 public override void Emit (EmitContext ec)
3431 public void AddressOf (EmitContext ec, AddressOp mode)
3433 ILGenerator ig = ec.ig;
3435 FieldBase f = TypeManager.GetField (FieldInfo);
3437 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
3438 Report.Warning (420, 1, loc, "`{0}': A volatile fields cannot be passed using a ref or out parameter",
3439 f.GetSignatureForError ());
3443 if ((mode & AddressOp.Store) != 0)
3445 if ((mode & AddressOp.Load) != 0)
3446 f.SetMemberIsUsed ();
3450 // Handle initonly fields specially: make a copy and then
3451 // get the address of the copy.
3454 if (FieldInfo.IsInitOnly){
3456 if (ec.IsConstructor){
3457 if (FieldInfo.IsStatic){
3469 local = ig.DeclareLocal (type);
3470 ig.Emit (OpCodes.Stloc, local);
3471 ig.Emit (OpCodes.Ldloca, local);
3476 if (FieldInfo.IsStatic){
3477 ig.Emit (OpCodes.Ldsflda, FieldInfo);
3480 EmitInstance (ec, false);
3481 ig.Emit (OpCodes.Ldflda, FieldInfo);
3487 // A FieldExpr whose address can not be taken
3489 public class FieldExprNoAddress : FieldExpr, IMemoryLocation {
3490 public FieldExprNoAddress (FieldInfo fi, Location loc) : base (fi, loc)
3494 public new void AddressOf (EmitContext ec, AddressOp mode)
3496 Report.Error (-215, "Report this: Taking the address of a remapped parameter not supported");
3501 /// Expression that evaluates to a Property. The Assign class
3502 /// might set the `Value' expression if we are in an assignment.
3504 /// This is not an LValue because we need to re-write the expression, we
3505 /// can not take data from the stack and store it.
3507 public class PropertyExpr : MemberExpr, IAssignMethod {
3508 public readonly PropertyInfo PropertyInfo;
3511 // This is set externally by the `BaseAccess' class
3514 MethodInfo getter, setter;
3519 LocalTemporary temp;
3522 public PropertyExpr (Type containerType, PropertyInfo pi, Location l)
3525 eclass = ExprClass.PropertyAccess;
3529 type = TypeManager.TypeToCoreType (pi.PropertyType);
3531 ResolveAccessors (containerType);
3534 public override string Name {
3536 return PropertyInfo.Name;
3540 public override bool IsInstance {
3546 public override bool IsStatic {
3552 public override Type DeclaringType {
3554 return PropertyInfo.DeclaringType;
3558 public override string GetSignatureForError ()
3560 return TypeManager.GetFullNameSignature (PropertyInfo);
3563 void FindAccessors (Type invocation_type)
3565 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
3566 BindingFlags.Static | BindingFlags.Instance |
3567 BindingFlags.DeclaredOnly;
3569 Type current = PropertyInfo.DeclaringType;
3570 for (; current != null; current = current.BaseType) {
3571 MemberInfo[] group = TypeManager.MemberLookup (
3572 invocation_type, invocation_type, current,
3573 MemberTypes.Property, flags, PropertyInfo.Name, null);
3578 if (group.Length != 1)
3579 // Oooops, can this ever happen ?
3582 PropertyInfo pi = (PropertyInfo) group [0];
3585 getter = pi.GetGetMethod (true);
3588 setter = pi.GetSetMethod (true);
3590 MethodInfo accessor = getter != null ? getter : setter;
3592 if (!accessor.IsVirtual)
3598 // We also perform the permission checking here, as the PropertyInfo does not
3599 // hold the information for the accessibility of its setter/getter
3601 // TODO: Refactor to use some kind of cache together with GetPropertyFromAccessor
3602 void ResolveAccessors (Type containerType)
3604 FindAccessors (containerType);
3606 if (getter != null) {
3607 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
3608 IMethodData md = TypeManager.GetMethod (the_getter);
3610 md.SetMemberIsUsed ();
3612 is_static = getter.IsStatic;
3615 if (setter != null) {
3616 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
3617 IMethodData md = TypeManager.GetMethod (the_setter);
3619 md.SetMemberIsUsed ();
3621 is_static = setter.IsStatic;
3625 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
3628 InstanceExpression = null;
3632 if (InstanceExpression == null) {
3633 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3637 InstanceExpression = InstanceExpression.DoResolve (ec);
3638 if (lvalue_instance && InstanceExpression != null)
3639 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
3641 if (InstanceExpression == null)
3644 InstanceExpression.CheckMarshalByRefAccess ();
3646 if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) &&
3647 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
3648 !TypeManager.IsNestedChildOf (ec.ContainerType, InstanceExpression.Type) &&
3649 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.ContainerType)) {
3650 Report.SymbolRelatedToPreviousError (PropertyInfo);
3651 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
3658 void Error_PropertyNotFound (MethodInfo mi, bool getter)
3660 // TODO: correctly we should compare arguments but it will lead to bigger changes
3661 if (mi is MethodBuilder) {
3662 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
3666 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
3668 ParameterData iparams = TypeManager.GetParameterData (mi);
3669 sig.Append (getter ? "get_" : "set_");
3671 sig.Append (iparams.GetSignatureForError ());
3673 Report.SymbolRelatedToPreviousError (mi);
3674 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
3675 Name, sig.ToString ());
3678 override public Expression DoResolve (EmitContext ec)
3683 if (getter != null){
3684 if (TypeManager.GetParameterData (getter).Count != 0){
3685 Error_PropertyNotFound (getter, true);
3690 if (getter == null){
3692 // The following condition happens if the PropertyExpr was
3693 // created, but is invalid (ie, the property is inaccessible),
3694 // and we did not want to embed the knowledge about this in
3695 // the caller routine. This only avoids double error reporting.
3700 if (InstanceExpression != EmptyExpression.Null) {
3701 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
3702 TypeManager.GetFullNameSignature (PropertyInfo));
3707 bool must_do_cs1540_check = false;
3708 if (getter != null &&
3709 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
3710 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
3711 if (pm != null && pm.HasCustomAccessModifier) {
3712 Report.SymbolRelatedToPreviousError (pm);
3713 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
3714 TypeManager.CSharpSignature (getter));
3717 Report.SymbolRelatedToPreviousError (getter);
3718 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
3723 if (!InstanceResolve (ec, false, must_do_cs1540_check))
3727 // Only base will allow this invocation to happen.
3729 if (IsBase && getter.IsAbstract) {
3730 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
3734 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
3744 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3746 if (right_side == EmptyExpression.OutAccess) {
3747 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
3748 GetSignatureForError ());
3752 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
3753 Report.Error (1612, loc, "Cannot modify the return value of `{0}' because it is not a variable",
3754 GetSignatureForError ());
3758 if (setter == null){
3760 // The following condition happens if the PropertyExpr was
3761 // created, but is invalid (ie, the property is inaccessible),
3762 // and we did not want to embed the knowledge about this in
3763 // the caller routine. This only avoids double error reporting.
3767 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
3768 GetSignatureForError ());
3772 if (TypeManager.GetParameterData (setter).Count != 1){
3773 Error_PropertyNotFound (setter, false);
3777 bool must_do_cs1540_check;
3778 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
3779 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
3780 if (pm != null && pm.HasCustomAccessModifier) {
3781 Report.SymbolRelatedToPreviousError (pm);
3782 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
3783 TypeManager.CSharpSignature (setter));
3786 Report.SymbolRelatedToPreviousError (setter);
3787 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
3792 if (!InstanceResolve (ec, PropertyInfo.DeclaringType.IsValueType, must_do_cs1540_check))
3796 // Only base will allow this invocation to happen.
3798 if (IsBase && setter.IsAbstract){
3799 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
3806 public override void Emit (EmitContext ec)
3811 public void Emit (EmitContext ec, bool leave_copy)
3814 // Special case: length of single dimension array property is turned into ldlen
3816 if ((getter == TypeManager.system_int_array_get_length) ||
3817 (getter == TypeManager.int_array_get_length)){
3818 Type iet = InstanceExpression.Type;
3821 // System.Array.Length can be called, but the Type does not
3822 // support invoking GetArrayRank, so test for that case first
3824 if (iet != TypeManager.array_type && (iet.GetArrayRank () == 1)) {
3826 EmitInstance (ec, false);
3827 ec.ig.Emit (OpCodes.Ldlen);
3828 ec.ig.Emit (OpCodes.Conv_I4);
3833 Invocation.EmitCall (ec, IsBase, IsStatic, InstanceExpression, getter, null, loc, prepared, false);
3836 ec.ig.Emit (OpCodes.Dup);
3838 temp = new LocalTemporary (this.Type);
3845 // Implements the IAssignMethod interface for assignments
3847 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
3849 Expression my_source = source;
3851 prepared = prepare_for_load;
3856 ec.ig.Emit (OpCodes.Dup);
3858 temp = new LocalTemporary (this.Type);
3862 } else if (leave_copy) {
3865 temp = new LocalTemporary (this.Type);
3871 ArrayList args = new ArrayList (1);
3872 args.Add (new Argument (my_source, Argument.AType.Expression));
3874 Invocation.EmitCall (ec, IsBase, IsStatic, InstanceExpression, setter, args, loc, false, prepared);
3884 /// Fully resolved expression that evaluates to an Event
3886 public class EventExpr : MemberExpr {
3887 public readonly EventInfo EventInfo;
3890 MethodInfo add_accessor, remove_accessor;
3892 public EventExpr (EventInfo ei, Location loc)
3896 eclass = ExprClass.EventAccess;
3898 add_accessor = TypeManager.GetAddMethod (ei);
3899 remove_accessor = TypeManager.GetRemoveMethod (ei);
3900 if (add_accessor.IsStatic || remove_accessor.IsStatic)
3903 if (EventInfo is MyEventBuilder){
3904 MyEventBuilder eb = (MyEventBuilder) EventInfo;
3905 type = eb.EventType;
3908 type = EventInfo.EventHandlerType;
3911 public override string Name {
3913 return EventInfo.Name;
3917 public override bool IsInstance {
3923 public override bool IsStatic {
3929 public override Type DeclaringType {
3931 return EventInfo.DeclaringType;
3935 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3936 SimpleName original)
3939 // If the event is local to this class, we transform ourselves into a FieldExpr
3942 if (EventInfo.DeclaringType == ec.ContainerType ||
3943 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
3944 MemberInfo mi = TypeManager.GetPrivateFieldOfEvent (EventInfo);
3947 MemberExpr ml = (MemberExpr) ExprClassFromMemberInfo (ec.ContainerType, mi, loc);
3950 Report.Error (-200, loc, "Internal error!!");
3954 InstanceExpression = null;
3956 return ml.ResolveMemberAccess (ec, left, loc, original);
3960 return base.ResolveMemberAccess (ec, left, loc, original);
3964 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
3967 InstanceExpression = null;
3971 if (InstanceExpression == null) {
3972 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3976 InstanceExpression = InstanceExpression.DoResolve (ec);
3977 if (InstanceExpression == null)
3981 // This is using the same mechanism as the CS1540 check in PropertyExpr.
3982 // However, in the Event case, we reported a CS0122 instead.
3984 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
3985 InstanceExpression.Type != ec.ContainerType &&
3986 ec.ContainerType.IsSubclassOf (InstanceExpression.Type)) {
3987 Report.SymbolRelatedToPreviousError (EventInfo);
3988 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
3995 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
3997 return DoResolve (ec);
4000 public override Expression DoResolve (EmitContext ec)
4002 bool must_do_cs1540_check;
4003 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
4004 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
4005 Report.SymbolRelatedToPreviousError (EventInfo);
4006 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
4010 if (!InstanceResolve (ec, must_do_cs1540_check))
4016 public override void Emit (EmitContext ec)
4018 if (InstanceExpression is This)
4019 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of += or -=", GetSignatureForError ());
4021 Report.Error (70, loc, "The event `{0}' can only appear on the left hand side of += or -= "+
4022 "(except on the defining type)", Name);
4025 public override string GetSignatureForError ()
4027 return TypeManager.CSharpSignature (EventInfo);
4030 public void EmitAddOrRemove (EmitContext ec, Expression source)
4032 BinaryDelegate source_del = source as BinaryDelegate;
4033 if (source_del == null) {
4037 Expression handler = source_del.Right;
4039 Argument arg = new Argument (handler, Argument.AType.Expression);
4040 ArrayList args = new ArrayList ();
4044 if (source_del.IsAddition)
4045 Invocation.EmitCall (
4046 ec, false, IsStatic, InstanceExpression, add_accessor, args, loc);
4048 Invocation.EmitCall (
4049 ec, false, IsStatic, InstanceExpression, remove_accessor, args, loc);
4053 public class TemporaryVariable : Expression, IMemoryLocation
4058 public TemporaryVariable (Type type, Location loc)
4062 eclass = ExprClass.Value;
4065 public override Expression DoResolve (EmitContext ec)
4070 TypeExpr te = new TypeExpression (type, loc);
4071 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
4072 if (!li.Resolve (ec))
4075 if (ec.MustCaptureVariable (li)) {
4076 ScopeInfo scope = li.Block.CreateScopeInfo ();
4077 var = scope.AddLocal (li);
4084 public Variable Variable {
4085 get { return var != null ? var : li.Variable; }
4088 public override void Emit (EmitContext ec)
4090 Variable.EmitInstance (ec);
4094 public void EmitLoadAddress (EmitContext ec)
4096 Variable.EmitInstance (ec);
4097 Variable.EmitAddressOf (ec);
4100 public void Store (EmitContext ec, Expression right_side)
4102 Variable.EmitInstance (ec);
4103 right_side.Emit (ec);
4104 Variable.EmitAssign (ec);
4107 public void EmitThis (EmitContext ec)
4109 Variable.EmitInstance (ec);
4112 public void EmitStore (EmitContext ec)
4114 Variable.EmitAssign (ec);
4117 public void AddressOf (EmitContext ec, AddressOp mode)
4119 EmitLoadAddress (ec);