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 // FIXME: check that 'type' can be converted to 'target_type' first
1397 return child.ConvertExplicitly (inCheckedContext, target_type);
1400 public override Constant Increment ()
1402 return child.Increment ();
1405 public override bool IsDefaultValue {
1406 get { return child.IsDefaultValue; }
1409 public override bool IsNegative {
1410 get { return child.IsNegative; }
1413 public override void Emit (EmitContext ec)
1418 public override Constant ConvertImplicitly (Type target_type)
1420 // FIXME: Do we need to check user conversions?
1421 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1423 return child.ConvertImplicitly (target_type);
1429 /// This class is used to wrap literals which belong inside Enums
1431 public class EnumConstant : Constant {
1432 public Constant Child;
1434 public EnumConstant (Constant child, Type enum_type):
1435 base (child.Location)
1437 eclass = child.eclass;
1442 public override Expression DoResolve (EmitContext ec)
1444 // This should never be invoked, we are born in fully
1445 // initialized state.
1450 public override void Emit (EmitContext ec)
1455 public override bool GetAttributableValue (Type valueType, out object value)
1457 value = GetTypedValue ();
1461 public override string GetSignatureForError()
1463 return TypeManager.CSharpName (Type);
1466 public override object GetValue ()
1468 return Child.GetValue ();
1471 public override object GetTypedValue ()
1473 // FIXME: runtime is not ready to work with just emited enums
1474 if (!RootContext.StdLib) {
1475 return Child.GetValue ();
1478 return System.Enum.ToObject (type, Child.GetValue ());
1481 public override string AsString ()
1483 string value = System.Enum.GetName (type, Child.GetValue ());
1484 return value == null ? "0" : value;
1487 public override Constant Increment()
1489 return new EnumConstant (Child.Increment (), type);
1492 public override bool IsDefaultValue {
1494 return Child.IsDefaultValue;
1498 public override bool IsZeroInteger {
1499 get { return Child.IsZeroInteger; }
1502 public override bool IsNegative {
1504 return Child.IsNegative;
1508 public override Constant ConvertExplicitly(bool inCheckedContext, Type target_type)
1510 if (Child.Type == target_type)
1513 return Child.ConvertExplicitly (inCheckedContext, target_type);
1516 public override Constant ConvertImplicitly (Type type)
1519 // This is workaround of mono bug. It can be removed when the latest corlib spreads enough
1520 if (TypeManager.IsEnumType (type.UnderlyingSystemType))
1523 if (type.UnderlyingSystemType != Child.Type)
1524 Child = Child.ConvertImplicitly (type.UnderlyingSystemType);
1528 if (!Convert.ImplicitStandardConversionExists (this, type)){
1532 return Child.ConvertImplicitly(type);
1538 /// This kind of cast is used to encapsulate Value Types in objects.
1540 /// The effect of it is to box the value type emitted by the previous
1543 public class BoxedCast : EmptyCast {
1545 public BoxedCast (Expression expr, Type target_type)
1546 : base (expr, target_type)
1548 eclass = ExprClass.Value;
1551 public override Expression DoResolve (EmitContext ec)
1553 // This should never be invoked, we are born in fully
1554 // initialized state.
1559 public override void Emit (EmitContext ec)
1563 ec.ig.Emit (OpCodes.Box, child.Type);
1567 public class UnboxCast : EmptyCast {
1568 public UnboxCast (Expression expr, Type return_type)
1569 : base (expr, return_type)
1573 public override Expression DoResolve (EmitContext ec)
1575 // This should never be invoked, we are born in fully
1576 // initialized state.
1581 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1583 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
1584 Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
1585 return base.DoResolveLValue (ec, right_side);
1588 public override void Emit (EmitContext ec)
1591 ILGenerator ig = ec.ig;
1595 if (t.IsGenericParameter || t.IsGenericType && t.IsValueType)
1596 ig.Emit (OpCodes.Unbox_Any, t);
1600 ig.Emit (OpCodes.Unbox, t);
1602 LoadFromPtr (ig, t);
1608 /// This is used to perform explicit numeric conversions.
1610 /// Explicit numeric conversions might trigger exceptions in a checked
1611 /// context, so they should generate the conv.ovf opcodes instead of
1614 public class ConvCast : EmptyCast {
1615 public enum Mode : byte {
1616 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1618 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1619 U2_I1, U2_U1, U2_I2, U2_CH,
1620 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1621 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1622 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH,
1623 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH,
1624 CH_I1, CH_U1, CH_I2,
1625 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1626 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4
1631 public ConvCast (Expression child, Type return_type, Mode m)
1632 : base (child, return_type)
1637 public override Expression DoResolve (EmitContext ec)
1639 // This should never be invoked, we are born in fully
1640 // initialized state.
1645 public override string ToString ()
1647 return String.Format ("ConvCast ({0}, {1})", mode, child);
1650 public override void Emit (EmitContext ec)
1652 ILGenerator ig = ec.ig;
1658 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1659 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1660 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1661 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1662 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1664 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1665 case Mode.U1_CH: /* nothing */ break;
1667 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1668 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1669 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1670 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1671 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1672 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1674 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1675 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1676 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1677 case Mode.U2_CH: /* nothing */ break;
1679 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1680 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1681 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1682 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1683 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1684 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1685 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1687 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1688 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1689 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1690 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1691 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1692 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1694 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1695 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1696 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1697 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1698 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1699 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1700 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1701 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1703 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1704 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1705 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1706 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1707 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1708 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1709 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1710 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1712 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1713 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1714 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1716 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1717 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1718 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1719 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1720 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1721 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1722 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1723 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1724 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1726 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1727 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1728 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1729 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1730 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1731 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1732 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1733 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1734 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1735 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1739 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
1740 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
1741 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
1742 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
1743 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
1745 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
1746 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
1748 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
1749 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
1750 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
1751 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
1752 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
1753 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
1755 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
1756 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
1757 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
1758 case Mode.U2_CH: /* nothing */ break;
1760 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
1761 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
1762 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
1763 case Mode.I4_U4: /* nothing */ break;
1764 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
1765 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
1766 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
1768 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
1769 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
1770 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
1771 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
1772 case Mode.U4_I4: /* nothing */ break;
1773 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
1775 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
1776 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
1777 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
1778 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
1779 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
1780 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
1781 case Mode.I8_U8: /* nothing */ break;
1782 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
1784 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
1785 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
1786 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
1787 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
1788 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
1789 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
1790 case Mode.U8_I8: /* nothing */ break;
1791 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
1793 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
1794 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
1795 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
1797 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
1798 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
1799 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
1800 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
1801 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
1802 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
1803 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
1804 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
1805 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
1807 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
1808 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
1809 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
1810 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
1811 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
1812 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
1813 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
1814 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
1815 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
1816 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1822 public class OpcodeCast : EmptyCast {
1826 public OpcodeCast (Expression child, Type return_type, OpCode op)
1827 : base (child, return_type)
1831 second_valid = false;
1834 public OpcodeCast (Expression child, Type return_type, OpCode op, OpCode op2)
1835 : base (child, return_type)
1840 second_valid = true;
1843 public override Expression DoResolve (EmitContext ec)
1845 // This should never be invoked, we are born in fully
1846 // initialized state.
1851 public override void Emit (EmitContext ec)
1862 /// This kind of cast is used to encapsulate a child and cast it
1863 /// to the class requested
1865 public class ClassCast : EmptyCast {
1866 public ClassCast (Expression child, Type return_type)
1867 : base (child, return_type)
1872 public override Expression DoResolve (EmitContext ec)
1874 // This should never be invoked, we are born in fully
1875 // initialized state.
1880 public override void Emit (EmitContext ec)
1884 if (TypeManager.IsGenericParameter (child.Type))
1885 ec.ig.Emit (OpCodes.Box, child.Type);
1888 if (type.IsGenericParameter)
1889 ec.ig.Emit (OpCodes.Unbox_Any, type);
1892 ec.ig.Emit (OpCodes.Castclass, type);
1897 /// SimpleName expressions are formed of a single word and only happen at the beginning
1898 /// of a dotted-name.
1900 public class SimpleName : Expression {
1902 public readonly TypeArguments Arguments;
1905 public SimpleName (string name, Location l)
1911 public SimpleName (string name, TypeArguments args, Location l)
1918 public SimpleName (string name, TypeParameter[] type_params, Location l)
1923 Arguments = new TypeArguments (l);
1924 foreach (TypeParameter type_param in type_params)
1925 Arguments.Add (new TypeParameterExpr (type_param, l));
1928 public static string RemoveGenericArity (string name)
1931 StringBuilder sb = null;
1933 int pos = name.IndexOf ('`', start);
1938 sb.Append (name.Substring (start));
1943 sb = new StringBuilder ();
1944 sb.Append (name.Substring (start, pos-start));
1947 while ((pos < name.Length) && Char.IsNumber (name [pos]))
1951 } while (start < name.Length);
1953 return sb.ToString ();
1956 public SimpleName GetMethodGroup ()
1958 return new SimpleName (RemoveGenericArity (Name), Arguments, loc);
1961 public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
1963 if (ec.IsFieldInitializer)
1964 Report.Error (236, l,
1965 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
1969 120, l, "`{0}': An object reference is required for the nonstatic field, method or property",
1973 public bool IdenticalNameAndTypeName (EmitContext ec, Expression resolved_to, Location loc)
1975 return resolved_to != null && resolved_to.Type != null &&
1976 resolved_to.Type.Name == Name &&
1977 (ec.DeclContainer.LookupType (Name, loc, /* ignore_cs0104 = */ true) != null);
1980 public override Expression DoResolve (EmitContext ec)
1982 return SimpleNameResolve (ec, null, false);
1985 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1987 return SimpleNameResolve (ec, right_side, false);
1991 public Expression DoResolve (EmitContext ec, bool intermediate)
1993 return SimpleNameResolve (ec, null, intermediate);
1996 private bool IsNestedChild (Type t, Type parent)
2001 while (parent != null) {
2002 parent = TypeManager.DropGenericTypeArguments (parent);
2003 if (TypeManager.IsNestedChildOf (t, parent))
2006 parent = parent.BaseType;
2012 FullNamedExpression ResolveNested (IResolveContext ec, Type t)
2014 if (!TypeManager.IsGenericTypeDefinition (t))
2017 DeclSpace ds = ec.DeclContainer;
2018 while (ds != null) {
2019 if (IsNestedChild (t, ds.TypeBuilder))
2028 Type[] gen_params = TypeManager.GetTypeArguments (t);
2030 int arg_count = Arguments != null ? Arguments.Count : 0;
2032 for (; (ds != null) && ds.IsGeneric; ds = ds.Parent) {
2033 if (arg_count + ds.CountTypeParameters == gen_params.Length) {
2034 TypeArguments new_args = new TypeArguments (loc);
2035 foreach (TypeParameter param in ds.TypeParameters)
2036 new_args.Add (new TypeParameterExpr (param, loc));
2038 if (Arguments != null)
2039 new_args.Add (Arguments);
2041 return new ConstructedType (t, new_args, loc);
2048 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2050 FullNamedExpression fne = ec.GenericDeclContainer.LookupGeneric (Name, loc);
2052 return fne.ResolveAsTypeStep (ec, silent);
2054 int errors = Report.Errors;
2055 fne = ec.DeclContainer.LookupType (Name, loc, /*ignore_cs0104=*/ false);
2058 if (fne.Type == null)
2061 FullNamedExpression nested = ResolveNested (ec, fne.Type);
2063 return nested.ResolveAsTypeStep (ec, false);
2065 if (Arguments != null) {
2066 ConstructedType ct = new ConstructedType (fne, Arguments, loc);
2067 return ct.ResolveAsTypeStep (ec, false);
2073 if (silent || errors != Report.Errors)
2076 MemberCore mc = ec.DeclContainer.GetDefinition (Name);
2078 Error_UnexpectedKind (ec.DeclContainer, "type", GetMemberType (mc), loc);
2082 string ns = ec.DeclContainer.NamespaceEntry.NS.Name;
2083 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2084 foreach (Assembly a in RootNamespace.Global.Assemblies) {
2085 Type type = a.GetType (fullname);
2087 Report.SymbolRelatedToPreviousError (type);
2088 Expression.ErrorIsInaccesible (loc, fullname);
2093 Type t = ec.DeclContainer.NamespaceEntry.NS.LookForAnyGenericType (Name);
2095 Namespace.Error_InvalidNumberOfTypeArguments (t, loc);
2099 NamespaceEntry.Error_NamespaceNotFound (loc, Name);
2103 // TODO: I am still not convinced about this. If someone else will need it
2104 // implement this as virtual property in MemberCore hierarchy
2105 public static string GetMemberType (MemberCore mc)
2111 if (mc is FieldBase)
2113 if (mc is MethodCore)
2115 if (mc is EnumMember)
2123 Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2129 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2133 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2140 /// 7.5.2: Simple Names.
2142 /// Local Variables and Parameters are handled at
2143 /// parse time, so they never occur as SimpleNames.
2145 /// The `intermediate' flag is used by MemberAccess only
2146 /// and it is used to inform us that it is ok for us to
2147 /// avoid the static check, because MemberAccess might end
2148 /// up resolving the Name as a Type name and the access as
2149 /// a static type access.
2151 /// ie: Type Type; .... { Type.GetType (""); }
2153 /// Type is both an instance variable and a Type; Type.GetType
2154 /// is the static method not an instance method of type.
2156 Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2158 Expression e = null;
2161 // Stage 1: Performed by the parser (binding to locals or parameters).
2163 Block current_block = ec.CurrentBlock;
2164 if (current_block != null){
2165 LocalInfo vi = current_block.GetLocalInfo (Name);
2167 if (Arguments != null) {
2168 Report.Error (307, loc,
2169 "The variable `{0}' cannot be used with type arguments",
2174 LocalVariableReference var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2175 if (right_side != null) {
2176 return var.ResolveLValue (ec, right_side, loc);
2178 ResolveFlags rf = ResolveFlags.VariableOrValue;
2180 rf |= ResolveFlags.DisableFlowAnalysis;
2181 return var.Resolve (ec, rf);
2185 ParameterReference pref = current_block.Toplevel.GetParameterReference (Name, loc);
2187 if (Arguments != null) {
2188 Report.Error (307, loc,
2189 "The variable `{0}' cannot be used with type arguments",
2194 if (right_side != null)
2195 return pref.ResolveLValue (ec, right_side, loc);
2197 return pref.Resolve (ec);
2202 // Stage 2: Lookup members
2205 DeclSpace lookup_ds = ec.DeclContainer;
2206 Type almost_matched_type = null;
2207 ArrayList almost_matched = null;
2209 if (lookup_ds.TypeBuilder == null)
2212 e = MemberLookup (ec.ContainerType, lookup_ds.TypeBuilder, Name, loc);
2216 if (almost_matched == null && almostMatchedMembers.Count > 0) {
2217 almost_matched_type = lookup_ds.TypeBuilder;
2218 almost_matched = (ArrayList) almostMatchedMembers.Clone ();
2221 lookup_ds =lookup_ds.Parent;
2222 } while (lookup_ds != null);
2224 if (e == null && ec.ContainerType != null)
2225 e = MemberLookup (ec.ContainerType, ec.ContainerType, Name, loc);
2228 if (almost_matched == null && almostMatchedMembers.Count > 0) {
2229 almost_matched_type = ec.ContainerType;
2230 almost_matched = (ArrayList) almostMatchedMembers.Clone ();
2232 e = ResolveAsTypeStep (ec, true);
2236 if (almost_matched != null)
2237 almostMatchedMembers = almost_matched;
2238 if (almost_matched_type == null)
2239 almost_matched_type = ec.ContainerType;
2240 MemberLookupFailed (ec.ContainerType, null, almost_matched_type, ((SimpleName) this).Name, ec.DeclContainer.Name, true, loc);
2244 if (e is TypeExpr) {
2245 if (Arguments == null)
2248 ConstructedType ct = new ConstructedType (
2249 (FullNamedExpression) e, Arguments, loc);
2250 return ct.ResolveAsTypeStep (ec, false);
2253 if (e is MemberExpr) {
2254 MemberExpr me = (MemberExpr) e;
2257 if (me.IsInstance) {
2258 if (ec.IsStatic || ec.IsFieldInitializer) {
2260 // Note that an MemberExpr can be both IsInstance and IsStatic.
2261 // An unresolved MethodGroupExpr can contain both kinds of methods
2262 // and each predicate is true if the MethodGroupExpr contains
2263 // at least one of that kind of method.
2267 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2268 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2269 return EmptyExpression.Null;
2273 // Pass the buck to MemberAccess and Invocation.
2275 left = EmptyExpression.Null;
2277 left = ec.GetThis (loc);
2280 left = new TypeExpression (ec.ContainerType, loc);
2283 e = me.ResolveMemberAccess (ec, left, loc, null);
2287 me = e as MemberExpr;
2291 if (Arguments != null) {
2292 MethodGroupExpr mg = me as MethodGroupExpr;
2296 return mg.ResolveGeneric (ec, Arguments);
2299 if (!me.IsStatic && (me.InstanceExpression != null) &&
2300 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2301 me.InstanceExpression.Type != me.DeclaringType &&
2302 !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2303 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2304 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2305 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2309 return (right_side != null)
2310 ? me.DoResolveLValue (ec, right_side)
2311 : me.DoResolve (ec);
2317 public override void Emit (EmitContext ec)
2320 // If this is ever reached, then we failed to
2321 // find the name as a namespace
2324 Error (103, "The name `" + Name +
2325 "' does not exist in the class `" +
2326 ec.DeclContainer.Name + "'");
2329 public override string ToString ()
2334 public override string GetSignatureForError ()
2341 /// Represents a namespace or a type. The name of the class was inspired by
2342 /// section 10.8.1 (Fully Qualified Names).
2344 public abstract class FullNamedExpression : Expression {
2345 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2350 public abstract string FullName {
2356 /// Expression that evaluates to a type
2358 public abstract class TypeExpr : FullNamedExpression {
2359 override public FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2361 TypeExpr t = DoResolveAsTypeStep (ec);
2365 eclass = ExprClass.Type;
2369 override public Expression DoResolve (EmitContext ec)
2371 return ResolveAsTypeTerminal (ec, false);
2374 override public void Emit (EmitContext ec)
2376 throw new Exception ("Should never be called");
2379 public virtual bool CheckAccessLevel (DeclSpace ds)
2381 return ds.CheckAccessLevel (Type);
2384 public virtual bool AsAccessible (DeclSpace ds, int flags)
2386 return ds.AsAccessible (Type, flags);
2389 public virtual bool IsClass {
2390 get { return Type.IsClass; }
2393 public virtual bool IsValueType {
2394 get { return Type.IsValueType; }
2397 public virtual bool IsInterface {
2398 get { return Type.IsInterface; }
2401 public virtual bool IsSealed {
2402 get { return Type.IsSealed; }
2405 public virtual bool CanInheritFrom ()
2407 if (Type == TypeManager.enum_type ||
2408 (Type == TypeManager.value_type && RootContext.StdLib) ||
2409 Type == TypeManager.multicast_delegate_type ||
2410 Type == TypeManager.delegate_type ||
2411 Type == TypeManager.array_type)
2417 protected abstract TypeExpr DoResolveAsTypeStep (IResolveContext ec);
2419 public abstract string Name {
2423 public override bool Equals (object obj)
2425 TypeExpr tobj = obj as TypeExpr;
2429 return Type == tobj.Type;
2432 public override int GetHashCode ()
2434 return Type.GetHashCode ();
2437 public override string ToString ()
2444 /// Fully resolved Expression that already evaluated to a type
2446 public class TypeExpression : TypeExpr {
2447 public TypeExpression (Type t, Location l)
2450 eclass = ExprClass.Type;
2454 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2459 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2464 public override string Name {
2465 get { return Type.ToString (); }
2468 public override string FullName {
2469 get { return Type.FullName; }
2474 /// Used to create types from a fully qualified name. These are just used
2475 /// by the parser to setup the core types. A TypeLookupExpression is always
2476 /// classified as a type.
2478 public sealed class TypeLookupExpression : TypeExpr {
2479 readonly string name;
2481 public TypeLookupExpression (string name)
2484 eclass = ExprClass.Type;
2487 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2489 // It's null for corlib compilation only
2491 return DoResolveAsTypeStep (ec);
2496 static readonly char [] dot_array = { '.' };
2497 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2499 // If name is of the form `N.I', first lookup `N', then search a member `I' in it.
2501 string lookup_name = name;
2502 int pos = name.IndexOf ('.');
2504 rest = name.Substring (pos + 1);
2505 lookup_name = name.Substring (0, pos);
2508 FullNamedExpression resolved = RootNamespace.Global.Lookup (ec.DeclContainer, lookup_name, Location.Null);
2510 if (resolved != null && rest != null) {
2511 // Now handle the rest of the the name.
2512 string [] elements = rest.Split (dot_array);
2514 int count = elements.Length;
2516 while (i < count && resolved != null && resolved is Namespace) {
2517 Namespace ns = resolved as Namespace;
2518 element = elements [i++];
2519 lookup_name += "." + element;
2520 resolved = ns.Lookup (ec.DeclContainer, element, Location.Null);
2523 if (resolved != null && resolved is TypeExpr) {
2524 Type t = ((TypeExpr) resolved).Type;
2526 if (!ec.DeclContainer.CheckAccessLevel (t)) {
2528 lookup_name = t.FullName;
2535 t = TypeManager.GetNestedType (t, elements [i++]);
2540 if (resolved == null) {
2541 NamespaceEntry.Error_NamespaceNotFound (loc, lookup_name);
2545 if (!(resolved is TypeExpr)) {
2546 resolved.Error_UnexpectedKind (ec.DeclContainer, "type", loc);
2550 type = resolved.Type;
2554 public override string Name {
2555 get { return name; }
2558 public override string FullName {
2559 get { return name; }
2564 /// Represents an "unbound generic type", ie. typeof (Foo<>).
2567 public class UnboundTypeExpression : TypeExpr
2571 public UnboundTypeExpression (MemberName name, Location l)
2577 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2580 if (name.Left != null) {
2581 Expression lexpr = name.Left.GetTypeExpression ();
2582 expr = new MemberAccess (lexpr, name.Basename);
2584 expr = new SimpleName (name.Basename, loc);
2587 FullNamedExpression fne = expr.ResolveAsTypeStep (ec, false);
2592 return new TypeExpression (type, loc);
2595 public override string Name {
2596 get { return name.FullName; }
2599 public override string FullName {
2600 get { return name.FullName; }
2604 public class TypeAliasExpression : TypeExpr {
2605 FullNamedExpression alias;
2610 public TypeAliasExpression (FullNamedExpression alias, TypeArguments args, Location l)
2616 eclass = ExprClass.Type;
2618 name = alias.FullName + "<" + args.ToString () + ">";
2620 name = alias.FullName;
2623 public override string Name {
2624 get { return alias.FullName; }
2627 public override string FullName {
2628 get { return name; }
2631 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2633 texpr = alias.ResolveAsTypeTerminal (ec, false);
2637 Type type = texpr.Type;
2638 int num_args = TypeManager.GetNumberOfTypeArguments (type);
2641 if (num_args == 0) {
2642 Report.Error (308, loc,
2643 "The non-generic type `{0}' cannot " +
2644 "be used with type arguments.",
2645 TypeManager.CSharpName (type));
2649 ConstructedType ctype = new ConstructedType (type, args, loc);
2650 return ctype.ResolveAsTypeTerminal (ec, false);
2651 } else if (num_args > 0) {
2652 Report.Error (305, loc,
2653 "Using the generic type `{0}' " +
2654 "requires {1} type arguments",
2655 TypeManager.CSharpName (type), num_args.ToString ());
2662 public override bool CheckAccessLevel (DeclSpace ds)
2664 return texpr.CheckAccessLevel (ds);
2667 public override bool AsAccessible (DeclSpace ds, int flags)
2669 return texpr.AsAccessible (ds, flags);
2672 public override bool IsClass {
2673 get { return texpr.IsClass; }
2676 public override bool IsValueType {
2677 get { return texpr.IsValueType; }
2680 public override bool IsInterface {
2681 get { return texpr.IsInterface; }
2684 public override bool IsSealed {
2685 get { return texpr.IsSealed; }
2690 /// This class denotes an expression which evaluates to a member
2691 /// of a struct or a class.
2693 public abstract class MemberExpr : Expression
2696 /// The name of this member.
2698 public abstract string Name {
2703 /// Whether this is an instance member.
2705 public abstract bool IsInstance {
2710 /// Whether this is a static member.
2712 public abstract bool IsStatic {
2717 /// The type which declares this member.
2719 public abstract Type DeclaringType {
2724 /// The instance expression associated with this member, if it's a
2725 /// non-static member.
2727 public Expression InstanceExpression;
2729 public static void error176 (Location loc, string name)
2731 Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
2732 "with an instance reference, qualify it with a type name instead", name);
2735 // TODO: possible optimalization
2736 // Cache resolved constant result in FieldBuilder <-> expression map
2737 public virtual Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
2738 SimpleName original)
2742 // original == null || original.Resolve (...) ==> left
2745 if (left is TypeExpr) {
2747 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
2755 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
2758 error176 (loc, GetSignatureForError ());
2762 InstanceExpression = left;
2767 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
2772 if (InstanceExpression == EmptyExpression.Null) {
2773 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
2777 if (InstanceExpression.Type.IsValueType) {
2778 if (InstanceExpression is IMemoryLocation) {
2779 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
2781 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
2782 InstanceExpression.Emit (ec);
2784 t.AddressOf (ec, AddressOp.Store);
2787 InstanceExpression.Emit (ec);
2789 if (prepare_for_load)
2790 ec.ig.Emit (OpCodes.Dup);
2795 /// MethodGroup Expression.
2797 /// This is a fully resolved expression that evaluates to a type
2799 public class MethodGroupExpr : MemberExpr {
2800 public MethodBase [] Methods;
2801 bool has_type_arguments = false;
2802 bool identical_type_name = false;
2805 public MethodGroupExpr (MemberInfo [] mi, Location l)
2807 Methods = new MethodBase [mi.Length];
2808 mi.CopyTo (Methods, 0);
2809 eclass = ExprClass.MethodGroup;
2811 // Set the type to something that will never be useful, which will
2812 // trigger the proper conversions.
2813 type = typeof (MethodGroupExpr);
2817 public MethodGroupExpr (ArrayList list, Location l)
2819 Methods = new MethodBase [list.Count];
2822 list.CopyTo (Methods, 0);
2824 foreach (MemberInfo m in list){
2825 if (!(m is MethodBase)){
2826 Console.WriteLine ("Name " + m.Name);
2827 Console.WriteLine ("Found a: " + m.GetType ().FullName);
2834 eclass = ExprClass.MethodGroup;
2835 type = TypeManager.object_type;
2838 public override Type DeclaringType {
2841 // We assume that the top-level type is in the end
2843 return Methods [Methods.Length - 1].DeclaringType;
2844 //return Methods [0].DeclaringType;
2848 public bool HasTypeArguments {
2850 return has_type_arguments;
2854 has_type_arguments = value;
2858 public bool IdenticalTypeName {
2860 return identical_type_name;
2864 identical_type_name = value;
2868 public bool IsBase {
2877 public override string GetSignatureForError ()
2879 return TypeManager.CSharpSignature (Methods [0]);
2882 public override string Name {
2884 return Methods [0].Name;
2888 public override bool IsInstance {
2890 foreach (MethodBase mb in Methods)
2898 public override bool IsStatic {
2900 foreach (MethodBase mb in Methods)
2908 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
2909 SimpleName original)
2911 if (!(left is TypeExpr) &&
2912 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
2913 IdenticalTypeName = true;
2915 return base.ResolveMemberAccess (ec, left, loc, original);
2918 override public Expression DoResolve (EmitContext ec)
2921 InstanceExpression = null;
2923 if (InstanceExpression != null) {
2924 InstanceExpression = InstanceExpression.DoResolve (ec);
2925 if (InstanceExpression == null)
2932 public void ReportUsageError ()
2934 Report.Error (654, loc, "Method `" + DeclaringType + "." +
2935 Name + "()' is referenced without parentheses");
2938 override public void Emit (EmitContext ec)
2940 ReportUsageError ();
2943 bool RemoveMethods (bool keep_static)
2945 ArrayList smethods = new ArrayList ();
2947 foreach (MethodBase mb in Methods){
2948 if (mb.IsStatic == keep_static)
2952 if (smethods.Count == 0)
2955 Methods = new MethodBase [smethods.Count];
2956 smethods.CopyTo (Methods, 0);
2962 /// Removes any instance methods from the MethodGroup, returns
2963 /// false if the resulting set is empty.
2965 public bool RemoveInstanceMethods ()
2967 return RemoveMethods (true);
2971 /// Removes any static methods from the MethodGroup, returns
2972 /// false if the resulting set is empty.
2974 public bool RemoveStaticMethods ()
2976 return RemoveMethods (false);
2979 public Expression ResolveGeneric (EmitContext ec, TypeArguments args)
2982 if (args.Resolve (ec) == false)
2985 Type[] atypes = args.Arguments;
2987 int first_count = 0;
2988 MethodInfo first = null;
2990 ArrayList list = new ArrayList ();
2991 foreach (MethodBase mb in Methods) {
2992 MethodInfo mi = mb as MethodInfo;
2993 if ((mi == null) || !mi.IsGenericMethod)
2996 Type[] gen_params = mi.GetGenericArguments ();
2998 if (first == null) {
3000 first_count = gen_params.Length;
3003 if (gen_params.Length != atypes.Length)
3006 list.Add (mi.MakeGenericMethod (atypes));
3009 if (list.Count > 0) {
3010 MethodGroupExpr new_mg = new MethodGroupExpr (list, Location);
3011 new_mg.InstanceExpression = InstanceExpression;
3012 new_mg.HasTypeArguments = true;
3013 new_mg.IsBase = IsBase;
3019 305, loc, "Using the generic method `{0}' " +
3020 "requires {1} type arguments", Name,
3021 first_count.ToString ());
3024 308, loc, "The non-generic method `{0}' " +
3025 "cannot be used with type arguments", Name);
3029 throw new NotImplementedException ();
3035 /// Fully resolved expression that evaluates to a Field
3037 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariable {
3038 public readonly FieldInfo FieldInfo;
3039 VariableInfo variable_info;
3041 LocalTemporary temp;
3043 bool in_initializer;
3045 public FieldExpr (FieldInfo fi, Location l, bool in_initializer):
3048 this.in_initializer = in_initializer;
3051 public FieldExpr (FieldInfo fi, Location l)
3054 eclass = ExprClass.Variable;
3055 type = TypeManager.TypeToCoreType (fi.FieldType);
3059 public override string Name {
3061 return FieldInfo.Name;
3065 public override bool IsInstance {
3067 return !FieldInfo.IsStatic;
3071 public override bool IsStatic {
3073 return FieldInfo.IsStatic;
3077 public override Type DeclaringType {
3079 return FieldInfo.DeclaringType;
3083 public override string GetSignatureForError ()
3085 return TypeManager.GetFullNameSignature (FieldInfo);
3088 public VariableInfo VariableInfo {
3090 return variable_info;
3094 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3095 SimpleName original)
3097 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
3099 Type t = fi.FieldType;
3101 if (fi.IsLiteral || (fi.IsInitOnly && t == TypeManager.decimal_type)) {
3102 IConstant ic = TypeManager.GetConstant (fi);
3105 ic = new ExternalConstant (fi);
3107 ic = ExternalConstant.CreateDecimal (fi);
3109 return base.ResolveMemberAccess (ec, left, loc, original);
3112 TypeManager.RegisterConstant (fi, ic);
3115 bool left_is_type = left is TypeExpr;
3116 if (!left_is_type && (original == null || !original.IdenticalNameAndTypeName (ec, left, loc))) {
3117 Report.SymbolRelatedToPreviousError (FieldInfo);
3118 error176 (loc, TypeManager.GetFullNameSignature (FieldInfo));
3122 if (ic.ResolveValue ()) {
3123 if (!ec.IsInObsoleteScope)
3124 ic.CheckObsoleteness (loc);
3127 return ic.CreateConstantReference (loc);
3130 if (t.IsPointer && !ec.InUnsafe) {
3135 return base.ResolveMemberAccess (ec, left, loc, original);
3138 override public Expression DoResolve (EmitContext ec)
3140 return DoResolve (ec, false, false);
3143 Expression DoResolve (EmitContext ec, bool lvalue_instance, bool out_access)
3145 if (!FieldInfo.IsStatic){
3146 if (InstanceExpression == null){
3148 // This can happen when referencing an instance field using
3149 // a fully qualified type expression: TypeName.InstanceField = xxx
3151 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3155 // Resolve the field's instance expression while flow analysis is turned
3156 // off: when accessing a field "a.b", we must check whether the field
3157 // "a.b" is initialized, not whether the whole struct "a" is initialized.
3159 if (lvalue_instance) {
3160 using (ec.With (EmitContext.Flags.DoFlowAnalysis, false)) {
3161 Expression right_side =
3162 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
3163 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side, loc);
3166 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
3167 InstanceExpression = InstanceExpression.Resolve (ec, rf);
3170 if (InstanceExpression == null)
3173 InstanceExpression.CheckMarshalByRefAccess ();
3176 if (!in_initializer && !ec.IsFieldInitializer) {
3177 ObsoleteAttribute oa;
3178 FieldBase f = TypeManager.GetField (FieldInfo);
3180 if (!ec.IsInObsoleteScope)
3181 f.CheckObsoleteness (loc);
3183 // To be sure that type is external because we do not register generated fields
3184 } else if (!(FieldInfo.DeclaringType is TypeBuilder)) {
3185 oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
3187 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
3191 AnonymousContainer am = ec.CurrentAnonymousMethod;
3193 if (!FieldInfo.IsStatic){
3194 if (!am.IsIterator && (ec.TypeContainer is Struct)){
3195 Report.Error (1673, loc,
3196 "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",
3203 // If the instance expression is a local variable or parameter.
3204 IVariable var = InstanceExpression as IVariable;
3205 if ((var == null) || (var.VariableInfo == null))
3208 VariableInfo vi = var.VariableInfo;
3209 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
3212 variable_info = vi.GetSubStruct (FieldInfo.Name);
3216 static readonly int [] codes = {
3217 191, // instance, write access
3218 192, // instance, out access
3219 198, // static, write access
3220 199, // static, out access
3221 1648, // member of value instance, write access
3222 1649, // member of value instance, out access
3223 1650, // member of value static, write access
3224 1651 // member of value static, out access
3227 static readonly string [] msgs = {
3228 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
3229 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
3230 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
3231 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
3232 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
3233 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
3234 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
3235 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
3238 // The return value is always null. Returning a value simplifies calling code.
3239 Expression Report_AssignToReadonly (Expression right_side)
3242 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
3246 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
3248 Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
3253 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3255 IVariable var = InstanceExpression as IVariable;
3256 if ((var != null) && (var.VariableInfo != null))
3257 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
3259 bool lvalue_instance = !FieldInfo.IsStatic && FieldInfo.DeclaringType.IsValueType;
3260 bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
3262 Expression e = DoResolve (ec, lvalue_instance, out_access);
3267 FieldBase fb = TypeManager.GetField (FieldInfo);
3271 if (FieldInfo.IsInitOnly) {
3272 // InitOnly fields can only be assigned in constructors or initializers
3273 if (!ec.IsFieldInitializer && !ec.IsConstructor)
3274 return Report_AssignToReadonly (right_side);
3276 if (ec.IsConstructor) {
3277 Type ctype = ec.TypeContainer.CurrentType;
3279 ctype = ec.ContainerType;
3281 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
3282 if (!TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
3283 return Report_AssignToReadonly (right_side);
3284 // static InitOnly fields cannot be assigned-to in an instance constructor
3285 if (IsStatic && !ec.IsStatic)
3286 return Report_AssignToReadonly (right_side);
3287 // instance constructors can't modify InitOnly fields of other instances of the same type
3288 if (!IsStatic && !(InstanceExpression is This))
3289 return Report_AssignToReadonly (right_side);
3293 if (right_side == EmptyExpression.OutAccess &&
3294 !IsStatic && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
3295 Report.SymbolRelatedToPreviousError (DeclaringType);
3296 Report.Warning (197, 1, loc,
3297 "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",
3298 GetSignatureForError ());
3304 public override void CheckMarshalByRefAccess ()
3306 if (!IsStatic && Type.IsValueType && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
3307 Report.SymbolRelatedToPreviousError (DeclaringType);
3308 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",
3309 GetSignatureForError ());
3313 public bool VerifyFixed ()
3315 IVariable variable = InstanceExpression as IVariable;
3316 // A variable of the form V.I is fixed when V is a fixed variable of a struct type.
3317 // We defer the InstanceExpression check after the variable check to avoid a
3318 // separate null check on InstanceExpression.
3319 return variable != null && InstanceExpression.Type.IsValueType && variable.VerifyFixed ();
3322 public override int GetHashCode ()
3324 return FieldInfo.GetHashCode ();
3327 public override bool Equals (object obj)
3329 FieldExpr fe = obj as FieldExpr;
3333 if (FieldInfo != fe.FieldInfo)
3336 if (InstanceExpression == null || fe.InstanceExpression == null)
3339 return InstanceExpression.Equals (fe.InstanceExpression);
3342 public void Emit (EmitContext ec, bool leave_copy)
3344 ILGenerator ig = ec.ig;
3345 bool is_volatile = false;
3347 FieldBase f = TypeManager.GetField (FieldInfo);
3349 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
3352 f.SetMemberIsUsed ();
3355 if (FieldInfo.IsStatic){
3357 ig.Emit (OpCodes.Volatile);
3359 ig.Emit (OpCodes.Ldsfld, FieldInfo);
3362 EmitInstance (ec, false);
3365 ig.Emit (OpCodes.Volatile);
3367 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
3370 ig.Emit (OpCodes.Ldflda, FieldInfo);
3371 ig.Emit (OpCodes.Ldflda, ff.Element);
3374 ig.Emit (OpCodes.Ldfld, FieldInfo);
3379 ec.ig.Emit (OpCodes.Dup);
3380 if (!FieldInfo.IsStatic) {
3381 temp = new LocalTemporary (this.Type);
3387 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
3389 FieldAttributes fa = FieldInfo.Attributes;
3390 bool is_static = (fa & FieldAttributes.Static) != 0;
3391 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
3392 ILGenerator ig = ec.ig;
3393 prepared = prepare_for_load;
3395 if (is_readonly && !ec.IsConstructor){
3396 Report_AssignToReadonly (source);
3400 EmitInstance (ec, prepare_for_load);
3404 ec.ig.Emit (OpCodes.Dup);
3405 if (!FieldInfo.IsStatic) {
3406 temp = new LocalTemporary (this.Type);
3411 FieldBase f = TypeManager.GetField (FieldInfo);
3413 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
3414 ig.Emit (OpCodes.Volatile);
3420 ig.Emit (OpCodes.Stsfld, FieldInfo);
3422 ig.Emit (OpCodes.Stfld, FieldInfo);
3430 public override void Emit (EmitContext ec)
3435 public void AddressOf (EmitContext ec, AddressOp mode)
3437 ILGenerator ig = ec.ig;
3439 FieldBase f = TypeManager.GetField (FieldInfo);
3441 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
3442 Report.Warning (420, 1, loc, "`{0}': A volatile fields cannot be passed using a ref or out parameter",
3443 f.GetSignatureForError ());
3447 if ((mode & AddressOp.Store) != 0)
3449 if ((mode & AddressOp.Load) != 0)
3450 f.SetMemberIsUsed ();
3454 // Handle initonly fields specially: make a copy and then
3455 // get the address of the copy.
3458 if (FieldInfo.IsInitOnly){
3460 if (ec.IsConstructor){
3461 if (FieldInfo.IsStatic){
3473 local = ig.DeclareLocal (type);
3474 ig.Emit (OpCodes.Stloc, local);
3475 ig.Emit (OpCodes.Ldloca, local);
3480 if (FieldInfo.IsStatic){
3481 ig.Emit (OpCodes.Ldsflda, FieldInfo);
3484 EmitInstance (ec, false);
3485 ig.Emit (OpCodes.Ldflda, FieldInfo);
3491 // A FieldExpr whose address can not be taken
3493 public class FieldExprNoAddress : FieldExpr, IMemoryLocation {
3494 public FieldExprNoAddress (FieldInfo fi, Location loc) : base (fi, loc)
3498 public new void AddressOf (EmitContext ec, AddressOp mode)
3500 Report.Error (-215, "Report this: Taking the address of a remapped parameter not supported");
3505 /// Expression that evaluates to a Property. The Assign class
3506 /// might set the `Value' expression if we are in an assignment.
3508 /// This is not an LValue because we need to re-write the expression, we
3509 /// can not take data from the stack and store it.
3511 public class PropertyExpr : MemberExpr, IAssignMethod {
3512 public readonly PropertyInfo PropertyInfo;
3515 // This is set externally by the `BaseAccess' class
3518 MethodInfo getter, setter;
3523 LocalTemporary temp;
3526 public PropertyExpr (Type containerType, PropertyInfo pi, Location l)
3529 eclass = ExprClass.PropertyAccess;
3533 type = TypeManager.TypeToCoreType (pi.PropertyType);
3535 ResolveAccessors (containerType);
3538 public override string Name {
3540 return PropertyInfo.Name;
3544 public override bool IsInstance {
3550 public override bool IsStatic {
3556 public override Type DeclaringType {
3558 return PropertyInfo.DeclaringType;
3562 public override string GetSignatureForError ()
3564 return TypeManager.GetFullNameSignature (PropertyInfo);
3567 void FindAccessors (Type invocation_type)
3569 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
3570 BindingFlags.Static | BindingFlags.Instance |
3571 BindingFlags.DeclaredOnly;
3573 Type current = PropertyInfo.DeclaringType;
3574 for (; current != null; current = current.BaseType) {
3575 MemberInfo[] group = TypeManager.MemberLookup (
3576 invocation_type, invocation_type, current,
3577 MemberTypes.Property, flags, PropertyInfo.Name, null);
3582 if (group.Length != 1)
3583 // Oooops, can this ever happen ?
3586 PropertyInfo pi = (PropertyInfo) group [0];
3589 getter = pi.GetGetMethod (true);
3592 setter = pi.GetSetMethod (true);
3594 MethodInfo accessor = getter != null ? getter : setter;
3596 if (!accessor.IsVirtual)
3602 // We also perform the permission checking here, as the PropertyInfo does not
3603 // hold the information for the accessibility of its setter/getter
3605 // TODO: Refactor to use some kind of cache together with GetPropertyFromAccessor
3606 void ResolveAccessors (Type containerType)
3608 FindAccessors (containerType);
3610 if (getter != null) {
3611 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
3612 IMethodData md = TypeManager.GetMethod (the_getter);
3614 md.SetMemberIsUsed ();
3616 is_static = getter.IsStatic;
3619 if (setter != null) {
3620 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
3621 IMethodData md = TypeManager.GetMethod (the_setter);
3623 md.SetMemberIsUsed ();
3625 is_static = setter.IsStatic;
3629 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
3632 InstanceExpression = null;
3636 if (InstanceExpression == null) {
3637 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3641 InstanceExpression = InstanceExpression.DoResolve (ec);
3642 if (lvalue_instance && InstanceExpression != null)
3643 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
3645 if (InstanceExpression == null)
3648 InstanceExpression.CheckMarshalByRefAccess ();
3650 if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) &&
3651 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
3652 !TypeManager.IsNestedChildOf (ec.ContainerType, InstanceExpression.Type) &&
3653 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.ContainerType)) {
3654 Report.SymbolRelatedToPreviousError (PropertyInfo);
3655 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
3662 void Error_PropertyNotFound (MethodInfo mi, bool getter)
3664 // TODO: correctly we should compare arguments but it will lead to bigger changes
3665 if (mi is MethodBuilder) {
3666 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
3670 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
3672 ParameterData iparams = TypeManager.GetParameterData (mi);
3673 sig.Append (getter ? "get_" : "set_");
3675 sig.Append (iparams.GetSignatureForError ());
3677 Report.SymbolRelatedToPreviousError (mi);
3678 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
3679 Name, sig.ToString ());
3682 override public Expression DoResolve (EmitContext ec)
3687 if (getter != null){
3688 if (TypeManager.GetParameterData (getter).Count != 0){
3689 Error_PropertyNotFound (getter, true);
3694 if (getter == null){
3696 // The following condition happens if the PropertyExpr was
3697 // created, but is invalid (ie, the property is inaccessible),
3698 // and we did not want to embed the knowledge about this in
3699 // the caller routine. This only avoids double error reporting.
3704 if (InstanceExpression != EmptyExpression.Null) {
3705 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
3706 TypeManager.GetFullNameSignature (PropertyInfo));
3711 bool must_do_cs1540_check = false;
3712 if (getter != null &&
3713 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
3714 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
3715 if (pm != null && pm.HasCustomAccessModifier) {
3716 Report.SymbolRelatedToPreviousError (pm);
3717 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
3718 TypeManager.CSharpSignature (getter));
3721 Report.SymbolRelatedToPreviousError (getter);
3722 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
3727 if (!InstanceResolve (ec, false, must_do_cs1540_check))
3731 // Only base will allow this invocation to happen.
3733 if (IsBase && getter.IsAbstract) {
3734 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
3738 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
3748 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3750 if (right_side == EmptyExpression.OutAccess) {
3751 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
3752 GetSignatureForError ());
3756 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
3757 Report.Error (1612, loc, "Cannot modify the return value of `{0}' because it is not a variable",
3758 GetSignatureForError ());
3762 if (setter == null){
3764 // The following condition happens if the PropertyExpr was
3765 // created, but is invalid (ie, the property is inaccessible),
3766 // and we did not want to embed the knowledge about this in
3767 // the caller routine. This only avoids double error reporting.
3771 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
3772 GetSignatureForError ());
3776 if (TypeManager.GetParameterData (setter).Count != 1){
3777 Error_PropertyNotFound (setter, false);
3781 bool must_do_cs1540_check;
3782 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
3783 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
3784 if (pm != null && pm.HasCustomAccessModifier) {
3785 Report.SymbolRelatedToPreviousError (pm);
3786 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
3787 TypeManager.CSharpSignature (setter));
3790 Report.SymbolRelatedToPreviousError (setter);
3791 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
3796 if (!InstanceResolve (ec, PropertyInfo.DeclaringType.IsValueType, must_do_cs1540_check))
3800 // Only base will allow this invocation to happen.
3802 if (IsBase && setter.IsAbstract){
3803 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
3810 public override void Emit (EmitContext ec)
3815 public void Emit (EmitContext ec, bool leave_copy)
3818 // Special case: length of single dimension array property is turned into ldlen
3820 if ((getter == TypeManager.system_int_array_get_length) ||
3821 (getter == TypeManager.int_array_get_length)){
3822 Type iet = InstanceExpression.Type;
3825 // System.Array.Length can be called, but the Type does not
3826 // support invoking GetArrayRank, so test for that case first
3828 if (iet != TypeManager.array_type && (iet.GetArrayRank () == 1)) {
3830 EmitInstance (ec, false);
3831 ec.ig.Emit (OpCodes.Ldlen);
3832 ec.ig.Emit (OpCodes.Conv_I4);
3837 Invocation.EmitCall (ec, IsBase, IsStatic, InstanceExpression, getter, null, loc, prepared, false);
3840 ec.ig.Emit (OpCodes.Dup);
3842 temp = new LocalTemporary (this.Type);
3849 // Implements the IAssignMethod interface for assignments
3851 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
3853 Expression my_source = source;
3855 prepared = prepare_for_load;
3860 ec.ig.Emit (OpCodes.Dup);
3862 temp = new LocalTemporary (this.Type);
3866 } else if (leave_copy) {
3869 temp = new LocalTemporary (this.Type);
3875 ArrayList args = new ArrayList (1);
3876 args.Add (new Argument (my_source, Argument.AType.Expression));
3878 Invocation.EmitCall (ec, IsBase, IsStatic, InstanceExpression, setter, args, loc, false, prepared);
3888 /// Fully resolved expression that evaluates to an Event
3890 public class EventExpr : MemberExpr {
3891 public readonly EventInfo EventInfo;
3894 MethodInfo add_accessor, remove_accessor;
3896 public EventExpr (EventInfo ei, Location loc)
3900 eclass = ExprClass.EventAccess;
3902 add_accessor = TypeManager.GetAddMethod (ei);
3903 remove_accessor = TypeManager.GetRemoveMethod (ei);
3904 if (add_accessor.IsStatic || remove_accessor.IsStatic)
3907 if (EventInfo is MyEventBuilder){
3908 MyEventBuilder eb = (MyEventBuilder) EventInfo;
3909 type = eb.EventType;
3912 type = EventInfo.EventHandlerType;
3915 public override string Name {
3917 return EventInfo.Name;
3921 public override bool IsInstance {
3927 public override bool IsStatic {
3933 public override Type DeclaringType {
3935 return EventInfo.DeclaringType;
3939 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3940 SimpleName original)
3943 // If the event is local to this class, we transform ourselves into a FieldExpr
3946 if (EventInfo.DeclaringType == ec.ContainerType ||
3947 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
3948 EventField mi = TypeManager.GetEventField (EventInfo);
3951 if (!ec.IsInObsoleteScope)
3952 mi.CheckObsoleteness (loc);
3954 FieldExpr ml = new FieldExpr (mi.FieldBuilder, loc);
3956 InstanceExpression = null;
3958 return ml.ResolveMemberAccess (ec, left, loc, original);
3962 return base.ResolveMemberAccess (ec, left, loc, original);
3966 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
3969 InstanceExpression = null;
3973 if (InstanceExpression == null) {
3974 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3978 InstanceExpression = InstanceExpression.DoResolve (ec);
3979 if (InstanceExpression == null)
3983 // This is using the same mechanism as the CS1540 check in PropertyExpr.
3984 // However, in the Event case, we reported a CS0122 instead.
3986 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
3987 InstanceExpression.Type != ec.ContainerType &&
3988 ec.ContainerType.IsSubclassOf (InstanceExpression.Type)) {
3989 Report.SymbolRelatedToPreviousError (EventInfo);
3990 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
3997 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
3999 return DoResolve (ec);
4002 public override Expression DoResolve (EmitContext ec)
4004 bool must_do_cs1540_check;
4005 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
4006 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
4007 Report.SymbolRelatedToPreviousError (EventInfo);
4008 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
4012 if (!InstanceResolve (ec, must_do_cs1540_check))
4018 public override void Emit (EmitContext ec)
4020 if (InstanceExpression is This)
4021 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of += or -=", GetSignatureForError ());
4023 Report.Error (70, loc, "The event `{0}' can only appear on the left hand side of += or -= "+
4024 "(except on the defining type)", Name);
4027 public override string GetSignatureForError ()
4029 return TypeManager.CSharpSignature (EventInfo);
4032 public void EmitAddOrRemove (EmitContext ec, Expression source)
4034 BinaryDelegate source_del = source as BinaryDelegate;
4035 if (source_del == null) {
4039 Expression handler = source_del.Right;
4041 Argument arg = new Argument (handler, Argument.AType.Expression);
4042 ArrayList args = new ArrayList ();
4046 if (source_del.IsAddition)
4047 Invocation.EmitCall (
4048 ec, false, IsStatic, InstanceExpression, add_accessor, args, loc);
4050 Invocation.EmitCall (
4051 ec, false, IsStatic, InstanceExpression, remove_accessor, args, loc);
4055 public class TemporaryVariable : Expression, IMemoryLocation
4060 public TemporaryVariable (Type type, Location loc)
4064 eclass = ExprClass.Value;
4067 public override Expression DoResolve (EmitContext ec)
4072 TypeExpr te = new TypeExpression (type, loc);
4073 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
4074 if (!li.Resolve (ec))
4077 if (ec.MustCaptureVariable (li)) {
4078 ScopeInfo scope = li.Block.CreateScopeInfo ();
4079 var = scope.AddLocal (li);
4086 public Variable Variable {
4087 get { return var != null ? var : li.Variable; }
4090 public override void Emit (EmitContext ec)
4092 Variable.EmitInstance (ec);
4096 public void EmitLoadAddress (EmitContext ec)
4098 Variable.EmitInstance (ec);
4099 Variable.EmitAddressOf (ec);
4102 public void Store (EmitContext ec, Expression right_side)
4104 Variable.EmitInstance (ec);
4105 right_side.Emit (ec);
4106 Variable.EmitAssign (ec);
4109 public void EmitThis (EmitContext ec)
4111 Variable.EmitInstance (ec);
4114 public void EmitStore (EmitContext ec)
4116 Variable.EmitAssign (ec);
4119 public void AddressOf (EmitContext ec, AddressOp mode)
4121 EmitLoadAddress (ec);