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}'",
1926 if (name.LastIndexOf ('.') > 0)
1927 name = name.Substring (name.LastIndexOf ('.') + 1);
1930 120, l, "`{0}': An object reference is required for the nonstatic field, method or property",
1935 public bool IdenticalNameAndTypeName (EmitContext ec, Expression resolved_to, Location loc)
1937 return resolved_to != null && resolved_to.Type != null &&
1938 resolved_to.Type.Name == Name &&
1939 (ec.DeclContainer.LookupType (Name, loc, /* ignore_cs0104 = */ true) != null);
1942 public override Expression DoResolve (EmitContext ec)
1944 return SimpleNameResolve (ec, null, false);
1947 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1949 return SimpleNameResolve (ec, right_side, false);
1953 public Expression DoResolve (EmitContext ec, bool intermediate)
1955 return SimpleNameResolve (ec, null, intermediate);
1958 private bool IsNestedChild (Type t, Type parent)
1963 while (parent != null) {
1964 parent = TypeManager.DropGenericTypeArguments (parent);
1965 if (TypeManager.IsNestedChildOf (t, parent))
1968 parent = parent.BaseType;
1974 FullNamedExpression ResolveNested (IResolveContext ec, Type t)
1976 if (!t.IsGenericTypeDefinition)
1979 DeclSpace ds = ec.DeclContainer;
1980 while (ds != null) {
1981 if (IsNestedChild (t, ds.TypeBuilder))
1990 Type[] gen_params = t.GetGenericArguments ();
1992 int arg_count = Arguments != null ? Arguments.Count : 0;
1994 for (; (ds != null) && ds.IsGeneric; ds = ds.Parent) {
1995 if (arg_count + ds.CountTypeParameters == gen_params.Length) {
1996 TypeArguments new_args = new TypeArguments (loc);
1997 foreach (TypeParameter param in ds.TypeParameters)
1998 new_args.Add (new TypeParameterExpr (param, loc));
2000 if (Arguments != null)
2001 new_args.Add (Arguments);
2003 return new ConstructedType (t, new_args, loc);
2010 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2012 FullNamedExpression fne = ec.DeclContainer.LookupGeneric (Name, loc);
2014 return fne.ResolveAsTypeStep (ec, silent);
2016 int errors = Report.Errors;
2017 fne = ec.DeclContainer.LookupType (Name, loc, /*ignore_cs0104=*/ false);
2020 if (fne.Type == null)
2023 FullNamedExpression nested = ResolveNested (ec, fne.Type);
2025 return nested.ResolveAsTypeStep (ec, false);
2027 if (Arguments != null) {
2028 ConstructedType ct = new ConstructedType (fne, Arguments, loc);
2029 return ct.ResolveAsTypeStep (ec, false);
2035 if (silent || errors != Report.Errors)
2038 MemberCore mc = ec.DeclContainer.GetDefinition (Name);
2040 Error_UnexpectedKind (ec.DeclContainer, "type", GetMemberType (mc), loc);
2044 string ns = ec.DeclContainer.NamespaceEntry.NS.Name;
2045 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2046 foreach (Assembly a in RootNamespace.Global.Assemblies) {
2047 Type type = a.GetType (fullname);
2049 Report.SymbolRelatedToPreviousError (type);
2050 Expression.ErrorIsInaccesible (loc, fullname);
2055 NamespaceEntry.Error_NamespaceNotFound (loc, Name);
2059 // TODO: I am still not convinced about this. If someone else will need it
2060 // implement this as virtual property in MemberCore hierarchy
2061 string GetMemberType (MemberCore mc)
2063 if (mc is PropertyBase)
2067 if (mc is FieldBase)
2069 if (mc is MethodCore)
2071 if (mc is EnumMember)
2077 Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2083 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2087 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2094 /// 7.5.2: Simple Names.
2096 /// Local Variables and Parameters are handled at
2097 /// parse time, so they never occur as SimpleNames.
2099 /// The `intermediate' flag is used by MemberAccess only
2100 /// and it is used to inform us that it is ok for us to
2101 /// avoid the static check, because MemberAccess might end
2102 /// up resolving the Name as a Type name and the access as
2103 /// a static type access.
2105 /// ie: Type Type; .... { Type.GetType (""); }
2107 /// Type is both an instance variable and a Type; Type.GetType
2108 /// is the static method not an instance method of type.
2110 Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2112 Expression e = null;
2115 // Stage 1: Performed by the parser (binding to locals or parameters).
2117 Block current_block = ec.CurrentBlock;
2118 if (current_block != null){
2119 LocalInfo vi = current_block.GetLocalInfo (Name);
2121 LocalVariableReference var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2122 if (right_side != null) {
2123 return var.ResolveLValue (ec, right_side, loc);
2125 ResolveFlags rf = ResolveFlags.VariableOrValue;
2127 rf |= ResolveFlags.DisableFlowAnalysis;
2128 return var.Resolve (ec, rf);
2132 ParameterReference pref = current_block.Toplevel.GetParameterReference (Name, loc);
2134 if (right_side != null)
2135 return pref.ResolveLValue (ec, right_side, loc);
2137 return pref.Resolve (ec);
2142 // Stage 2: Lookup members
2145 DeclSpace lookup_ds = ec.DeclContainer;
2146 Type almost_matched_type = null;
2147 ArrayList almost_matched = null;
2149 if (lookup_ds.TypeBuilder == null)
2152 e = MemberLookup (ec.ContainerType, lookup_ds.TypeBuilder, Name, loc);
2156 if (almost_matched == null && almostMatchedMembers.Count > 0) {
2157 almost_matched_type = lookup_ds.TypeBuilder;
2158 almost_matched = (ArrayList) almostMatchedMembers.Clone ();
2161 lookup_ds =lookup_ds.Parent;
2162 } while (lookup_ds != null);
2164 if (e == null && ec.ContainerType != null)
2165 e = MemberLookup (ec.ContainerType, ec.ContainerType, Name, loc);
2168 if (almost_matched == null && almostMatchedMembers.Count > 0) {
2169 almost_matched_type = ec.ContainerType;
2170 almost_matched = (ArrayList) almostMatchedMembers.Clone ();
2172 e = ResolveAsTypeStep (ec, true);
2176 if (almost_matched != null)
2177 almostMatchedMembers = almost_matched;
2178 if (almost_matched_type == null)
2179 almost_matched_type = ec.ContainerType;
2180 MemberLookupFailed (ec.ContainerType, null, almost_matched_type, ((SimpleName) this).Name, ec.DeclContainer.Name, true, loc);
2187 if (e is MemberExpr) {
2188 MemberExpr me = (MemberExpr) e;
2191 if (me.IsInstance) {
2192 if (ec.IsStatic || ec.IsFieldInitializer) {
2194 // Note that an MemberExpr can be both IsInstance and IsStatic.
2195 // An unresolved MethodGroupExpr can contain both kinds of methods
2196 // and each predicate is true if the MethodGroupExpr contains
2197 // at least one of that kind of method.
2201 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2202 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2203 return EmptyExpression.Null;
2207 // Pass the buck to MemberAccess and Invocation.
2209 left = EmptyExpression.Null;
2211 left = ec.GetThis (loc);
2214 left = new TypeExpression (ec.ContainerType, loc);
2217 e = me.ResolveMemberAccess (ec, left, loc, null);
2221 me = e as MemberExpr;
2225 if (Arguments != null) {
2226 MethodGroupExpr mg = me as MethodGroupExpr;
2230 return mg.ResolveGeneric (ec, Arguments);
2234 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2235 me.InstanceExpression.Type != me.DeclaringType &&
2236 !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2237 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2238 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2239 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2243 return (right_side != null)
2244 ? me.DoResolveLValue (ec, right_side)
2245 : me.DoResolve (ec);
2251 public override void Emit (EmitContext ec)
2254 // If this is ever reached, then we failed to
2255 // find the name as a namespace
2258 Error (103, "The name `" + Name +
2259 "' does not exist in the class `" +
2260 ec.DeclContainer.Name + "'");
2263 public override string ToString ()
2268 public override string GetSignatureForError ()
2275 /// Represents a namespace or a type. The name of the class was inspired by
2276 /// section 10.8.1 (Fully Qualified Names).
2278 public abstract class FullNamedExpression : Expression {
2279 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2284 public abstract string FullName {
2290 /// Expression that evaluates to a type
2292 public abstract class TypeExpr : FullNamedExpression {
2293 override public FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2295 TypeExpr t = DoResolveAsTypeStep (ec);
2299 eclass = ExprClass.Type;
2303 override public Expression DoResolve (EmitContext ec)
2305 return ResolveAsTypeTerminal (ec, false);
2308 override public void Emit (EmitContext ec)
2310 throw new Exception ("Should never be called");
2313 public virtual bool CheckAccessLevel (DeclSpace ds)
2315 return ds.CheckAccessLevel (Type);
2318 public virtual bool AsAccessible (DeclSpace ds, int flags)
2320 return ds.AsAccessible (Type, flags);
2323 public virtual bool IsClass {
2324 get { return Type.IsClass; }
2327 public virtual bool IsValueType {
2328 get { return Type.IsValueType; }
2331 public virtual bool IsInterface {
2332 get { return Type.IsInterface; }
2335 public virtual bool IsSealed {
2336 get { return Type.IsSealed; }
2339 public virtual bool CanInheritFrom ()
2341 if (Type == TypeManager.enum_type ||
2342 (Type == TypeManager.value_type && RootContext.StdLib) ||
2343 Type == TypeManager.multicast_delegate_type ||
2344 Type == TypeManager.delegate_type ||
2345 Type == TypeManager.array_type)
2351 protected abstract TypeExpr DoResolveAsTypeStep (IResolveContext ec);
2353 public abstract string Name {
2357 public override bool Equals (object obj)
2359 TypeExpr tobj = obj as TypeExpr;
2363 return Type == tobj.Type;
2366 public override int GetHashCode ()
2368 return Type.GetHashCode ();
2371 public override string ToString ()
2378 /// Fully resolved Expression that already evaluated to a type
2380 public class TypeExpression : TypeExpr {
2381 public TypeExpression (Type t, Location l)
2384 eclass = ExprClass.Type;
2388 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2393 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2398 public override string Name {
2399 get { return Type.ToString (); }
2402 public override string FullName {
2403 get { return Type.FullName; }
2408 /// Used to create types from a fully qualified name. These are just used
2409 /// by the parser to setup the core types. A TypeLookupExpression is always
2410 /// classified as a type.
2412 public sealed class TypeLookupExpression : TypeExpr {
2413 readonly string name;
2415 public TypeLookupExpression (string name)
2418 eclass = ExprClass.Type;
2421 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2423 // It's null for corlib compilation only
2425 return DoResolveAsTypeStep (ec);
2430 static readonly char [] dot_array = { '.' };
2431 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2433 // If name is of the form `N.I', first lookup `N', then search a member `I' in it.
2435 string lookup_name = name;
2436 int pos = name.IndexOf ('.');
2438 rest = name.Substring (pos + 1);
2439 lookup_name = name.Substring (0, pos);
2442 FullNamedExpression resolved = RootNamespace.Global.Lookup (ec.DeclContainer, lookup_name, Location.Null);
2444 if (resolved != null && rest != null) {
2445 // Now handle the rest of the the name.
2446 string [] elements = rest.Split (dot_array);
2448 int count = elements.Length;
2450 while (i < count && resolved != null && resolved is Namespace) {
2451 Namespace ns = resolved as Namespace;
2452 element = elements [i++];
2453 lookup_name += "." + element;
2454 resolved = ns.Lookup (ec.DeclContainer, element, Location.Null);
2457 if (resolved != null && resolved is TypeExpr) {
2458 Type t = ((TypeExpr) resolved).Type;
2460 if (!ec.DeclContainer.CheckAccessLevel (t)) {
2462 lookup_name = t.FullName;
2469 t = TypeManager.GetNestedType (t, elements [i++]);
2474 if (resolved == null) {
2475 NamespaceEntry.Error_NamespaceNotFound (loc, lookup_name);
2479 if (!(resolved is TypeExpr)) {
2480 resolved.Error_UnexpectedKind (ec.DeclContainer, "type", loc);
2484 type = resolved.Type;
2488 public override string Name {
2489 get { return name; }
2492 public override string FullName {
2493 get { return name; }
2498 /// Represents an "unbound generic type", ie. typeof (Foo<>).
2501 public class UnboundTypeExpression : TypeExpr
2505 public UnboundTypeExpression (MemberName name, Location l)
2511 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2514 if (name.Left != null) {
2515 Expression lexpr = name.Left.GetTypeExpression ();
2516 expr = new MemberAccess (lexpr, name.Basename);
2518 expr = new SimpleName (name.Basename, loc);
2521 FullNamedExpression fne = expr.ResolveAsTypeStep (ec, false);
2526 return new TypeExpression (type, loc);
2529 public override string Name {
2530 get { return name.FullName; }
2533 public override string FullName {
2534 get { return name.FullName; }
2538 public class TypeAliasExpression : TypeExpr {
2539 FullNamedExpression alias;
2544 public TypeAliasExpression (FullNamedExpression alias, TypeArguments args, Location l)
2550 eclass = ExprClass.Type;
2552 name = alias.FullName + "<" + args.ToString () + ">";
2554 name = alias.FullName;
2557 public override string Name {
2558 get { return alias.FullName; }
2561 public override string FullName {
2562 get { return name; }
2565 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2567 texpr = alias.ResolveAsTypeTerminal (ec, false);
2571 Type type = texpr.Type;
2572 int num_args = TypeManager.GetNumberOfTypeArguments (type);
2575 if (num_args == 0) {
2576 Report.Error (308, loc,
2577 "The non-generic type `{0}' cannot " +
2578 "be used with type arguments.",
2579 TypeManager.CSharpName (type));
2583 ConstructedType ctype = new ConstructedType (type, args, loc);
2584 return ctype.ResolveAsTypeTerminal (ec, false);
2585 } else if (num_args > 0) {
2586 Report.Error (305, loc,
2587 "Using the generic type `{0}' " +
2588 "requires {1} type arguments",
2589 TypeManager.CSharpName (type), num_args.ToString ());
2596 public override bool CheckAccessLevel (DeclSpace ds)
2598 return texpr.CheckAccessLevel (ds);
2601 public override bool AsAccessible (DeclSpace ds, int flags)
2603 return texpr.AsAccessible (ds, flags);
2606 public override bool IsClass {
2607 get { return texpr.IsClass; }
2610 public override bool IsValueType {
2611 get { return texpr.IsValueType; }
2614 public override bool IsInterface {
2615 get { return texpr.IsInterface; }
2618 public override bool IsSealed {
2619 get { return texpr.IsSealed; }
2624 /// This class denotes an expression which evaluates to a member
2625 /// of a struct or a class.
2627 public abstract class MemberExpr : Expression
2630 /// The name of this member.
2632 public abstract string Name {
2637 /// Whether this is an instance member.
2639 public abstract bool IsInstance {
2644 /// Whether this is a static member.
2646 public abstract bool IsStatic {
2651 /// The type which declares this member.
2653 public abstract Type DeclaringType {
2658 /// The instance expression associated with this member, if it's a
2659 /// non-static member.
2661 public Expression InstanceExpression;
2663 public static void error176 (Location loc, string name)
2665 Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
2666 "with an instance reference, qualify it with a type name instead", name);
2669 // TODO: possible optimalization
2670 // Cache resolved constant result in FieldBuilder <-> expression map
2671 public virtual Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
2672 SimpleName original)
2676 // original == null || original.Resolve (...) ==> left
2679 if (left is TypeExpr) {
2681 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
2689 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
2692 error176 (loc, GetSignatureForError ());
2696 InstanceExpression = left;
2701 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
2706 if (InstanceExpression == EmptyExpression.Null) {
2707 SimpleName.Error_ObjectRefRequired (ec, loc, Name);
2711 if (InstanceExpression.Type.IsValueType) {
2712 if (InstanceExpression is IMemoryLocation) {
2713 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
2715 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
2716 InstanceExpression.Emit (ec);
2718 t.AddressOf (ec, AddressOp.Store);
2721 InstanceExpression.Emit (ec);
2723 if (prepare_for_load)
2724 ec.ig.Emit (OpCodes.Dup);
2729 /// MethodGroup Expression.
2731 /// This is a fully resolved expression that evaluates to a type
2733 public class MethodGroupExpr : MemberExpr {
2734 public MethodBase [] Methods;
2735 bool has_type_arguments = false;
2736 bool identical_type_name = false;
2739 public MethodGroupExpr (MemberInfo [] mi, Location l)
2741 Methods = new MethodBase [mi.Length];
2742 mi.CopyTo (Methods, 0);
2743 eclass = ExprClass.MethodGroup;
2744 type = TypeManager.object_type;
2748 public MethodGroupExpr (ArrayList list, Location l)
2750 Methods = new MethodBase [list.Count];
2753 list.CopyTo (Methods, 0);
2755 foreach (MemberInfo m in list){
2756 if (!(m is MethodBase)){
2757 Console.WriteLine ("Name " + m.Name);
2758 Console.WriteLine ("Found a: " + m.GetType ().FullName);
2765 eclass = ExprClass.MethodGroup;
2766 type = TypeManager.object_type;
2769 public override Type DeclaringType {
2772 // We assume that the top-level type is in the end
2774 return Methods [Methods.Length - 1].DeclaringType;
2775 //return Methods [0].DeclaringType;
2779 public bool HasTypeArguments {
2781 return has_type_arguments;
2785 has_type_arguments = value;
2789 public bool IdenticalTypeName {
2791 return identical_type_name;
2795 identical_type_name = value;
2799 public bool IsBase {
2808 public override string GetSignatureForError ()
2810 return TypeManager.CSharpSignature (Methods [0]);
2813 public override string Name {
2815 return Methods [0].Name;
2819 public override bool IsInstance {
2821 foreach (MethodBase mb in Methods)
2829 public override bool IsStatic {
2831 foreach (MethodBase mb in Methods)
2839 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
2840 SimpleName original)
2842 if (!(left is TypeExpr) &&
2843 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
2844 IdenticalTypeName = true;
2846 return base.ResolveMemberAccess (ec, left, loc, original);
2849 override public Expression DoResolve (EmitContext ec)
2852 InstanceExpression = null;
2854 if (InstanceExpression != null) {
2855 InstanceExpression = InstanceExpression.DoResolve (ec);
2856 if (InstanceExpression == null)
2863 public void ReportUsageError ()
2865 Report.Error (654, loc, "Method `" + DeclaringType + "." +
2866 Name + "()' is referenced without parentheses");
2869 override public void Emit (EmitContext ec)
2871 ReportUsageError ();
2874 bool RemoveMethods (bool keep_static)
2876 ArrayList smethods = new ArrayList ();
2878 foreach (MethodBase mb in Methods){
2879 if (mb.IsStatic == keep_static)
2883 if (smethods.Count == 0)
2886 Methods = new MethodBase [smethods.Count];
2887 smethods.CopyTo (Methods, 0);
2893 /// Removes any instance methods from the MethodGroup, returns
2894 /// false if the resulting set is empty.
2896 public bool RemoveInstanceMethods ()
2898 return RemoveMethods (true);
2902 /// Removes any static methods from the MethodGroup, returns
2903 /// false if the resulting set is empty.
2905 public bool RemoveStaticMethods ()
2907 return RemoveMethods (false);
2910 public Expression ResolveGeneric (EmitContext ec, TypeArguments args)
2912 if (args.Resolve (ec) == false)
2915 Type[] atypes = args.Arguments;
2917 int first_count = 0;
2918 MethodInfo first = null;
2920 ArrayList list = new ArrayList ();
2921 foreach (MethodBase mb in Methods) {
2922 MethodInfo mi = mb as MethodInfo;
2923 if ((mi == null) || !mi.IsGenericMethod)
2926 Type[] gen_params = mi.GetGenericArguments ();
2928 if (first == null) {
2930 first_count = gen_params.Length;
2933 if (gen_params.Length != atypes.Length)
2936 list.Add (mi.MakeGenericMethod (atypes));
2939 if (list.Count > 0) {
2940 MethodGroupExpr new_mg = new MethodGroupExpr (list, Location);
2941 new_mg.InstanceExpression = InstanceExpression;
2942 new_mg.HasTypeArguments = true;
2943 new_mg.IsBase = IsBase;
2949 305, loc, "Using the generic method `{0}' " +
2950 "requires {1} type arguments", Name,
2951 first_count.ToString ());
2954 308, loc, "The non-generic method `{0}' " +
2955 "cannot be used with type arguments", Name);
2962 /// Fully resolved expression that evaluates to a Field
2964 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariable {
2965 public readonly FieldInfo FieldInfo;
2966 VariableInfo variable_info;
2968 LocalTemporary temp;
2970 bool in_initializer;
2972 public FieldExpr (FieldInfo fi, Location l, bool in_initializer):
2975 this.in_initializer = in_initializer;
2978 public FieldExpr (FieldInfo fi, Location l)
2981 eclass = ExprClass.Variable;
2982 type = TypeManager.TypeToCoreType (fi.FieldType);
2986 public override string Name {
2988 return FieldInfo.Name;
2992 public override bool IsInstance {
2994 return !FieldInfo.IsStatic;
2998 public override bool IsStatic {
3000 return FieldInfo.IsStatic;
3004 public override Type DeclaringType {
3006 return FieldInfo.DeclaringType;
3010 public override string GetSignatureForError ()
3012 return TypeManager.GetFullNameSignature (FieldInfo);
3015 public VariableInfo VariableInfo {
3017 return variable_info;
3021 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3022 SimpleName original)
3024 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
3026 Type t = fi.FieldType;
3028 if (fi.IsLiteral || (fi.IsInitOnly && t == TypeManager.decimal_type)) {
3029 IConstant ic = TypeManager.GetConstant (fi);
3032 ic = new ExternalConstant (fi);
3034 ic = ExternalConstant.CreateDecimal (fi);
3036 return base.ResolveMemberAccess (ec, left, loc, original);
3039 TypeManager.RegisterConstant (fi, ic);
3042 bool left_is_type = left is TypeExpr;
3043 if (!left_is_type && (original == null || !original.IdenticalNameAndTypeName (ec, left, loc))) {
3044 Report.SymbolRelatedToPreviousError (FieldInfo);
3045 error176 (loc, TypeManager.GetFullNameSignature (FieldInfo));
3049 if (ic.ResolveValue ()) {
3050 if (!ec.IsInObsoleteScope)
3051 ic.CheckObsoleteness (loc);
3057 if (t.IsPointer && !ec.InUnsafe) {
3062 return base.ResolveMemberAccess (ec, left, loc, original);
3065 override public Expression DoResolve (EmitContext ec)
3067 return DoResolve (ec, false, false);
3070 Expression DoResolve (EmitContext ec, bool lvalue_instance, bool out_access)
3072 if (!FieldInfo.IsStatic){
3073 if (InstanceExpression == null){
3075 // This can happen when referencing an instance field using
3076 // a fully qualified type expression: TypeName.InstanceField = xxx
3078 SimpleName.Error_ObjectRefRequired (ec, loc, FieldInfo.Name);
3082 // Resolve the field's instance expression while flow analysis is turned
3083 // off: when accessing a field "a.b", we must check whether the field
3084 // "a.b" is initialized, not whether the whole struct "a" is initialized.
3086 if (lvalue_instance) {
3087 bool old_do_flow_analysis = ec.DoFlowAnalysis;
3088 ec.DoFlowAnalysis = false;
3089 Expression right_side =
3090 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
3091 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side, loc);
3092 ec.DoFlowAnalysis = old_do_flow_analysis;
3094 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
3095 InstanceExpression = InstanceExpression.Resolve (ec, rf);
3098 if (InstanceExpression == null)
3101 InstanceExpression.CheckMarshalByRefAccess ();
3104 if (!in_initializer && !ec.IsFieldInitializer) {
3105 ObsoleteAttribute oa;
3106 FieldBase f = TypeManager.GetField (FieldInfo);
3108 if (!ec.IsInObsoleteScope)
3109 f.CheckObsoleteness (loc);
3111 // To be sure that type is external because we do not register generated fields
3112 } else if (!(FieldInfo.DeclaringType is TypeBuilder)) {
3113 oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
3115 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
3119 AnonymousContainer am = ec.CurrentAnonymousMethod;
3121 if (!FieldInfo.IsStatic){
3122 if (!am.IsIterator && (ec.TypeContainer is Struct)){
3123 Report.Error (1673, loc,
3124 "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",
3128 if ((am.ContainerAnonymousMethod == null) && (InstanceExpression is This))
3129 ec.CaptureField (this);
3133 // If the instance expression is a local variable or parameter.
3134 IVariable var = InstanceExpression as IVariable;
3135 if ((var == null) || (var.VariableInfo == null))
3138 VariableInfo vi = var.VariableInfo;
3139 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
3142 variable_info = vi.GetSubStruct (FieldInfo.Name);
3146 static readonly int [] codes = {
3147 191, // instance, write access
3148 192, // instance, out access
3149 198, // static, write access
3150 199, // static, out access
3151 1648, // member of value instance, write access
3152 1649, // member of value instance, out access
3153 1650, // member of value static, write access
3154 1651 // member of value static, out access
3157 static readonly string [] msgs = {
3158 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
3159 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
3160 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
3161 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
3162 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
3163 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
3164 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
3165 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
3168 // The return value is always null. Returning a value simplifies calling code.
3169 Expression Report_AssignToReadonly (Expression right_side)
3172 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
3176 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
3178 Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
3183 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3185 IVariable var = InstanceExpression as IVariable;
3186 if ((var != null) && (var.VariableInfo != null))
3187 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
3189 bool lvalue_instance = !FieldInfo.IsStatic && FieldInfo.DeclaringType.IsValueType;
3190 bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
3192 Expression e = DoResolve (ec, lvalue_instance, out_access);
3197 FieldBase fb = TypeManager.GetField (FieldInfo);
3201 if (FieldInfo.IsInitOnly) {
3202 // InitOnly fields can only be assigned in constructors or initializers
3203 if (!ec.IsFieldInitializer && !ec.IsConstructor)
3204 return Report_AssignToReadonly (right_side);
3206 if (ec.IsConstructor) {
3207 Type ctype = ec.TypeContainer.CurrentType;
3209 ctype = ec.ContainerType;
3211 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
3212 if (!TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
3213 return Report_AssignToReadonly (right_side);
3214 // static InitOnly fields cannot be assigned-to in an instance constructor
3215 if (IsStatic && !ec.IsStatic)
3216 return Report_AssignToReadonly (right_side);
3217 // instance constructors can't modify InitOnly fields of other instances of the same type
3218 if (!IsStatic && !(InstanceExpression is This))
3219 return Report_AssignToReadonly (right_side);
3223 if (right_side == EmptyExpression.OutAccess &&
3224 !IsStatic && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
3225 Report.SymbolRelatedToPreviousError (DeclaringType);
3226 Report.Warning (197, 1, loc,
3227 "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",
3228 GetSignatureForError ());
3234 public override void CheckMarshalByRefAccess ()
3236 if (!IsStatic && Type.IsValueType && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
3237 Report.SymbolRelatedToPreviousError (DeclaringType);
3238 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",
3239 GetSignatureForError ());
3243 public bool VerifyFixed ()
3245 IVariable variable = InstanceExpression as IVariable;
3246 // A variable of the form V.I is fixed when V is a fixed variable of a struct type.
3247 // We defer the InstanceExpression check after the variable check to avoid a
3248 // separate null check on InstanceExpression.
3249 return variable != null && InstanceExpression.Type.IsValueType && variable.VerifyFixed ();
3252 public override int GetHashCode ()
3254 return FieldInfo.GetHashCode ();
3257 public override bool Equals (object obj)
3259 FieldExpr fe = obj as FieldExpr;
3263 if (FieldInfo != fe.FieldInfo)
3266 if (InstanceExpression == null || fe.InstanceExpression == null)
3269 return InstanceExpression.Equals (fe.InstanceExpression);
3272 public void Emit (EmitContext ec, bool leave_copy)
3274 ILGenerator ig = ec.ig;
3275 bool is_volatile = false;
3277 FieldBase f = TypeManager.GetField (FieldInfo);
3279 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
3282 f.SetMemberIsUsed ();
3285 if (FieldInfo.IsStatic){
3287 ig.Emit (OpCodes.Volatile);
3289 ig.Emit (OpCodes.Ldsfld, FieldInfo);
3292 EmitInstance (ec, false);
3295 ig.Emit (OpCodes.Volatile);
3297 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
3300 ig.Emit (OpCodes.Ldflda, FieldInfo);
3301 ig.Emit (OpCodes.Ldflda, ff.Element);
3304 ig.Emit (OpCodes.Ldfld, FieldInfo);
3309 ec.ig.Emit (OpCodes.Dup);
3310 if (!FieldInfo.IsStatic) {
3311 temp = new LocalTemporary (this.Type);
3317 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
3319 FieldAttributes fa = FieldInfo.Attributes;
3320 bool is_static = (fa & FieldAttributes.Static) != 0;
3321 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
3322 ILGenerator ig = ec.ig;
3323 prepared = prepare_for_load;
3325 if (is_readonly && !ec.IsConstructor){
3326 Report_AssignToReadonly (source);
3330 EmitInstance (ec, prepare_for_load);
3334 ec.ig.Emit (OpCodes.Dup);
3335 if (!FieldInfo.IsStatic) {
3336 temp = new LocalTemporary (this.Type);
3341 if (FieldInfo is FieldBuilder){
3342 FieldBase f = TypeManager.GetField (FieldInfo);
3344 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
3345 ig.Emit (OpCodes.Volatile);
3352 ig.Emit (OpCodes.Stsfld, FieldInfo);
3354 ig.Emit (OpCodes.Stfld, FieldInfo);
3360 public override void Emit (EmitContext ec)
3365 public void AddressOf (EmitContext ec, AddressOp mode)
3367 ILGenerator ig = ec.ig;
3369 if (FieldInfo is FieldBuilder){
3370 FieldBase f = TypeManager.GetField (FieldInfo);
3372 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
3373 Report.Warning (420, 1, loc, "`{0}': A volatile fields cannot be passed using a ref or out parameter",
3374 f.GetSignatureForError ());
3378 if ((mode & AddressOp.Store) != 0)
3380 if ((mode & AddressOp.Load) != 0)
3381 f.SetMemberIsUsed ();
3386 // Handle initonly fields specially: make a copy and then
3387 // get the address of the copy.
3390 if (FieldInfo.IsInitOnly){
3392 if (ec.IsConstructor){
3393 if (FieldInfo.IsStatic){
3405 local = ig.DeclareLocal (type);
3406 ig.Emit (OpCodes.Stloc, local);
3407 ig.Emit (OpCodes.Ldloca, local);
3412 if (FieldInfo.IsStatic){
3413 ig.Emit (OpCodes.Ldsflda, FieldInfo);
3416 EmitInstance (ec, false);
3417 ig.Emit (OpCodes.Ldflda, FieldInfo);
3423 // A FieldExpr whose address can not be taken
3425 public class FieldExprNoAddress : FieldExpr, IMemoryLocation {
3426 public FieldExprNoAddress (FieldInfo fi, Location loc) : base (fi, loc)
3430 public new void AddressOf (EmitContext ec, AddressOp mode)
3432 Report.Error (-215, "Report this: Taking the address of a remapped parameter not supported");
3437 /// Expression that evaluates to a Property. The Assign class
3438 /// might set the `Value' expression if we are in an assignment.
3440 /// This is not an LValue because we need to re-write the expression, we
3441 /// can not take data from the stack and store it.
3443 public class PropertyExpr : MemberExpr, IAssignMethod {
3444 public readonly PropertyInfo PropertyInfo;
3447 // This is set externally by the `BaseAccess' class
3450 MethodInfo getter, setter;
3455 LocalTemporary temp;
3458 internal static PtrHashtable AccessorTable = new PtrHashtable ();
3460 public PropertyExpr (Type containerType, PropertyInfo pi, Location l)
3463 eclass = ExprClass.PropertyAccess;
3467 type = TypeManager.TypeToCoreType (pi.PropertyType);
3469 ResolveAccessors (containerType);
3472 public override string Name {
3474 return PropertyInfo.Name;
3478 public override bool IsInstance {
3484 public override bool IsStatic {
3490 public override Type DeclaringType {
3492 return PropertyInfo.DeclaringType;
3496 public override string GetSignatureForError ()
3498 return TypeManager.GetFullNameSignature (PropertyInfo);
3501 void FindAccessors (Type invocation_type)
3503 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
3504 BindingFlags.Static | BindingFlags.Instance |
3505 BindingFlags.DeclaredOnly;
3507 Type current = PropertyInfo.DeclaringType;
3508 for (; current != null; current = current.BaseType) {
3509 MemberInfo[] group = TypeManager.MemberLookup (
3510 invocation_type, invocation_type, current,
3511 MemberTypes.Property, flags, PropertyInfo.Name, null);
3516 if (group.Length != 1)
3517 // Oooops, can this ever happen ?
3520 PropertyInfo pi = (PropertyInfo) group [0];
3523 getter = pi.GetGetMethod (true);
3526 setter = pi.GetSetMethod (true);
3528 MethodInfo accessor = getter != null ? getter : setter;
3530 if (!accessor.IsVirtual)
3536 // We also perform the permission checking here, as the PropertyInfo does not
3537 // hold the information for the accessibility of its setter/getter
3539 // TODO: can use TypeManager.GetProperty to boost performance
3540 void ResolveAccessors (Type containerType)
3542 FindAccessors (containerType);
3544 if (getter != null) {
3545 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
3546 IMethodData md = TypeManager.GetMethod (the_getter);
3548 md.SetMemberIsUsed ();
3550 AccessorTable [getter] = PropertyInfo;
3551 is_static = getter.IsStatic;
3554 if (setter != null) {
3555 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
3556 IMethodData md = TypeManager.GetMethod (the_setter);
3558 md.SetMemberIsUsed ();
3560 AccessorTable [setter] = PropertyInfo;
3561 is_static = setter.IsStatic;
3565 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
3568 InstanceExpression = null;
3572 if (InstanceExpression == null) {
3573 SimpleName.Error_ObjectRefRequired (ec, loc, PropertyInfo.Name);
3577 if (lvalue_instance)
3578 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
3580 InstanceExpression = InstanceExpression.DoResolve (ec);
3581 if (InstanceExpression == null)
3584 InstanceExpression.CheckMarshalByRefAccess ();
3586 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
3587 InstanceExpression.Type != ec.ContainerType &&
3588 ec.ContainerType.IsSubclassOf (PropertyInfo.DeclaringType) &&
3589 !InstanceExpression.Type.IsSubclassOf (ec.ContainerType)) {
3590 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
3597 void Error_PropertyNotFound (MethodInfo mi, bool getter)
3599 // TODO: correctly we should compare arguments but it will lead to bigger changes
3600 if (mi is MethodBuilder) {
3601 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
3605 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
3607 ParameterData iparams = TypeManager.GetParameterData (mi);
3608 sig.Append (getter ? "get_" : "set_");
3610 sig.Append (iparams.GetSignatureForError ());
3612 Report.SymbolRelatedToPreviousError (mi);
3613 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
3614 Name, sig.ToString ());
3617 override public Expression DoResolve (EmitContext ec)
3622 if (getter != null){
3623 if (TypeManager.GetParameterData (getter).Count != 0){
3624 Error_PropertyNotFound (getter, true);
3629 if (getter == null){
3631 // The following condition happens if the PropertyExpr was
3632 // created, but is invalid (ie, the property is inaccessible),
3633 // and we did not want to embed the knowledge about this in
3634 // the caller routine. This only avoids double error reporting.
3639 if (InstanceExpression != EmptyExpression.Null) {
3640 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
3641 TypeManager.GetFullNameSignature (PropertyInfo));
3646 bool must_do_cs1540_check = false;
3647 if (getter != null &&
3648 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
3649 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
3650 if (pm != null && pm.HasCustomAccessModifier) {
3651 Report.SymbolRelatedToPreviousError (pm);
3652 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
3653 TypeManager.CSharpSignature (getter));
3656 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
3660 if (!InstanceResolve (ec, false, must_do_cs1540_check))
3664 // Only base will allow this invocation to happen.
3666 if (IsBase && getter.IsAbstract) {
3667 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
3671 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
3681 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3683 if (right_side == EmptyExpression.OutAccess) {
3684 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
3685 GetSignatureForError ());
3689 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
3690 Report.Error (1612, loc, "Cannot modify the return value of `{0}' because it is not a variable",
3691 GetSignatureForError ());
3695 if (setter == null){
3697 // The following condition happens if the PropertyExpr was
3698 // created, but is invalid (ie, the property is inaccessible),
3699 // and we did not want to embed the knowledge about this in
3700 // the caller routine. This only avoids double error reporting.
3704 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
3705 GetSignatureForError ());
3709 if (TypeManager.GetParameterData (setter).Count != 1){
3710 Error_PropertyNotFound (setter, false);
3714 bool must_do_cs1540_check;
3715 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
3716 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
3717 if (pm != null && pm.HasCustomAccessModifier) {
3718 Report.SymbolRelatedToPreviousError (pm);
3719 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
3720 TypeManager.CSharpSignature (setter));
3723 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
3727 if (!InstanceResolve (ec, PropertyInfo.DeclaringType.IsValueType, must_do_cs1540_check))
3731 // Only base will allow this invocation to happen.
3733 if (IsBase && setter.IsAbstract){
3734 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
3741 public override void Emit (EmitContext ec)
3746 public void Emit (EmitContext ec, bool leave_copy)
3749 // Special case: length of single dimension array property is turned into ldlen
3751 if ((getter == TypeManager.system_int_array_get_length) ||
3752 (getter == TypeManager.int_array_get_length)){
3753 Type iet = InstanceExpression.Type;
3756 // System.Array.Length can be called, but the Type does not
3757 // support invoking GetArrayRank, so test for that case first
3759 if (iet != TypeManager.array_type && (iet.GetArrayRank () == 1)) {
3761 EmitInstance (ec, false);
3762 ec.ig.Emit (OpCodes.Ldlen);
3763 ec.ig.Emit (OpCodes.Conv_I4);
3768 Invocation.EmitCall (ec, IsBase, IsStatic, InstanceExpression, getter, null, loc, prepared, false);
3771 ec.ig.Emit (OpCodes.Dup);
3773 temp = new LocalTemporary (this.Type);
3780 // Implements the IAssignMethod interface for assignments
3782 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
3784 Expression my_source = source;
3786 prepared = prepare_for_load;
3791 ec.ig.Emit (OpCodes.Dup);
3793 temp = new LocalTemporary (this.Type);
3797 } else if (leave_copy) {
3800 temp = new LocalTemporary (this.Type);
3806 ArrayList args = new ArrayList (1);
3807 args.Add (new Argument (my_source, Argument.AType.Expression));
3809 Invocation.EmitCall (ec, IsBase, IsStatic, InstanceExpression, setter, args, loc, false, prepared);
3817 /// Fully resolved expression that evaluates to an Event
3819 public class EventExpr : MemberExpr {
3820 public readonly EventInfo EventInfo;
3823 MethodInfo add_accessor, remove_accessor;
3825 public EventExpr (EventInfo ei, Location loc)
3829 eclass = ExprClass.EventAccess;
3831 add_accessor = TypeManager.GetAddMethod (ei);
3832 remove_accessor = TypeManager.GetRemoveMethod (ei);
3834 if (add_accessor.IsStatic || remove_accessor.IsStatic)
3837 if (EventInfo is MyEventBuilder){
3838 MyEventBuilder eb = (MyEventBuilder) EventInfo;
3839 type = eb.EventType;
3842 type = EventInfo.EventHandlerType;
3845 public override string Name {
3847 return EventInfo.Name;
3851 public override bool IsInstance {
3857 public override bool IsStatic {
3863 public override Type DeclaringType {
3865 return EventInfo.DeclaringType;
3869 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3870 SimpleName original)
3873 // If the event is local to this class, we transform ourselves into a FieldExpr
3876 if (EventInfo.DeclaringType == ec.ContainerType ||
3877 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
3878 MemberInfo mi = TypeManager.GetPrivateFieldOfEvent (EventInfo);
3881 MemberExpr ml = (MemberExpr) ExprClassFromMemberInfo (ec.ContainerType, mi, loc);
3884 Report.Error (-200, loc, "Internal error!!");
3888 InstanceExpression = null;
3890 return ml.ResolveMemberAccess (ec, left, loc, original);
3894 return base.ResolveMemberAccess (ec, left, loc, original);
3898 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
3901 InstanceExpression = null;
3905 if (InstanceExpression == null) {
3906 SimpleName.Error_ObjectRefRequired (ec, loc, EventInfo.Name);
3910 InstanceExpression = InstanceExpression.DoResolve (ec);
3911 if (InstanceExpression == null)
3915 // This is using the same mechanism as the CS1540 check in PropertyExpr.
3916 // However, in the Event case, we reported a CS0122 instead.
3918 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
3919 InstanceExpression.Type != ec.ContainerType &&
3920 ec.ContainerType.IsSubclassOf (InstanceExpression.Type)) {
3921 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
3928 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
3930 return DoResolve (ec);
3933 public override Expression DoResolve (EmitContext ec)
3935 bool must_do_cs1540_check;
3936 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
3937 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
3938 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
3942 if (!InstanceResolve (ec, must_do_cs1540_check))
3948 public override void Emit (EmitContext ec)
3950 if (InstanceExpression is This)
3951 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of += or -=", GetSignatureForError ());
3953 Report.Error (70, loc, "The event `{0}' can only appear on the left hand side of += or -= "+
3954 "(except on the defining type)", Name);
3957 public override string GetSignatureForError ()
3959 return TypeManager.CSharpSignature (EventInfo);
3962 public void EmitAddOrRemove (EmitContext ec, Expression source)
3964 BinaryDelegate source_del = (BinaryDelegate) source;
3965 Expression handler = source_del.Right;
3967 Argument arg = new Argument (handler, Argument.AType.Expression);
3968 ArrayList args = new ArrayList ();
3972 if (source_del.IsAddition)
3973 Invocation.EmitCall (
3974 ec, false, IsStatic, InstanceExpression, add_accessor, args, loc);
3976 Invocation.EmitCall (
3977 ec, false, IsStatic, InstanceExpression, remove_accessor, args, loc);
3982 public class TemporaryVariable : Expression, IMemoryLocation
3986 public TemporaryVariable (Type type, Location loc)
3990 eclass = ExprClass.Value;
3993 public override Expression DoResolve (EmitContext ec)
3998 TypeExpr te = new TypeExpression (type, loc);
3999 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
4000 if (!li.Resolve (ec))
4003 AnonymousContainer am = ec.CurrentAnonymousMethod;
4004 if ((am != null) && am.IsIterator)
4005 ec.CaptureVariable (li);
4010 public override void Emit (EmitContext ec)
4012 ILGenerator ig = ec.ig;
4014 if (li.FieldBuilder != null) {
4015 ig.Emit (OpCodes.Ldarg_0);
4016 ig.Emit (OpCodes.Ldfld, li.FieldBuilder);
4018 ig.Emit (OpCodes.Ldloc, li.LocalBuilder);
4022 public void EmitLoadAddress (EmitContext ec)
4024 ILGenerator ig = ec.ig;
4026 if (li.FieldBuilder != null) {
4027 ig.Emit (OpCodes.Ldarg_0);
4028 ig.Emit (OpCodes.Ldflda, li.FieldBuilder);
4030 ig.Emit (OpCodes.Ldloca, li.LocalBuilder);
4034 public void Store (EmitContext ec, Expression right_side)
4036 if (li.FieldBuilder != null)
4037 ec.ig.Emit (OpCodes.Ldarg_0);
4039 right_side.Emit (ec);
4040 if (li.FieldBuilder != null) {
4041 ec.ig.Emit (OpCodes.Stfld, li.FieldBuilder);
4043 ec.ig.Emit (OpCodes.Stloc, li.LocalBuilder);
4047 public void EmitThis (EmitContext ec)
4049 if (li.FieldBuilder != null) {
4050 ec.ig.Emit (OpCodes.Ldarg_0);
4054 public void EmitStore (ILGenerator ig)
4056 if (li.FieldBuilder != null)
4057 ig.Emit (OpCodes.Stfld, li.FieldBuilder);
4059 ig.Emit (OpCodes.Stloc, li.LocalBuilder);
4062 public void AddressOf (EmitContext ec, AddressOp mode)
4064 EmitLoadAddress (ec);