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);
242 ObsoleteAttribute obsolete_attr = AttributeTester.GetObsoleteAttribute (te.Type);
243 if (obsolete_attr != null && !ec.IsInObsoleteScope) {
244 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location);
249 public TypeExpr ResolveAsBaseTerminal (IResolveContext ec, bool silent)
251 int errors = Report.Errors;
253 FullNamedExpression fne = ResolveAsTypeStep (ec, silent);
256 if (!silent && errors == Report.Errors)
257 Report.Error (118, loc, "Expecting a type.");
261 if (fne.eclass != ExprClass.Type) {
262 if (!silent && errors == Report.Errors)
263 fne.Error_UnexpectedKind (null, "type", loc);
267 TypeExpr te = fne as TypeExpr;
269 if (!te.CheckAccessLevel (ec.DeclContainer)) {
270 ErrorIsInaccesible (loc, TypeManager.CSharpName (te.Type));
274 // Constrains don't need to be checked for overrides
275 GenericMethod gm = ec.DeclContainer as GenericMethod;
276 if (gm != null && (gm.ModFlags & Modifiers.OVERRIDE) != 0) {
281 ConstructedType ct = te as ConstructedType;
282 if ((ct != null) && !ct.CheckConstraints (ec))
289 public static void ErrorIsInaccesible (Location loc, string name)
291 Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", name);
294 protected static void Error_CannotAccessProtected (Location loc, MemberInfo m, Type qualifier, Type container)
296 Report.Error (1540, loc, "Cannot access protected member `{0}' via a qualifier of type `{1}';"
297 + " the qualifier must be of type `{2}' (or derived from it)",
298 TypeManager.GetFullNameSignature (m),
299 TypeManager.CSharpName (qualifier),
300 TypeManager.CSharpName (container));
304 public virtual void Error_ValueCannotBeConverted (Location loc, Type target, bool expl)
306 if (Type.Name == target.Name){
307 Report.ExtraInformation (loc,
309 "The type {0} has two conflicting definitions, one comes from {1} and the other from {2}",
310 Type.Name, Type.Assembly.FullName, target.Assembly.FullName));
315 Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
316 GetSignatureForError (), TypeManager.CSharpName (target));
320 Expression e = (this is EnumConstant) ? ((EnumConstant)this).Child : this;
321 bool b = Convert.ExplicitNumericConversion (e, target) != null;
323 if (b || Convert.ExplicitReferenceConversionExists (Type, target) || Convert.ExplicitUnsafe (e, target) != null) {
324 Report.Error (266, loc, "Cannot implicitly convert type `{0}' to `{1}'. An explicit conversion exists (are you missing a cast?)",
325 TypeManager.CSharpName (Type), TypeManager.CSharpName (target));
329 if (Type != TypeManager.string_type && this is Constant && !(this is NullCast)) {
330 Report.Error (31, loc, "Constant value `{0}' cannot be converted to a `{1}'",
331 GetSignatureForError (), TypeManager.CSharpName (target));
335 Report.Error (29, loc, "Cannot implicitly convert type {0} to `{1}'",
336 Type == TypeManager.anonymous_method_type ?
337 "anonymous method" : "`" + GetSignatureForError () + "'",
338 TypeManager.CSharpName (target));
341 protected static void Error_TypeDoesNotContainDefinition (Location loc, Type type, string name)
343 Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
344 TypeManager.CSharpName (type), name);
347 ResolveFlags ExprClassToResolveFlags
352 case ExprClass.Namespace:
353 return ResolveFlags.Type;
355 case ExprClass.MethodGroup:
356 return ResolveFlags.MethodGroup;
358 case ExprClass.Value:
359 case ExprClass.Variable:
360 case ExprClass.PropertyAccess:
361 case ExprClass.EventAccess:
362 case ExprClass.IndexerAccess:
363 return ResolveFlags.VariableOrValue;
366 throw new Exception ("Expression " + GetType () +
367 " ExprClass is Invalid after resolve");
373 /// Resolves an expression and performs semantic analysis on it.
377 /// Currently Resolve wraps DoResolve to perform sanity
378 /// checking and assertion checking on what we expect from Resolve.
380 public Expression Resolve (EmitContext ec, ResolveFlags flags)
382 if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type)
383 return ResolveAsTypeStep (ec, false);
385 bool old_do_flow_analysis = ec.DoFlowAnalysis;
386 bool old_omit_struct_analysis = ec.OmitStructFlowAnalysis;
387 if ((flags & ResolveFlags.DisableFlowAnalysis) != 0)
388 ec.DoFlowAnalysis = false;
389 if ((flags & ResolveFlags.DisableStructFlowAnalysis) != 0)
390 ec.OmitStructFlowAnalysis = true;
393 if (this is SimpleName) {
394 bool intermediate = (flags & ResolveFlags.Intermediate) == ResolveFlags.Intermediate;
395 e = ((SimpleName) this).DoResolve (ec, intermediate);
400 ec.DoFlowAnalysis = old_do_flow_analysis;
401 ec.OmitStructFlowAnalysis = old_omit_struct_analysis;
406 if ((flags & e.ExprClassToResolveFlags) == 0) {
407 e.Error_UnexpectedKind (flags, loc);
411 if (e.type == null && !(e is Namespace)) {
412 throw new Exception (
413 "Expression " + e.GetType () +
414 " did not set its type after Resolve\n" +
415 "called from: " + this.GetType ());
422 /// Resolves an expression and performs semantic analysis on it.
424 public Expression Resolve (EmitContext ec)
426 Expression e = Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
428 if (e != null && e.eclass == ExprClass.MethodGroup && RootContext.Version == LanguageVersion.ISO_1) {
429 ((MethodGroupExpr) e).ReportUsageError ();
435 public Constant ResolveAsConstant (EmitContext ec, MemberCore mc)
437 Expression e = Resolve (ec);
441 Constant c = e as Constant;
445 Type constant_type = null;
446 if (mc is MemberBase) {
447 constant_type = ((MemberBase)mc).MemberType;
450 Const.Error_ExpressionMustBeConstant (constant_type, loc, mc.GetSignatureForError ());
455 /// Resolves an expression for LValue assignment
459 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
460 /// checking and assertion checking on what we expect from Resolve
462 public Expression ResolveLValue (EmitContext ec, Expression right_side, Location loc)
464 int errors = Report.Errors;
465 bool out_access = right_side == EmptyExpression.OutAccess;
467 Expression e = DoResolveLValue (ec, right_side);
469 if (e != null && out_access && !(e is IMemoryLocation)) {
470 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
471 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
473 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
474 // e.GetType () + " " + e.GetSignatureForError ());
479 if (errors == Report.Errors) {
481 Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
483 Report.Error (131, loc, "The left-hand side of an assignment or mutating operation must be a variable, property or indexer");
488 if (e.eclass == ExprClass.Invalid)
489 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
491 if (e.eclass == ExprClass.MethodGroup) {
492 ((MethodGroupExpr) e).ReportUsageError ();
496 if ((e.type == null) && !(e is ConstructedType))
497 throw new Exception ("Expression " + e + " did not set its type after Resolve");
503 /// Emits the code for the expression
507 /// The Emit method is invoked to generate the code
508 /// for the expression.
510 public abstract void Emit (EmitContext ec);
512 public virtual void EmitBranchable (EmitContext ec, Label target, bool onTrue)
515 ec.ig.Emit (onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target);
519 /// Protected constructor. Only derivate types should
520 /// be able to be created
523 protected Expression ()
525 eclass = ExprClass.Invalid;
530 /// Returns a literalized version of a literal FieldInfo
534 /// The possible return values are:
535 /// IntConstant, UIntConstant
536 /// LongLiteral, ULongConstant
537 /// FloatConstant, DoubleConstant
540 /// The value returned is already resolved.
542 public static Constant Constantify (object v, Type t)
544 if (t == TypeManager.int32_type)
545 return new IntConstant ((int) v, Location.Null);
546 else if (t == TypeManager.uint32_type)
547 return new UIntConstant ((uint) v, Location.Null);
548 else if (t == TypeManager.int64_type)
549 return new LongConstant ((long) v, Location.Null);
550 else if (t == TypeManager.uint64_type)
551 return new ULongConstant ((ulong) v, Location.Null);
552 else if (t == TypeManager.float_type)
553 return new FloatConstant ((float) v, Location.Null);
554 else if (t == TypeManager.double_type)
555 return new DoubleConstant ((double) v, Location.Null);
556 else if (t == TypeManager.string_type)
557 return new StringConstant ((string) v, Location.Null);
558 else if (t == TypeManager.short_type)
559 return new ShortConstant ((short)v, Location.Null);
560 else if (t == TypeManager.ushort_type)
561 return new UShortConstant ((ushort)v, Location.Null);
562 else if (t == TypeManager.sbyte_type)
563 return new SByteConstant ((sbyte)v, Location.Null);
564 else if (t == TypeManager.byte_type)
565 return new ByteConstant ((byte)v, Location.Null);
566 else if (t == TypeManager.char_type)
567 return new CharConstant ((char)v, Location.Null);
568 else if (t == TypeManager.bool_type)
569 return new BoolConstant ((bool) v, Location.Null);
570 else if (t == TypeManager.decimal_type)
571 return new DecimalConstant ((decimal) v, Location.Null);
572 else if (TypeManager.IsEnumType (t)){
573 Type real_type = TypeManager.TypeToCoreType (v.GetType ());
575 real_type = System.Enum.GetUnderlyingType (real_type);
577 Constant e = Constantify (v, real_type);
579 return new EnumConstant (e, t);
580 } else if (v == null && !TypeManager.IsValueType (t))
581 return new NullLiteral (Location.Null);
583 throw new Exception ("Unknown type for constant (" + t +
588 /// Returns a fully formed expression after a MemberLookup
591 public static Expression ExprClassFromMemberInfo (Type containerType, MemberInfo mi, Location loc)
594 return new EventExpr ((EventInfo) mi, loc);
595 else if (mi is FieldInfo)
596 return new FieldExpr ((FieldInfo) mi, loc);
597 else if (mi is PropertyInfo)
598 return new PropertyExpr (containerType, (PropertyInfo) mi, loc);
599 else if (mi is Type){
600 return new TypeExpression ((System.Type) mi, loc);
606 protected static ArrayList almostMatchedMembers = new ArrayList (4);
609 // FIXME: Probably implement a cache for (t,name,current_access_set)?
611 // This code could use some optimizations, but we need to do some
612 // measurements. For example, we could use a delegate to `flag' when
613 // something can not any longer be a method-group (because it is something
617 // If the return value is an Array, then it is an array of
620 // If the return value is an MemberInfo, it is anything, but a Method
624 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
625 // the arguments here and have MemberLookup return only the methods that
626 // match the argument count/type, unlike we are doing now (we delay this
629 // This is so we can catch correctly attempts to invoke instance methods
630 // from a static body (scan for error 120 in ResolveSimpleName).
633 // FIXME: Potential optimization, have a static ArrayList
636 public static Expression MemberLookup (Type container_type, Type queried_type, string name,
637 MemberTypes mt, BindingFlags bf, Location loc)
639 return MemberLookup (container_type, null, queried_type, name, mt, bf, loc);
643 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
644 // `qualifier_type' or null to lookup members in the current class.
647 public static Expression MemberLookup (Type container_type,
648 Type qualifier_type, Type queried_type,
649 string name, MemberTypes mt,
650 BindingFlags bf, Location loc)
652 almostMatchedMembers.Clear ();
654 MemberInfo [] mi = TypeManager.MemberLookup (container_type, qualifier_type,
655 queried_type, mt, bf, name, almostMatchedMembers);
660 int count = mi.Length;
662 if (mi [0] is MethodBase)
663 return new MethodGroupExpr (mi, loc);
668 return ExprClassFromMemberInfo (container_type, mi [0], loc);
671 public const MemberTypes AllMemberTypes =
672 MemberTypes.Constructor |
676 MemberTypes.NestedType |
677 MemberTypes.Property;
679 public const BindingFlags AllBindingFlags =
680 BindingFlags.Public |
681 BindingFlags.Static |
682 BindingFlags.Instance;
684 public static Expression MemberLookup (Type container_type, Type queried_type,
685 string name, Location loc)
687 return MemberLookup (container_type, null, queried_type, name,
688 AllMemberTypes, AllBindingFlags, loc);
691 public static Expression MemberLookup (Type container_type, Type qualifier_type,
692 Type queried_type, string name, Location loc)
694 return MemberLookup (container_type, qualifier_type, queried_type,
695 name, AllMemberTypes, AllBindingFlags, loc);
698 public static Expression MethodLookup (EmitContext ec, Type queried_type,
699 string name, Location loc)
701 return MemberLookup (ec.ContainerType, null, queried_type, name,
702 MemberTypes.Method, AllBindingFlags, loc);
706 /// This is a wrapper for MemberLookup that is not used to "probe", but
707 /// to find a final definition. If the final definition is not found, we
708 /// look for private members and display a useful debugging message if we
711 public static Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
712 Type queried_type, string name, Location loc)
714 return MemberLookupFinal (ec, qualifier_type, queried_type, name,
715 AllMemberTypes, AllBindingFlags, loc);
718 public static Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
719 Type queried_type, string name,
720 MemberTypes mt, BindingFlags bf,
725 int errors = Report.Errors;
727 e = MemberLookup (ec.ContainerType, qualifier_type, queried_type, name, mt, bf, loc);
729 if (e == null && errors == Report.Errors)
730 // No errors were reported by MemberLookup, but there was an error.
731 MemberLookupFailed (ec.ContainerType, qualifier_type, queried_type, name, null, true, loc);
736 public static void MemberLookupFailed (Type container_type, Type qualifier_type,
737 Type queried_type, string name,
738 string class_name, bool complain_if_none_found,
741 if (almostMatchedMembers.Count != 0) {
742 for (int i = 0; i < almostMatchedMembers.Count; ++i) {
743 MemberInfo m = (MemberInfo) almostMatchedMembers [i];
744 for (int j = 0; j < i; ++j) {
745 if (m == almostMatchedMembers [j]) {
753 Type declaring_type = m.DeclaringType;
755 Report.SymbolRelatedToPreviousError (m);
756 if (qualifier_type == null) {
757 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
758 TypeManager.CSharpName (m.DeclaringType),
759 TypeManager.CSharpName (container_type));
761 } else if (qualifier_type != container_type &&
762 TypeManager.IsNestedFamilyAccessible (container_type, declaring_type)) {
763 // Although a derived class can access protected members of
764 // its base class it cannot do so through an instance of the
765 // base class (CS1540). If the qualifier_type is a base of the
766 // ec.ContainerType and the lookup succeeds with the latter one,
767 // then we are in this situation.
768 Error_CannotAccessProtected (loc, m, qualifier_type, container_type);
770 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (m));
773 almostMatchedMembers.Clear ();
777 MemberInfo[] lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
778 AllMemberTypes, AllBindingFlags |
779 BindingFlags.NonPublic, name, null);
781 if (lookup == null) {
782 if (!complain_if_none_found)
785 if (class_name != null)
786 Report.Error (103, loc, "The name `{0}' does not exist in the context of `{1}'",
789 Error_TypeDoesNotContainDefinition (loc, queried_type, name);
793 if (TypeManager.MemberLookup (queried_type, null, queried_type,
794 AllMemberTypes, AllBindingFlags |
795 BindingFlags.NonPublic, name, null) == null) {
796 if ((lookup.Length == 1) && (lookup [0] is Type)) {
797 Type t = (Type) lookup [0];
799 Report.Error (305, loc,
800 "Using the generic type `{0}' " +
801 "requires {1} type arguments",
802 TypeManager.CSharpName (t),
803 TypeManager.GetNumberOfTypeArguments (t).ToString ());
808 MemberList ml = TypeManager.FindMembers (queried_type, MemberTypes.Constructor,
809 BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly, null, null);
810 if (name == ".ctor" && ml.Count == 0)
812 Report.Error (143, loc, "The type `{0}' has no constructors defined", TypeManager.CSharpName (queried_type));
816 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (lookup [0]));
820 /// Returns an expression that can be used to invoke operator true
821 /// on the expression if it exists.
823 static public Expression GetOperatorTrue (EmitContext ec, Expression e, Location loc)
825 return GetOperatorTrueOrFalse (ec, e, true, loc);
829 /// Returns an expression that can be used to invoke operator false
830 /// on the expression if it exists.
832 static public Expression GetOperatorFalse (EmitContext ec, Expression e, Location loc)
834 return GetOperatorTrueOrFalse (ec, e, false, loc);
837 static Expression GetOperatorTrueOrFalse (EmitContext ec, Expression e, bool is_true, Location loc)
840 Expression operator_group;
842 if (TypeManager.IsNullableType (e.Type))
843 return new Nullable.OperatorTrueOrFalse (e, is_true, loc).Resolve (ec);
845 operator_group = MethodLookup (ec, e.Type, is_true ? "op_True" : "op_False", loc);
846 if (operator_group == null)
849 ArrayList arguments = new ArrayList ();
850 arguments.Add (new Argument (e, Argument.AType.Expression));
851 method = Invocation.OverloadResolve (
852 ec, (MethodGroupExpr) operator_group, arguments, false, loc);
857 return new StaticCallExpr ((MethodInfo) method, arguments, loc);
861 /// Resolves the expression `e' into a boolean expression: either through
862 /// an implicit conversion, or through an `operator true' invocation
864 public static Expression ResolveBoolean (EmitContext ec, Expression e, Location loc)
870 if (e.Type == TypeManager.bool_type)
873 Expression converted = Convert.ImplicitConversion (ec, e, TypeManager.bool_type, Location.Null);
875 if (converted != null)
879 // If no implicit conversion to bool exists, try using `operator true'
881 converted = Expression.GetOperatorTrue (ec, e, loc);
882 if (converted == null){
883 e.Error_ValueCannotBeConverted (loc, TypeManager.bool_type, false);
889 public virtual string ExprClassName
893 case ExprClass.Invalid:
895 case ExprClass.Value:
897 case ExprClass.Variable:
899 case ExprClass.Namespace:
903 case ExprClass.MethodGroup:
904 return "method group";
905 case ExprClass.PropertyAccess:
906 return "property access";
907 case ExprClass.EventAccess:
908 return "event access";
909 case ExprClass.IndexerAccess:
910 return "indexer access";
911 case ExprClass.Nothing:
914 throw new Exception ("Should not happen");
919 /// Reports that we were expecting `expr' to be of class `expected'
921 public void Error_UnexpectedKind (DeclSpace ds, string expected, Location loc)
923 Error_UnexpectedKind (ds, expected, ExprClassName, loc);
926 public void Error_UnexpectedKind (DeclSpace ds, string expected, string was, Location loc)
928 string name = GetSignatureForError ();
930 name = ds.GetSignatureForError () + '.' + name;
932 Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
933 name, was, expected);
936 public void Error_UnexpectedKind (ResolveFlags flags, Location loc)
938 string [] valid = new string [4];
941 if ((flags & ResolveFlags.VariableOrValue) != 0) {
942 valid [count++] = "variable";
943 valid [count++] = "value";
946 if ((flags & ResolveFlags.Type) != 0)
947 valid [count++] = "type";
949 if ((flags & ResolveFlags.MethodGroup) != 0)
950 valid [count++] = "method group";
953 valid [count++] = "unknown";
955 StringBuilder sb = new StringBuilder (valid [0]);
956 for (int i = 1; i < count - 1; i++) {
958 sb.Append (valid [i]);
961 sb.Append ("' or `");
962 sb.Append (valid [count - 1]);
965 Report.Error (119, loc,
966 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
969 public static void UnsafeError (Location loc)
971 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
975 // Load the object from the pointer.
977 public static void LoadFromPtr (ILGenerator ig, Type t)
979 if (t == TypeManager.int32_type)
980 ig.Emit (OpCodes.Ldind_I4);
981 else if (t == TypeManager.uint32_type)
982 ig.Emit (OpCodes.Ldind_U4);
983 else if (t == TypeManager.short_type)
984 ig.Emit (OpCodes.Ldind_I2);
985 else if (t == TypeManager.ushort_type)
986 ig.Emit (OpCodes.Ldind_U2);
987 else if (t == TypeManager.char_type)
988 ig.Emit (OpCodes.Ldind_U2);
989 else if (t == TypeManager.byte_type)
990 ig.Emit (OpCodes.Ldind_U1);
991 else if (t == TypeManager.sbyte_type)
992 ig.Emit (OpCodes.Ldind_I1);
993 else if (t == TypeManager.uint64_type)
994 ig.Emit (OpCodes.Ldind_I8);
995 else if (t == TypeManager.int64_type)
996 ig.Emit (OpCodes.Ldind_I8);
997 else if (t == TypeManager.float_type)
998 ig.Emit (OpCodes.Ldind_R4);
999 else if (t == TypeManager.double_type)
1000 ig.Emit (OpCodes.Ldind_R8);
1001 else if (t == TypeManager.bool_type)
1002 ig.Emit (OpCodes.Ldind_I1);
1003 else if (t == TypeManager.intptr_type)
1004 ig.Emit (OpCodes.Ldind_I);
1005 else if (TypeManager.IsEnumType (t)) {
1006 if (t == TypeManager.enum_type)
1007 ig.Emit (OpCodes.Ldind_Ref);
1009 LoadFromPtr (ig, TypeManager.EnumToUnderlying (t));
1010 } else if (t.IsValueType || t.IsGenericParameter)
1011 ig.Emit (OpCodes.Ldobj, t);
1012 else if (t.IsPointer)
1013 ig.Emit (OpCodes.Ldind_I);
1015 ig.Emit (OpCodes.Ldind_Ref);
1019 // The stack contains the pointer and the value of type `type'
1021 public static void StoreFromPtr (ILGenerator ig, Type type)
1023 if (TypeManager.IsEnumType (type))
1024 type = TypeManager.EnumToUnderlying (type);
1025 if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
1026 ig.Emit (OpCodes.Stind_I4);
1027 else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
1028 ig.Emit (OpCodes.Stind_I8);
1029 else if (type == TypeManager.char_type || type == TypeManager.short_type ||
1030 type == TypeManager.ushort_type)
1031 ig.Emit (OpCodes.Stind_I2);
1032 else if (type == TypeManager.float_type)
1033 ig.Emit (OpCodes.Stind_R4);
1034 else if (type == TypeManager.double_type)
1035 ig.Emit (OpCodes.Stind_R8);
1036 else if (type == TypeManager.byte_type || type == TypeManager.sbyte_type ||
1037 type == TypeManager.bool_type)
1038 ig.Emit (OpCodes.Stind_I1);
1039 else if (type == TypeManager.intptr_type)
1040 ig.Emit (OpCodes.Stind_I);
1041 else if (type.IsValueType || type.IsGenericParameter)
1042 ig.Emit (OpCodes.Stobj, type);
1044 ig.Emit (OpCodes.Stind_Ref);
1048 // Returns the size of type `t' if known, otherwise, 0
1050 public static int GetTypeSize (Type t)
1052 t = TypeManager.TypeToCoreType (t);
1053 if (t == TypeManager.int32_type ||
1054 t == TypeManager.uint32_type ||
1055 t == TypeManager.float_type)
1057 else if (t == TypeManager.int64_type ||
1058 t == TypeManager.uint64_type ||
1059 t == TypeManager.double_type)
1061 else if (t == TypeManager.byte_type ||
1062 t == TypeManager.sbyte_type ||
1063 t == TypeManager.bool_type)
1065 else if (t == TypeManager.short_type ||
1066 t == TypeManager.char_type ||
1067 t == TypeManager.ushort_type)
1069 else if (t == TypeManager.decimal_type)
1075 public static void Error_NegativeArrayIndex (Location loc)
1077 Report.Error (248, loc, "Cannot create an array with a negative size");
1080 protected void Error_CannotCallAbstractBase (string name)
1082 Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
1086 // Converts `source' to an int, uint, long or ulong.
1088 public Expression ExpressionToArrayArgument (EmitContext ec, Expression source, Location loc)
1092 bool old_checked = ec.CheckState;
1093 ec.CheckState = true;
1095 target = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, loc);
1096 if (target == null){
1097 target = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, loc);
1098 if (target == null){
1099 target = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, loc);
1100 if (target == null){
1101 target = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, loc);
1103 source.Error_ValueCannotBeConverted (loc, TypeManager.int32_type, false);
1107 ec.CheckState = old_checked;
1110 // Only positive constants are allowed at compile time
1112 if (target is Constant){
1113 if (target is IntConstant){
1114 if (((IntConstant) target).Value < 0){
1115 Error_NegativeArrayIndex (loc);
1120 if (target is LongConstant){
1121 if (((LongConstant) target).Value < 0){
1122 Error_NegativeArrayIndex (loc);
1135 /// This is just a base class for expressions that can
1136 /// appear on statements (invocations, object creation,
1137 /// assignments, post/pre increment and decrement). The idea
1138 /// being that they would support an extra Emition interface that
1139 /// does not leave a result on the stack.
1141 public abstract class ExpressionStatement : Expression {
1143 public virtual ExpressionStatement ResolveStatement (EmitContext ec)
1145 Expression e = Resolve (ec);
1149 ExpressionStatement es = e as ExpressionStatement;
1151 Error (201, "Only assignment, call, increment, decrement and new object " +
1152 "expressions can be used as a statement");
1158 /// Requests the expression to be emitted in a `statement'
1159 /// context. This means that no new value is left on the
1160 /// stack after invoking this method (constrasted with
1161 /// Emit that will always leave a value on the stack).
1163 public abstract void EmitStatement (EmitContext ec);
1167 /// This kind of cast is used to encapsulate the child
1168 /// whose type is child.Type into an expression that is
1169 /// reported to return "return_type". This is used to encapsulate
1170 /// expressions which have compatible types, but need to be dealt
1171 /// at higher levels with.
1173 /// For example, a "byte" expression could be encapsulated in one
1174 /// of these as an "unsigned int". The type for the expression
1175 /// would be "unsigned int".
1178 public class EmptyCast : Expression {
1179 protected readonly Expression child;
1181 public EmptyCast (Expression child, Type return_type)
1183 eclass = child.eclass;
1184 loc = child.Location;
1189 public override Expression DoResolve (EmitContext ec)
1191 // This should never be invoked, we are born in fully
1192 // initialized state.
1197 public override void Emit (EmitContext ec)
1202 public override bool GetAttributableValue (Type valueType, out object value)
1204 return child.GetAttributableValue (valueType, out value);
1209 /// This is a numeric cast to a Decimal
1211 public class CastToDecimal : EmptyCast {
1213 MethodInfo conversion_operator;
1215 public CastToDecimal (Expression child)
1216 : this (child, false)
1220 public CastToDecimal (Expression child, bool find_explicit)
1221 : base (child, TypeManager.decimal_type)
1223 conversion_operator = GetConversionOperator (find_explicit);
1225 if (conversion_operator == null)
1226 throw new InternalErrorException ("Outer conversion routine is out of sync");
1229 // Returns the implicit operator that converts from
1230 // 'child.Type' to System.Decimal.
1231 MethodInfo GetConversionOperator (bool find_explicit)
1233 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1235 MemberInfo [] mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1236 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1238 foreach (MethodInfo oper in mi) {
1239 ParameterData pd = TypeManager.GetParameterData (oper);
1241 if (pd.ParameterType (0) == child.Type && oper.ReturnType == type)
1247 public override void Emit (EmitContext ec)
1249 ILGenerator ig = ec.ig;
1252 ig.Emit (OpCodes.Call, conversion_operator);
1257 /// This is an explicit numeric cast from a Decimal
1259 public class CastFromDecimal : EmptyCast
1261 static IDictionary operators;
1263 public CastFromDecimal (Expression child, Type return_type)
1264 : base (child, return_type)
1266 if (child.Type != TypeManager.decimal_type)
1267 throw new InternalErrorException (
1268 "The expected type is Decimal, instead it is " + child.Type.FullName);
1271 // Returns the explicit operator that converts from an
1272 // express of type System.Decimal to 'type'.
1273 public Expression Resolve ()
1275 if (operators == null) {
1276 MemberInfo[] all_oper = TypeManager.MemberLookup (TypeManager.decimal_type,
1277 TypeManager.decimal_type, TypeManager.decimal_type, MemberTypes.Method,
1278 BindingFlags.Static | BindingFlags.Public, "op_Explicit", null);
1280 operators = new System.Collections.Specialized.HybridDictionary ();
1281 foreach (MethodInfo oper in all_oper) {
1282 ParameterData pd = TypeManager.GetParameterData (oper);
1283 if (pd.ParameterType (0) == TypeManager.decimal_type)
1284 operators.Add (oper.ReturnType, oper);
1288 return operators.Contains (type) ? this : null;
1291 public override void Emit (EmitContext ec)
1293 ILGenerator ig = ec.ig;
1296 ig.Emit (OpCodes.Call, (MethodInfo)operators [type]);
1301 // We need to special case this since an empty cast of
1302 // a NullLiteral is still a Constant
1304 public class NullCast : Constant {
1305 public Constant child;
1307 public NullCast (Constant child, Type return_type):
1308 base (Location.Null)
1310 eclass = child.eclass;
1315 override public string AsString ()
1320 public override object GetValue ()
1325 public override Expression DoResolve (EmitContext ec)
1327 // This should never be invoked, we are born in fully
1328 // initialized state.
1333 public override void Emit (EmitContext ec)
1338 public override Constant Increment ()
1340 throw new NotSupportedException ();
1343 public override bool IsDefaultValue {
1349 public override bool IsNegative {
1355 public override Constant Reduce (bool inCheckedContext, Type target_type)
1357 if (type == target_type)
1358 return child.Reduce (inCheckedContext, target_type);
1367 /// This class is used to wrap literals which belong inside Enums
1369 public class EnumConstant : Constant {
1370 public Constant Child;
1372 public EnumConstant (Constant child, Type enum_type):
1373 base (child.Location)
1375 eclass = child.eclass;
1380 public override Expression DoResolve (EmitContext ec)
1382 // This should never be invoked, we are born in fully
1383 // initialized state.
1388 public override void Emit (EmitContext ec)
1393 public override bool GetAttributableValue (Type valueType, out object value)
1395 value = GetTypedValue ();
1399 public override string GetSignatureForError()
1401 return TypeManager.CSharpName (Type);
1404 public override object GetValue ()
1406 return Child.GetValue ();
1409 public override object GetTypedValue ()
1411 // FIXME: runtime is not ready to work with just emited enums
1412 if (!RootContext.StdLib) {
1413 return Child.GetValue ();
1416 return System.Enum.ToObject (type, Child.GetValue ());
1419 public override string AsString ()
1421 return Child.AsString ();
1424 public override DoubleConstant ConvertToDouble ()
1426 return Child.ConvertToDouble ();
1429 public override FloatConstant ConvertToFloat ()
1431 return Child.ConvertToFloat ();
1434 public override ULongConstant ConvertToULong ()
1436 return Child.ConvertToULong ();
1439 public override LongConstant ConvertToLong ()
1441 return Child.ConvertToLong ();
1444 public override UIntConstant ConvertToUInt ()
1446 return Child.ConvertToUInt ();
1449 public override IntConstant ConvertToInt ()
1451 return Child.ConvertToInt ();
1454 public override Constant Increment()
1456 return new EnumConstant (Child.Increment (), type);
1459 public override bool IsDefaultValue {
1461 return Child.IsDefaultValue;
1465 public override bool IsZeroInteger {
1466 get { return Child.IsZeroInteger; }
1469 public override bool IsNegative {
1471 return Child.IsNegative;
1475 public override Constant Reduce(bool inCheckedContext, Type target_type)
1477 if (Child.Type == target_type)
1480 return Child.Reduce (inCheckedContext, target_type);
1483 public override Constant ToType (Type type, Location loc)
1486 // This is workaround of mono bug. It can be removed when the latest corlib spreads enough
1487 if (TypeManager.IsEnumType (type.UnderlyingSystemType))
1490 if (type.UnderlyingSystemType != Child.Type)
1491 Child = Child.ToType (type.UnderlyingSystemType, loc);
1495 if (!Convert.ImplicitStandardConversionExists (this, type)){
1496 Error_ValueCannotBeConverted (loc, type, false);
1500 return Child.ToType (type, loc);
1506 /// This kind of cast is used to encapsulate Value Types in objects.
1508 /// The effect of it is to box the value type emitted by the previous
1511 public class BoxedCast : EmptyCast {
1513 public BoxedCast (Expression expr, Type target_type)
1514 : base (expr, target_type)
1516 eclass = ExprClass.Value;
1519 public override Expression DoResolve (EmitContext ec)
1521 // This should never be invoked, we are born in fully
1522 // initialized state.
1527 public override void Emit (EmitContext ec)
1531 ec.ig.Emit (OpCodes.Box, child.Type);
1535 public class UnboxCast : EmptyCast {
1536 public UnboxCast (Expression expr, Type return_type)
1537 : base (expr, return_type)
1541 public override Expression DoResolve (EmitContext ec)
1543 // This should never be invoked, we are born in fully
1544 // initialized state.
1549 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1551 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
1552 Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
1553 return base.DoResolveLValue (ec, right_side);
1556 public override void Emit (EmitContext ec)
1559 ILGenerator ig = ec.ig;
1562 if (t.IsGenericParameter)
1563 ig.Emit (OpCodes.Unbox_Any, t);
1565 ig.Emit (OpCodes.Unbox, t);
1567 LoadFromPtr (ig, t);
1573 /// This is used to perform explicit numeric conversions.
1575 /// Explicit numeric conversions might trigger exceptions in a checked
1576 /// context, so they should generate the conv.ovf opcodes instead of
1579 public class ConvCast : EmptyCast {
1580 public enum Mode : byte {
1581 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1583 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1584 U2_I1, U2_U1, U2_I2, U2_CH,
1585 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1586 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1587 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH,
1588 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH,
1589 CH_I1, CH_U1, CH_I2,
1590 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1591 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4
1596 public ConvCast (Expression child, Type return_type, Mode m)
1597 : base (child, return_type)
1602 public override Expression DoResolve (EmitContext ec)
1604 // This should never be invoked, we are born in fully
1605 // initialized state.
1610 public override string ToString ()
1612 return String.Format ("ConvCast ({0}, {1})", mode, child);
1615 public override void Emit (EmitContext ec)
1617 ILGenerator ig = ec.ig;
1623 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1624 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1625 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1626 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1627 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1629 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1630 case Mode.U1_CH: /* nothing */ break;
1632 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1633 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1634 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1635 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1636 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1637 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1639 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1640 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1641 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1642 case Mode.U2_CH: /* nothing */ break;
1644 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1645 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1646 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1647 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1648 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1649 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1650 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1652 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1653 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1654 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1655 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1656 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1657 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1659 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1660 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1661 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1662 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1663 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1664 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1665 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1666 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1668 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1669 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1670 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1671 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1672 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1673 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1674 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1675 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1677 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1678 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1679 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1681 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1682 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1683 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1684 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1685 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1686 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1687 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1688 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1689 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1691 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1692 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1693 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1694 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1695 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1696 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1697 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1698 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1699 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1700 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1704 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
1705 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
1706 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
1707 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
1708 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
1710 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
1711 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
1713 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
1714 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
1715 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
1716 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
1717 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
1718 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
1720 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
1721 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
1722 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
1723 case Mode.U2_CH: /* nothing */ break;
1725 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
1726 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
1727 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
1728 case Mode.I4_U4: /* nothing */ break;
1729 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
1730 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
1731 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
1733 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
1734 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
1735 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
1736 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
1737 case Mode.U4_I4: /* nothing */ break;
1738 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
1740 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
1741 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
1742 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
1743 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
1744 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
1745 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
1746 case Mode.I8_U8: /* nothing */ break;
1747 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
1749 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
1750 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
1751 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
1752 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
1753 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
1754 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
1755 case Mode.U8_I8: /* nothing */ break;
1756 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
1758 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
1759 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
1760 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
1762 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
1763 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
1764 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
1765 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
1766 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
1767 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
1768 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
1769 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
1770 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
1772 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
1773 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
1774 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
1775 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
1776 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
1777 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
1778 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
1779 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
1780 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
1781 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1787 public class OpcodeCast : EmptyCast {
1791 public OpcodeCast (Expression child, Type return_type, OpCode op)
1792 : base (child, return_type)
1796 second_valid = false;
1799 public OpcodeCast (Expression child, Type return_type, OpCode op, OpCode op2)
1800 : base (child, return_type)
1805 second_valid = true;
1808 public override Expression DoResolve (EmitContext ec)
1810 // This should never be invoked, we are born in fully
1811 // initialized state.
1816 public override void Emit (EmitContext ec)
1827 /// This kind of cast is used to encapsulate a child and cast it
1828 /// to the class requested
1830 public class ClassCast : EmptyCast {
1831 public ClassCast (Expression child, Type return_type)
1832 : base (child, return_type)
1837 public override Expression DoResolve (EmitContext ec)
1839 // This should never be invoked, we are born in fully
1840 // initialized state.
1845 public override void Emit (EmitContext ec)
1849 if (child.Type.IsGenericParameter)
1850 ec.ig.Emit (OpCodes.Box, child.Type);
1852 if (type.IsGenericParameter)
1853 ec.ig.Emit (OpCodes.Unbox_Any, type);
1855 ec.ig.Emit (OpCodes.Castclass, type);
1860 /// SimpleName expressions are formed of a single word and only happen at the beginning
1861 /// of a dotted-name.
1863 public class SimpleName : Expression {
1865 public readonly TypeArguments Arguments;
1868 public SimpleName (string name, Location l)
1874 public SimpleName (string name, TypeArguments args, Location l)
1881 public SimpleName (string name, TypeParameter[] type_params, Location l)
1886 Arguments = new TypeArguments (l);
1887 foreach (TypeParameter type_param in type_params)
1888 Arguments.Add (new TypeParameterExpr (type_param, l));
1891 public static string RemoveGenericArity (string name)
1894 StringBuilder sb = new StringBuilder ();
1895 while (start < name.Length) {
1896 int pos = name.IndexOf ('`', start);
1898 sb.Append (name.Substring (start));
1902 sb.Append (name.Substring (start, pos-start));
1905 while ((pos < name.Length) && Char.IsNumber (name [pos]))
1911 return sb.ToString ();
1914 public SimpleName GetMethodGroup ()
1916 return new SimpleName (RemoveGenericArity (Name), Arguments, loc);
1919 public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
1921 if (ec.IsFieldInitializer)
1922 Report.Error (236, l,
1923 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
1927 120, l, "`{0}': An object reference is required for the nonstatic field, method or property",
1931 public bool IdenticalNameAndTypeName (EmitContext ec, Expression resolved_to, Location loc)
1933 return resolved_to != null && resolved_to.Type != null &&
1934 resolved_to.Type.Name == Name &&
1935 (ec.DeclContainer.LookupType (Name, loc, /* ignore_cs0104 = */ true) != null);
1938 public override Expression DoResolve (EmitContext ec)
1940 return SimpleNameResolve (ec, null, false);
1943 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1945 return SimpleNameResolve (ec, right_side, false);
1949 public Expression DoResolve (EmitContext ec, bool intermediate)
1951 return SimpleNameResolve (ec, null, intermediate);
1954 private bool IsNestedChild (Type t, Type parent)
1959 while (parent != null) {
1960 parent = TypeManager.DropGenericTypeArguments (parent);
1961 if (TypeManager.IsNestedChildOf (t, parent))
1964 parent = parent.BaseType;
1970 FullNamedExpression ResolveNested (IResolveContext ec, Type t)
1972 if (!t.IsGenericTypeDefinition)
1975 DeclSpace ds = ec.DeclContainer;
1976 while (ds != null) {
1977 if (IsNestedChild (t, ds.TypeBuilder))
1986 Type[] gen_params = t.GetGenericArguments ();
1988 int arg_count = Arguments != null ? Arguments.Count : 0;
1990 for (; (ds != null) && ds.IsGeneric; ds = ds.Parent) {
1991 if (arg_count + ds.CountTypeParameters == gen_params.Length) {
1992 TypeArguments new_args = new TypeArguments (loc);
1993 foreach (TypeParameter param in ds.TypeParameters)
1994 new_args.Add (new TypeParameterExpr (param, loc));
1996 if (Arguments != null)
1997 new_args.Add (Arguments);
1999 return new ConstructedType (t, new_args, loc);
2006 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2008 FullNamedExpression fne = ec.DeclContainer.LookupGeneric (Name, loc);
2010 return fne.ResolveAsTypeStep (ec, silent);
2012 int errors = Report.Errors;
2013 fne = ec.DeclContainer.LookupType (Name, loc, /*ignore_cs0104=*/ false);
2016 if (fne.Type == null)
2019 FullNamedExpression nested = ResolveNested (ec, fne.Type);
2021 return nested.ResolveAsTypeStep (ec, false);
2023 if (Arguments != null) {
2024 ConstructedType ct = new ConstructedType (fne, Arguments, loc);
2025 return ct.ResolveAsTypeStep (ec, false);
2031 if (silent || errors != Report.Errors)
2034 MemberCore mc = ec.DeclContainer.GetDefinition (Name);
2036 Error_UnexpectedKind (ec.DeclContainer, "type", GetMemberType (mc), loc);
2040 string ns = ec.DeclContainer.NamespaceEntry.NS.Name;
2041 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2042 foreach (Assembly a in RootNamespace.Global.Assemblies) {
2043 Type type = a.GetType (fullname);
2045 Report.SymbolRelatedToPreviousError (type);
2046 Expression.ErrorIsInaccesible (loc, fullname);
2051 NamespaceEntry.Error_NamespaceNotFound (loc, Name);
2055 // TODO: I am still not convinced about this. If someone else will need it
2056 // implement this as virtual property in MemberCore hierarchy
2057 string GetMemberType (MemberCore mc)
2059 if (mc is PropertyBase)
2063 if (mc is FieldBase)
2065 if (mc is MethodCore)
2067 if (mc is EnumMember)
2073 Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2079 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2083 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2090 /// 7.5.2: Simple Names.
2092 /// Local Variables and Parameters are handled at
2093 /// parse time, so they never occur as SimpleNames.
2095 /// The `intermediate' flag is used by MemberAccess only
2096 /// and it is used to inform us that it is ok for us to
2097 /// avoid the static check, because MemberAccess might end
2098 /// up resolving the Name as a Type name and the access as
2099 /// a static type access.
2101 /// ie: Type Type; .... { Type.GetType (""); }
2103 /// Type is both an instance variable and a Type; Type.GetType
2104 /// is the static method not an instance method of type.
2106 Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2108 Expression e = null;
2111 // Stage 1: Performed by the parser (binding to locals or parameters).
2113 Block current_block = ec.CurrentBlock;
2114 if (current_block != null){
2115 LocalInfo vi = current_block.GetLocalInfo (Name);
2117 LocalVariableReference var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2118 if (right_side != null) {
2119 return var.ResolveLValue (ec, right_side, loc);
2121 ResolveFlags rf = ResolveFlags.VariableOrValue;
2123 rf |= ResolveFlags.DisableFlowAnalysis;
2124 return var.Resolve (ec, rf);
2128 ParameterReference pref = current_block.Toplevel.GetParameterReference (Name, loc);
2130 if (right_side != null)
2131 return pref.ResolveLValue (ec, right_side, loc);
2133 return pref.Resolve (ec);
2138 // Stage 2: Lookup members
2141 DeclSpace lookup_ds = ec.DeclContainer;
2142 Type almost_matched_type = null;
2143 ArrayList almost_matched = null;
2145 if (lookup_ds.TypeBuilder == null)
2148 e = MemberLookup (ec.ContainerType, lookup_ds.TypeBuilder, Name, loc);
2152 if (almost_matched == null && almostMatchedMembers.Count > 0) {
2153 almost_matched_type = lookup_ds.TypeBuilder;
2154 almost_matched = (ArrayList) almostMatchedMembers.Clone ();
2157 lookup_ds =lookup_ds.Parent;
2158 } while (lookup_ds != null);
2160 if (e == null && ec.ContainerType != null)
2161 e = MemberLookup (ec.ContainerType, ec.ContainerType, Name, loc);
2164 if (almost_matched == null && almostMatchedMembers.Count > 0) {
2165 almost_matched_type = ec.ContainerType;
2166 almost_matched = (ArrayList) almostMatchedMembers.Clone ();
2168 e = ResolveAsTypeStep (ec, true);
2172 if (almost_matched != null)
2173 almostMatchedMembers = almost_matched;
2174 if (almost_matched_type == null)
2175 almost_matched_type = ec.ContainerType;
2176 MemberLookupFailed (ec.ContainerType, null, almost_matched_type, ((SimpleName) this).Name, ec.DeclContainer.Name, true, loc);
2180 if (e is TypeExpr) {
2181 if (Arguments == null)
2184 ConstructedType ct = new ConstructedType (
2185 (FullNamedExpression) e, Arguments, loc);
2186 return ct.ResolveAsTypeStep (ec, false);
2189 if (e is MemberExpr) {
2190 MemberExpr me = (MemberExpr) e;
2193 if (me.IsInstance) {
2194 if (ec.IsStatic || ec.IsFieldInitializer) {
2196 // Note that an MemberExpr can be both IsInstance and IsStatic.
2197 // An unresolved MethodGroupExpr can contain both kinds of methods
2198 // and each predicate is true if the MethodGroupExpr contains
2199 // at least one of that kind of method.
2203 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2204 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2205 return EmptyExpression.Null;
2209 // Pass the buck to MemberAccess and Invocation.
2211 left = EmptyExpression.Null;
2213 left = ec.GetThis (loc);
2216 left = new TypeExpression (ec.ContainerType, loc);
2219 e = me.ResolveMemberAccess (ec, left, loc, null);
2223 me = e as MemberExpr;
2227 if (Arguments != null) {
2228 MethodGroupExpr mg = me as MethodGroupExpr;
2232 return mg.ResolveGeneric (ec, Arguments);
2236 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2237 me.InstanceExpression.Type != me.DeclaringType &&
2238 !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2239 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2240 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2241 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2245 return (right_side != null)
2246 ? me.DoResolveLValue (ec, right_side)
2247 : me.DoResolve (ec);
2253 public override void Emit (EmitContext ec)
2256 // If this is ever reached, then we failed to
2257 // find the name as a namespace
2260 Error (103, "The name `" + Name +
2261 "' does not exist in the class `" +
2262 ec.DeclContainer.Name + "'");
2265 public override string ToString ()
2270 public override string GetSignatureForError ()
2277 /// Represents a namespace or a type. The name of the class was inspired by
2278 /// section 10.8.1 (Fully Qualified Names).
2280 public abstract class FullNamedExpression : Expression {
2281 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2286 public abstract string FullName {
2292 /// Expression that evaluates to a type
2294 public abstract class TypeExpr : FullNamedExpression {
2295 override public FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2297 TypeExpr t = DoResolveAsTypeStep (ec);
2301 eclass = ExprClass.Type;
2305 override public Expression DoResolve (EmitContext ec)
2307 return ResolveAsTypeTerminal (ec, false);
2310 override public void Emit (EmitContext ec)
2312 throw new Exception ("Should never be called");
2315 public virtual bool CheckAccessLevel (DeclSpace ds)
2317 return ds.CheckAccessLevel (Type);
2320 public virtual bool AsAccessible (DeclSpace ds, int flags)
2322 return ds.AsAccessible (Type, flags);
2325 public virtual bool IsClass {
2326 get { return Type.IsClass; }
2329 public virtual bool IsValueType {
2330 get { return Type.IsValueType; }
2333 public virtual bool IsInterface {
2334 get { return Type.IsInterface; }
2337 public virtual bool IsSealed {
2338 get { return Type.IsSealed; }
2341 public virtual bool CanInheritFrom ()
2343 if (Type == TypeManager.enum_type ||
2344 (Type == TypeManager.value_type && RootContext.StdLib) ||
2345 Type == TypeManager.multicast_delegate_type ||
2346 Type == TypeManager.delegate_type ||
2347 Type == TypeManager.array_type)
2353 protected abstract TypeExpr DoResolveAsTypeStep (IResolveContext ec);
2355 public abstract string Name {
2359 public override bool Equals (object obj)
2361 TypeExpr tobj = obj as TypeExpr;
2365 return Type == tobj.Type;
2368 public override int GetHashCode ()
2370 return Type.GetHashCode ();
2373 public override string ToString ()
2380 /// Fully resolved Expression that already evaluated to a type
2382 public class TypeExpression : TypeExpr {
2383 public TypeExpression (Type t, Location l)
2386 eclass = ExprClass.Type;
2390 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2395 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2400 public override string Name {
2401 get { return Type.ToString (); }
2404 public override string FullName {
2405 get { return Type.FullName; }
2410 /// Used to create types from a fully qualified name. These are just used
2411 /// by the parser to setup the core types. A TypeLookupExpression is always
2412 /// classified as a type.
2414 public sealed class TypeLookupExpression : TypeExpr {
2415 readonly string name;
2417 public TypeLookupExpression (string name)
2420 eclass = ExprClass.Type;
2423 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2425 // It's null for corlib compilation only
2427 return DoResolveAsTypeStep (ec);
2432 static readonly char [] dot_array = { '.' };
2433 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2435 // If name is of the form `N.I', first lookup `N', then search a member `I' in it.
2437 string lookup_name = name;
2438 int pos = name.IndexOf ('.');
2440 rest = name.Substring (pos + 1);
2441 lookup_name = name.Substring (0, pos);
2444 FullNamedExpression resolved = RootNamespace.Global.Lookup (ec.DeclContainer, lookup_name, Location.Null);
2446 if (resolved != null && rest != null) {
2447 // Now handle the rest of the the name.
2448 string [] elements = rest.Split (dot_array);
2450 int count = elements.Length;
2452 while (i < count && resolved != null && resolved is Namespace) {
2453 Namespace ns = resolved as Namespace;
2454 element = elements [i++];
2455 lookup_name += "." + element;
2456 resolved = ns.Lookup (ec.DeclContainer, element, Location.Null);
2459 if (resolved != null && resolved is TypeExpr) {
2460 Type t = ((TypeExpr) resolved).Type;
2462 if (!ec.DeclContainer.CheckAccessLevel (t)) {
2464 lookup_name = t.FullName;
2471 t = TypeManager.GetNestedType (t, elements [i++]);
2476 if (resolved == null) {
2477 NamespaceEntry.Error_NamespaceNotFound (loc, lookup_name);
2481 if (!(resolved is TypeExpr)) {
2482 resolved.Error_UnexpectedKind (ec.DeclContainer, "type", loc);
2486 type = resolved.Type;
2490 public override string Name {
2491 get { return name; }
2494 public override string FullName {
2495 get { return name; }
2500 /// Represents an "unbound generic type", ie. typeof (Foo<>).
2503 public class UnboundTypeExpression : TypeExpr
2507 public UnboundTypeExpression (MemberName name, Location l)
2513 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2516 if (name.Left != null) {
2517 Expression lexpr = name.Left.GetTypeExpression ();
2518 expr = new MemberAccess (lexpr, name.Basename);
2520 expr = new SimpleName (name.Basename, loc);
2523 FullNamedExpression fne = expr.ResolveAsTypeStep (ec, false);
2528 return new TypeExpression (type, loc);
2531 public override string Name {
2532 get { return name.FullName; }
2535 public override string FullName {
2536 get { return name.FullName; }
2540 public class TypeAliasExpression : TypeExpr {
2541 FullNamedExpression alias;
2546 public TypeAliasExpression (FullNamedExpression alias, TypeArguments args, Location l)
2552 eclass = ExprClass.Type;
2554 name = alias.FullName + "<" + args.ToString () + ">";
2556 name = alias.FullName;
2559 public override string Name {
2560 get { return alias.FullName; }
2563 public override string FullName {
2564 get { return name; }
2567 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2569 texpr = alias.ResolveAsTypeTerminal (ec, false);
2573 Type type = texpr.Type;
2574 int num_args = TypeManager.GetNumberOfTypeArguments (type);
2577 if (num_args == 0) {
2578 Report.Error (308, loc,
2579 "The non-generic type `{0}' cannot " +
2580 "be used with type arguments.",
2581 TypeManager.CSharpName (type));
2585 ConstructedType ctype = new ConstructedType (type, args, loc);
2586 return ctype.ResolveAsTypeTerminal (ec, false);
2587 } else if (num_args > 0) {
2588 Report.Error (305, loc,
2589 "Using the generic type `{0}' " +
2590 "requires {1} type arguments",
2591 TypeManager.CSharpName (type), num_args.ToString ());
2598 public override bool CheckAccessLevel (DeclSpace ds)
2600 return texpr.CheckAccessLevel (ds);
2603 public override bool AsAccessible (DeclSpace ds, int flags)
2605 return texpr.AsAccessible (ds, flags);
2608 public override bool IsClass {
2609 get { return texpr.IsClass; }
2612 public override bool IsValueType {
2613 get { return texpr.IsValueType; }
2616 public override bool IsInterface {
2617 get { return texpr.IsInterface; }
2620 public override bool IsSealed {
2621 get { return texpr.IsSealed; }
2626 /// This class denotes an expression which evaluates to a member
2627 /// of a struct or a class.
2629 public abstract class MemberExpr : Expression
2632 /// The name of this member.
2634 public abstract string Name {
2639 /// Whether this is an instance member.
2641 public abstract bool IsInstance {
2646 /// Whether this is a static member.
2648 public abstract bool IsStatic {
2653 /// The type which declares this member.
2655 public abstract Type DeclaringType {
2660 /// The instance expression associated with this member, if it's a
2661 /// non-static member.
2663 public Expression InstanceExpression;
2665 public static void error176 (Location loc, string name)
2667 Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
2668 "with an instance reference, qualify it with a type name instead", name);
2671 // TODO: possible optimalization
2672 // Cache resolved constant result in FieldBuilder <-> expression map
2673 public virtual Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
2674 SimpleName original)
2678 // original == null || original.Resolve (...) ==> left
2681 if (left is TypeExpr) {
2683 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
2691 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
2694 error176 (loc, GetSignatureForError ());
2698 InstanceExpression = left;
2703 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
2708 if (InstanceExpression == EmptyExpression.Null) {
2709 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
2713 if (InstanceExpression.Type.IsValueType) {
2714 if (InstanceExpression is IMemoryLocation) {
2715 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
2717 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
2718 InstanceExpression.Emit (ec);
2720 t.AddressOf (ec, AddressOp.Store);
2723 InstanceExpression.Emit (ec);
2725 if (prepare_for_load)
2726 ec.ig.Emit (OpCodes.Dup);
2731 /// MethodGroup Expression.
2733 /// This is a fully resolved expression that evaluates to a type
2735 public class MethodGroupExpr : MemberExpr {
2736 public MethodBase [] Methods;
2737 bool has_type_arguments = false;
2738 bool identical_type_name = false;
2741 public MethodGroupExpr (MemberInfo [] mi, Location l)
2743 Methods = new MethodBase [mi.Length];
2744 mi.CopyTo (Methods, 0);
2745 eclass = ExprClass.MethodGroup;
2746 type = TypeManager.object_type;
2750 public MethodGroupExpr (ArrayList list, Location l)
2752 Methods = new MethodBase [list.Count];
2755 list.CopyTo (Methods, 0);
2757 foreach (MemberInfo m in list){
2758 if (!(m is MethodBase)){
2759 Console.WriteLine ("Name " + m.Name);
2760 Console.WriteLine ("Found a: " + m.GetType ().FullName);
2767 eclass = ExprClass.MethodGroup;
2768 type = TypeManager.object_type;
2771 public override Type DeclaringType {
2774 // We assume that the top-level type is in the end
2776 return Methods [Methods.Length - 1].DeclaringType;
2777 //return Methods [0].DeclaringType;
2781 public bool HasTypeArguments {
2783 return has_type_arguments;
2787 has_type_arguments = value;
2791 public bool IdenticalTypeName {
2793 return identical_type_name;
2797 identical_type_name = value;
2801 public bool IsBase {
2810 public override string GetSignatureForError ()
2812 return TypeManager.CSharpSignature (Methods [0]);
2815 public override string Name {
2817 return Methods [0].Name;
2821 public override bool IsInstance {
2823 foreach (MethodBase mb in Methods)
2831 public override bool IsStatic {
2833 foreach (MethodBase mb in Methods)
2841 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
2842 SimpleName original)
2844 if (!(left is TypeExpr) &&
2845 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
2846 IdenticalTypeName = true;
2848 return base.ResolveMemberAccess (ec, left, loc, original);
2851 override public Expression DoResolve (EmitContext ec)
2854 InstanceExpression = null;
2856 if (InstanceExpression != null) {
2857 InstanceExpression = InstanceExpression.DoResolve (ec);
2858 if (InstanceExpression == null)
2865 public void ReportUsageError ()
2867 Report.Error (654, loc, "Method `" + DeclaringType + "." +
2868 Name + "()' is referenced without parentheses");
2871 override public void Emit (EmitContext ec)
2873 ReportUsageError ();
2876 bool RemoveMethods (bool keep_static)
2878 ArrayList smethods = new ArrayList ();
2880 foreach (MethodBase mb in Methods){
2881 if (mb.IsStatic == keep_static)
2885 if (smethods.Count == 0)
2888 Methods = new MethodBase [smethods.Count];
2889 smethods.CopyTo (Methods, 0);
2895 /// Removes any instance methods from the MethodGroup, returns
2896 /// false if the resulting set is empty.
2898 public bool RemoveInstanceMethods ()
2900 return RemoveMethods (true);
2904 /// Removes any static methods from the MethodGroup, returns
2905 /// false if the resulting set is empty.
2907 public bool RemoveStaticMethods ()
2909 return RemoveMethods (false);
2912 public Expression ResolveGeneric (EmitContext ec, TypeArguments args)
2914 if (args.Resolve (ec) == false)
2917 Type[] atypes = args.Arguments;
2919 int first_count = 0;
2920 MethodInfo first = null;
2922 ArrayList list = new ArrayList ();
2923 foreach (MethodBase mb in Methods) {
2924 MethodInfo mi = mb as MethodInfo;
2925 if ((mi == null) || !mi.IsGenericMethod)
2928 Type[] gen_params = mi.GetGenericArguments ();
2930 if (first == null) {
2932 first_count = gen_params.Length;
2935 if (gen_params.Length != atypes.Length)
2938 list.Add (mi.MakeGenericMethod (atypes));
2941 if (list.Count > 0) {
2942 MethodGroupExpr new_mg = new MethodGroupExpr (list, Location);
2943 new_mg.InstanceExpression = InstanceExpression;
2944 new_mg.HasTypeArguments = true;
2945 new_mg.IsBase = IsBase;
2951 305, loc, "Using the generic method `{0}' " +
2952 "requires {1} type arguments", Name,
2953 first_count.ToString ());
2956 308, loc, "The non-generic method `{0}' " +
2957 "cannot be used with type arguments", Name);
2964 /// Fully resolved expression that evaluates to a Field
2966 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariable {
2967 public readonly FieldInfo FieldInfo;
2968 VariableInfo variable_info;
2970 LocalTemporary temp;
2972 bool in_initializer;
2974 public FieldExpr (FieldInfo fi, Location l, bool in_initializer):
2977 this.in_initializer = in_initializer;
2980 public FieldExpr (FieldInfo fi, Location l)
2983 eclass = ExprClass.Variable;
2984 type = TypeManager.TypeToCoreType (fi.FieldType);
2988 public override string Name {
2990 return FieldInfo.Name;
2994 public override bool IsInstance {
2996 return !FieldInfo.IsStatic;
3000 public override bool IsStatic {
3002 return FieldInfo.IsStatic;
3006 public override Type DeclaringType {
3008 return FieldInfo.DeclaringType;
3012 public override string GetSignatureForError ()
3014 return TypeManager.GetFullNameSignature (FieldInfo);
3017 public VariableInfo VariableInfo {
3019 return variable_info;
3023 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3024 SimpleName original)
3026 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
3028 Type t = fi.FieldType;
3030 if (fi.IsLiteral || (fi.IsInitOnly && t == TypeManager.decimal_type)) {
3031 IConstant ic = TypeManager.GetConstant (fi);
3034 ic = new ExternalConstant (fi);
3036 ic = ExternalConstant.CreateDecimal (fi);
3038 return base.ResolveMemberAccess (ec, left, loc, original);
3041 TypeManager.RegisterConstant (fi, ic);
3044 bool left_is_type = left is TypeExpr;
3045 if (!left_is_type && (original == null || !original.IdenticalNameAndTypeName (ec, left, loc))) {
3046 Report.SymbolRelatedToPreviousError (FieldInfo);
3047 error176 (loc, TypeManager.GetFullNameSignature (FieldInfo));
3051 if (ic.ResolveValue ()) {
3052 if (!ec.IsInObsoleteScope)
3053 ic.CheckObsoleteness (loc);
3059 if (t.IsPointer && !ec.InUnsafe) {
3064 return base.ResolveMemberAccess (ec, left, loc, original);
3067 override public Expression DoResolve (EmitContext ec)
3069 return DoResolve (ec, false, false);
3072 Expression DoResolve (EmitContext ec, bool lvalue_instance, bool out_access)
3074 if (!FieldInfo.IsStatic){
3075 if (InstanceExpression == null){
3077 // This can happen when referencing an instance field using
3078 // a fully qualified type expression: TypeName.InstanceField = xxx
3080 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3084 // Resolve the field's instance expression while flow analysis is turned
3085 // off: when accessing a field "a.b", we must check whether the field
3086 // "a.b" is initialized, not whether the whole struct "a" is initialized.
3088 if (lvalue_instance) {
3089 bool old_do_flow_analysis = ec.DoFlowAnalysis;
3090 ec.DoFlowAnalysis = false;
3091 Expression right_side =
3092 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
3093 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side, loc);
3094 ec.DoFlowAnalysis = old_do_flow_analysis;
3096 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
3097 InstanceExpression = InstanceExpression.Resolve (ec, rf);
3100 if (InstanceExpression == null)
3103 InstanceExpression.CheckMarshalByRefAccess ();
3106 if (!in_initializer && !ec.IsFieldInitializer) {
3107 ObsoleteAttribute oa;
3108 FieldBase f = TypeManager.GetField (FieldInfo);
3110 if (!ec.IsInObsoleteScope)
3111 f.CheckObsoleteness (loc);
3113 // To be sure that type is external because we do not register generated fields
3114 } else if (!(FieldInfo.DeclaringType is TypeBuilder)) {
3115 oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
3117 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
3121 AnonymousContainer am = ec.CurrentAnonymousMethod;
3123 if (!FieldInfo.IsStatic){
3124 if (!am.IsIterator && (ec.TypeContainer is Struct)){
3125 Report.Error (1673, loc,
3126 "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",
3130 if ((am.ContainerAnonymousMethod == null) && (InstanceExpression is This))
3131 ec.CaptureField (this);
3135 // If the instance expression is a local variable or parameter.
3136 IVariable var = InstanceExpression as IVariable;
3137 if ((var == null) || (var.VariableInfo == null))
3140 VariableInfo vi = var.VariableInfo;
3141 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
3144 variable_info = vi.GetSubStruct (FieldInfo.Name);
3148 static readonly int [] codes = {
3149 191, // instance, write access
3150 192, // instance, out access
3151 198, // static, write access
3152 199, // static, out access
3153 1648, // member of value instance, write access
3154 1649, // member of value instance, out access
3155 1650, // member of value static, write access
3156 1651 // member of value static, out access
3159 static readonly string [] msgs = {
3160 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
3161 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
3162 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
3163 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
3164 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
3165 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
3166 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
3167 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
3170 // The return value is always null. Returning a value simplifies calling code.
3171 Expression Report_AssignToReadonly (Expression right_side)
3174 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
3178 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
3180 Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
3185 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3187 IVariable var = InstanceExpression as IVariable;
3188 if ((var != null) && (var.VariableInfo != null))
3189 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
3191 bool lvalue_instance = !FieldInfo.IsStatic && FieldInfo.DeclaringType.IsValueType;
3192 bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
3194 Expression e = DoResolve (ec, lvalue_instance, out_access);
3199 FieldBase fb = TypeManager.GetField (FieldInfo);
3203 if (FieldInfo.IsInitOnly) {
3204 // InitOnly fields can only be assigned in constructors or initializers
3205 if (!ec.IsFieldInitializer && !ec.IsConstructor)
3206 return Report_AssignToReadonly (right_side);
3208 if (ec.IsConstructor) {
3209 Type ctype = ec.TypeContainer.CurrentType;
3211 ctype = ec.ContainerType;
3213 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
3214 if (!TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
3215 return Report_AssignToReadonly (right_side);
3216 // static InitOnly fields cannot be assigned-to in an instance constructor
3217 if (IsStatic && !ec.IsStatic)
3218 return Report_AssignToReadonly (right_side);
3219 // instance constructors can't modify InitOnly fields of other instances of the same type
3220 if (!IsStatic && !(InstanceExpression is This))
3221 return Report_AssignToReadonly (right_side);
3225 if (right_side == EmptyExpression.OutAccess &&
3226 !IsStatic && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
3227 Report.SymbolRelatedToPreviousError (DeclaringType);
3228 Report.Warning (197, 1, loc,
3229 "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",
3230 GetSignatureForError ());
3236 public override void CheckMarshalByRefAccess ()
3238 if (!IsStatic && Type.IsValueType && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
3239 Report.SymbolRelatedToPreviousError (DeclaringType);
3240 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",
3241 GetSignatureForError ());
3245 public bool VerifyFixed ()
3247 IVariable variable = InstanceExpression as IVariable;
3248 // A variable of the form V.I is fixed when V is a fixed variable of a struct type.
3249 // We defer the InstanceExpression check after the variable check to avoid a
3250 // separate null check on InstanceExpression.
3251 return variable != null && InstanceExpression.Type.IsValueType && variable.VerifyFixed ();
3254 public override int GetHashCode ()
3256 return FieldInfo.GetHashCode ();
3259 public override bool Equals (object obj)
3261 FieldExpr fe = obj as FieldExpr;
3265 if (FieldInfo != fe.FieldInfo)
3268 if (InstanceExpression == null || fe.InstanceExpression == null)
3271 return InstanceExpression.Equals (fe.InstanceExpression);
3274 public void Emit (EmitContext ec, bool leave_copy)
3276 ILGenerator ig = ec.ig;
3277 bool is_volatile = false;
3279 FieldBase f = TypeManager.GetField (FieldInfo);
3281 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
3284 f.SetMemberIsUsed ();
3287 if (FieldInfo.IsStatic){
3289 ig.Emit (OpCodes.Volatile);
3291 ig.Emit (OpCodes.Ldsfld, FieldInfo);
3294 EmitInstance (ec, false);
3297 ig.Emit (OpCodes.Volatile);
3299 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
3302 ig.Emit (OpCodes.Ldflda, FieldInfo);
3303 ig.Emit (OpCodes.Ldflda, ff.Element);
3306 ig.Emit (OpCodes.Ldfld, FieldInfo);
3311 ec.ig.Emit (OpCodes.Dup);
3312 if (!FieldInfo.IsStatic) {
3313 temp = new LocalTemporary (this.Type);
3319 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
3321 FieldAttributes fa = FieldInfo.Attributes;
3322 bool is_static = (fa & FieldAttributes.Static) != 0;
3323 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
3324 ILGenerator ig = ec.ig;
3325 prepared = prepare_for_load;
3327 if (is_readonly && !ec.IsConstructor){
3328 Report_AssignToReadonly (source);
3332 EmitInstance (ec, prepare_for_load);
3336 ec.ig.Emit (OpCodes.Dup);
3337 if (!FieldInfo.IsStatic) {
3338 temp = new LocalTemporary (this.Type);
3343 if (FieldInfo is FieldBuilder){
3344 FieldBase f = TypeManager.GetField (FieldInfo);
3346 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
3347 ig.Emit (OpCodes.Volatile);
3354 ig.Emit (OpCodes.Stsfld, FieldInfo);
3356 ig.Emit (OpCodes.Stfld, FieldInfo);
3362 public override void Emit (EmitContext ec)
3367 public void AddressOf (EmitContext ec, AddressOp mode)
3369 ILGenerator ig = ec.ig;
3371 if (FieldInfo is FieldBuilder){
3372 FieldBase f = TypeManager.GetField (FieldInfo);
3374 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
3375 Report.Warning (420, 1, loc, "`{0}': A volatile fields cannot be passed using a ref or out parameter",
3376 f.GetSignatureForError ());
3380 if ((mode & AddressOp.Store) != 0)
3382 if ((mode & AddressOp.Load) != 0)
3383 f.SetMemberIsUsed ();
3388 // Handle initonly fields specially: make a copy and then
3389 // get the address of the copy.
3392 if (FieldInfo.IsInitOnly){
3394 if (ec.IsConstructor){
3395 if (FieldInfo.IsStatic){
3407 local = ig.DeclareLocal (type);
3408 ig.Emit (OpCodes.Stloc, local);
3409 ig.Emit (OpCodes.Ldloca, local);
3414 if (FieldInfo.IsStatic){
3415 ig.Emit (OpCodes.Ldsflda, FieldInfo);
3418 EmitInstance (ec, false);
3419 ig.Emit (OpCodes.Ldflda, FieldInfo);
3425 // A FieldExpr whose address can not be taken
3427 public class FieldExprNoAddress : FieldExpr, IMemoryLocation {
3428 public FieldExprNoAddress (FieldInfo fi, Location loc) : base (fi, loc)
3432 public new void AddressOf (EmitContext ec, AddressOp mode)
3434 Report.Error (-215, "Report this: Taking the address of a remapped parameter not supported");
3439 /// Expression that evaluates to a Property. The Assign class
3440 /// might set the `Value' expression if we are in an assignment.
3442 /// This is not an LValue because we need to re-write the expression, we
3443 /// can not take data from the stack and store it.
3445 public class PropertyExpr : MemberExpr, IAssignMethod {
3446 public readonly PropertyInfo PropertyInfo;
3449 // This is set externally by the `BaseAccess' class
3452 MethodInfo getter, setter;
3457 LocalTemporary temp;
3460 internal static PtrHashtable AccessorTable = new PtrHashtable ();
3462 public PropertyExpr (Type containerType, PropertyInfo pi, Location l)
3465 eclass = ExprClass.PropertyAccess;
3469 type = TypeManager.TypeToCoreType (pi.PropertyType);
3471 ResolveAccessors (containerType);
3474 public override string Name {
3476 return PropertyInfo.Name;
3480 public override bool IsInstance {
3486 public override bool IsStatic {
3492 public override Type DeclaringType {
3494 return PropertyInfo.DeclaringType;
3498 public override string GetSignatureForError ()
3500 return TypeManager.GetFullNameSignature (PropertyInfo);
3503 void FindAccessors (Type invocation_type)
3505 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
3506 BindingFlags.Static | BindingFlags.Instance |
3507 BindingFlags.DeclaredOnly;
3509 Type current = PropertyInfo.DeclaringType;
3510 for (; current != null; current = current.BaseType) {
3511 MemberInfo[] group = TypeManager.MemberLookup (
3512 invocation_type, invocation_type, current,
3513 MemberTypes.Property, flags, PropertyInfo.Name, null);
3518 if (group.Length != 1)
3519 // Oooops, can this ever happen ?
3522 PropertyInfo pi = (PropertyInfo) group [0];
3525 getter = pi.GetGetMethod (true);
3528 setter = pi.GetSetMethod (true);
3530 MethodInfo accessor = getter != null ? getter : setter;
3532 if (!accessor.IsVirtual)
3538 // We also perform the permission checking here, as the PropertyInfo does not
3539 // hold the information for the accessibility of its setter/getter
3541 // TODO: can use TypeManager.GetProperty to boost performance
3542 void ResolveAccessors (Type containerType)
3544 FindAccessors (containerType);
3546 if (getter != null) {
3547 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
3548 IMethodData md = TypeManager.GetMethod (the_getter);
3550 md.SetMemberIsUsed ();
3552 AccessorTable [getter] = PropertyInfo;
3553 is_static = getter.IsStatic;
3556 if (setter != null) {
3557 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
3558 IMethodData md = TypeManager.GetMethod (the_setter);
3560 md.SetMemberIsUsed ();
3562 AccessorTable [setter] = PropertyInfo;
3563 is_static = setter.IsStatic;
3567 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
3570 InstanceExpression = null;
3574 if (InstanceExpression == null) {
3575 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3579 if (lvalue_instance)
3580 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
3582 InstanceExpression = InstanceExpression.DoResolve (ec);
3583 if (InstanceExpression == null)
3586 InstanceExpression.CheckMarshalByRefAccess ();
3588 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
3589 InstanceExpression.Type != ec.ContainerType &&
3590 ec.ContainerType.IsSubclassOf (PropertyInfo.DeclaringType) &&
3591 !InstanceExpression.Type.IsSubclassOf (ec.ContainerType)) {
3592 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
3599 void Error_PropertyNotFound (MethodInfo mi, bool getter)
3601 // TODO: correctly we should compare arguments but it will lead to bigger changes
3602 if (mi is MethodBuilder) {
3603 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
3607 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
3609 ParameterData iparams = TypeManager.GetParameterData (mi);
3610 sig.Append (getter ? "get_" : "set_");
3612 sig.Append (iparams.GetSignatureForError ());
3614 Report.SymbolRelatedToPreviousError (mi);
3615 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
3616 Name, sig.ToString ());
3619 override public Expression DoResolve (EmitContext ec)
3624 if (getter != null){
3625 if (TypeManager.GetParameterData (getter).Count != 0){
3626 Error_PropertyNotFound (getter, true);
3631 if (getter == null){
3633 // The following condition happens if the PropertyExpr was
3634 // created, but is invalid (ie, the property is inaccessible),
3635 // and we did not want to embed the knowledge about this in
3636 // the caller routine. This only avoids double error reporting.
3641 if (InstanceExpression != EmptyExpression.Null) {
3642 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
3643 TypeManager.GetFullNameSignature (PropertyInfo));
3648 bool must_do_cs1540_check = false;
3649 if (getter != null &&
3650 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
3651 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
3652 if (pm != null && pm.HasCustomAccessModifier) {
3653 Report.SymbolRelatedToPreviousError (pm);
3654 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
3655 TypeManager.CSharpSignature (getter));
3658 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
3662 if (!InstanceResolve (ec, false, must_do_cs1540_check))
3666 // Only base will allow this invocation to happen.
3668 if (IsBase && getter.IsAbstract) {
3669 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
3673 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
3683 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3685 if (right_side == EmptyExpression.OutAccess) {
3686 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
3687 GetSignatureForError ());
3691 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
3692 Report.Error (1612, loc, "Cannot modify the return value of `{0}' because it is not a variable",
3693 GetSignatureForError ());
3697 if (setter == null){
3699 // The following condition happens if the PropertyExpr was
3700 // created, but is invalid (ie, the property is inaccessible),
3701 // and we did not want to embed the knowledge about this in
3702 // the caller routine. This only avoids double error reporting.
3706 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
3707 GetSignatureForError ());
3711 if (TypeManager.GetParameterData (setter).Count != 1){
3712 Error_PropertyNotFound (setter, false);
3716 bool must_do_cs1540_check;
3717 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
3718 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
3719 if (pm != null && pm.HasCustomAccessModifier) {
3720 Report.SymbolRelatedToPreviousError (pm);
3721 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
3722 TypeManager.CSharpSignature (setter));
3725 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
3729 if (!InstanceResolve (ec, PropertyInfo.DeclaringType.IsValueType, must_do_cs1540_check))
3733 // Only base will allow this invocation to happen.
3735 if (IsBase && setter.IsAbstract){
3736 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
3743 public override void Emit (EmitContext ec)
3748 public void Emit (EmitContext ec, bool leave_copy)
3751 // Special case: length of single dimension array property is turned into ldlen
3753 if ((getter == TypeManager.system_int_array_get_length) ||
3754 (getter == TypeManager.int_array_get_length)){
3755 Type iet = InstanceExpression.Type;
3758 // System.Array.Length can be called, but the Type does not
3759 // support invoking GetArrayRank, so test for that case first
3761 if (iet != TypeManager.array_type && (iet.GetArrayRank () == 1)) {
3763 EmitInstance (ec, false);
3764 ec.ig.Emit (OpCodes.Ldlen);
3765 ec.ig.Emit (OpCodes.Conv_I4);
3770 Invocation.EmitCall (ec, IsBase, IsStatic, InstanceExpression, getter, null, loc, prepared, false);
3773 ec.ig.Emit (OpCodes.Dup);
3775 temp = new LocalTemporary (this.Type);
3782 // Implements the IAssignMethod interface for assignments
3784 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
3786 Expression my_source = source;
3788 prepared = prepare_for_load;
3793 ec.ig.Emit (OpCodes.Dup);
3795 temp = new LocalTemporary (this.Type);
3799 } else if (leave_copy) {
3802 temp = new LocalTemporary (this.Type);
3808 ArrayList args = new ArrayList (1);
3809 args.Add (new Argument (my_source, Argument.AType.Expression));
3811 Invocation.EmitCall (ec, IsBase, IsStatic, InstanceExpression, setter, args, loc, false, prepared);
3819 /// Fully resolved expression that evaluates to an Event
3821 public class EventExpr : MemberExpr {
3822 public readonly EventInfo EventInfo;
3825 MethodInfo add_accessor, remove_accessor;
3827 public EventExpr (EventInfo ei, Location loc)
3831 eclass = ExprClass.EventAccess;
3833 add_accessor = TypeManager.GetAddMethod (ei);
3834 remove_accessor = TypeManager.GetRemoveMethod (ei);
3836 if (add_accessor.IsStatic || remove_accessor.IsStatic)
3839 if (EventInfo is MyEventBuilder){
3840 MyEventBuilder eb = (MyEventBuilder) EventInfo;
3841 type = eb.EventType;
3844 type = EventInfo.EventHandlerType;
3847 public override string Name {
3849 return EventInfo.Name;
3853 public override bool IsInstance {
3859 public override bool IsStatic {
3865 public override Type DeclaringType {
3867 return EventInfo.DeclaringType;
3871 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3872 SimpleName original)
3875 // If the event is local to this class, we transform ourselves into a FieldExpr
3878 if (EventInfo.DeclaringType == ec.ContainerType ||
3879 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
3880 MemberInfo mi = TypeManager.GetPrivateFieldOfEvent (EventInfo);
3883 MemberExpr ml = (MemberExpr) ExprClassFromMemberInfo (ec.ContainerType, mi, loc);
3886 Report.Error (-200, loc, "Internal error!!");
3890 InstanceExpression = null;
3892 return ml.ResolveMemberAccess (ec, left, loc, original);
3896 return base.ResolveMemberAccess (ec, left, loc, original);
3900 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
3903 InstanceExpression = null;
3907 if (InstanceExpression == null) {
3908 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3912 InstanceExpression = InstanceExpression.DoResolve (ec);
3913 if (InstanceExpression == null)
3917 // This is using the same mechanism as the CS1540 check in PropertyExpr.
3918 // However, in the Event case, we reported a CS0122 instead.
3920 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
3921 InstanceExpression.Type != ec.ContainerType &&
3922 ec.ContainerType.IsSubclassOf (InstanceExpression.Type)) {
3923 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
3930 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
3932 return DoResolve (ec);
3935 public override Expression DoResolve (EmitContext ec)
3937 bool must_do_cs1540_check;
3938 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
3939 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
3940 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
3944 if (!InstanceResolve (ec, must_do_cs1540_check))
3950 public override void Emit (EmitContext ec)
3952 if (InstanceExpression is This)
3953 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of += or -=", GetSignatureForError ());
3955 Report.Error (70, loc, "The event `{0}' can only appear on the left hand side of += or -= "+
3956 "(except on the defining type)", Name);
3959 public override string GetSignatureForError ()
3961 return TypeManager.CSharpSignature (EventInfo);
3964 public void EmitAddOrRemove (EmitContext ec, Expression source)
3966 BinaryDelegate source_del = (BinaryDelegate) source;
3967 Expression handler = source_del.Right;
3969 Argument arg = new Argument (handler, Argument.AType.Expression);
3970 ArrayList args = new ArrayList ();
3974 if (source_del.IsAddition)
3975 Invocation.EmitCall (
3976 ec, false, IsStatic, InstanceExpression, add_accessor, args, loc);
3978 Invocation.EmitCall (
3979 ec, false, IsStatic, InstanceExpression, remove_accessor, args, loc);
3984 public class TemporaryVariable : Expression, IMemoryLocation
3988 public TemporaryVariable (Type type, Location loc)
3992 eclass = ExprClass.Value;
3995 public override Expression DoResolve (EmitContext ec)
4000 TypeExpr te = new TypeExpression (type, loc);
4001 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
4002 if (!li.Resolve (ec))
4005 AnonymousContainer am = ec.CurrentAnonymousMethod;
4006 if ((am != null) && am.IsIterator)
4007 ec.CaptureVariable (li);
4012 public override void Emit (EmitContext ec)
4014 ILGenerator ig = ec.ig;
4016 if (li.FieldBuilder != null) {
4017 ig.Emit (OpCodes.Ldarg_0);
4018 ig.Emit (OpCodes.Ldfld, li.FieldBuilder);
4020 ig.Emit (OpCodes.Ldloc, li.LocalBuilder);
4024 public void EmitLoadAddress (EmitContext ec)
4026 ILGenerator ig = ec.ig;
4028 if (li.FieldBuilder != null) {
4029 ig.Emit (OpCodes.Ldarg_0);
4030 ig.Emit (OpCodes.Ldflda, li.FieldBuilder);
4032 ig.Emit (OpCodes.Ldloca, li.LocalBuilder);
4036 public void Store (EmitContext ec, Expression right_side)
4038 if (li.FieldBuilder != null)
4039 ec.ig.Emit (OpCodes.Ldarg_0);
4041 right_side.Emit (ec);
4042 if (li.FieldBuilder != null) {
4043 ec.ig.Emit (OpCodes.Stfld, li.FieldBuilder);
4045 ec.ig.Emit (OpCodes.Stloc, li.LocalBuilder);
4049 public void EmitThis (EmitContext ec)
4051 if (li.FieldBuilder != null) {
4052 ec.ig.Emit (OpCodes.Ldarg_0);
4056 public void EmitStore (ILGenerator ig)
4058 if (li.FieldBuilder != null)
4059 ig.Emit (OpCodes.Stfld, li.FieldBuilder);
4061 ig.Emit (OpCodes.Stloc, li.LocalBuilder);
4064 public void AddressOf (EmitContext ec, AddressOp mode)
4066 EmitLoadAddress (ec);