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, 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 Const.Error_ExpressionMustBeConstant (loc, mc.GetSignatureForError ());
450 /// Resolves an expression for LValue assignment
454 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
455 /// checking and assertion checking on what we expect from Resolve
457 public Expression ResolveLValue (EmitContext ec, Expression right_side, Location loc)
459 int errors = Report.Errors;
460 bool out_access = right_side == EmptyExpression.OutAccess;
462 Expression e = DoResolveLValue (ec, right_side);
464 if (e != null && out_access && !(e is IMemoryLocation)) {
465 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
466 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
468 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
469 // e.GetType () + " " + e.GetSignatureForError ());
474 if (errors == Report.Errors) {
476 Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
478 Report.Error (131, loc, "The left-hand side of an assignment or mutating operation must be a variable, property or indexer");
483 if (e.eclass == ExprClass.Invalid)
484 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
486 if (e.eclass == ExprClass.MethodGroup) {
487 ((MethodGroupExpr) e).ReportUsageError ();
491 if ((e.type == null) && !(e is ConstructedType))
492 throw new Exception ("Expression " + e + " did not set its type after Resolve");
498 /// Emits the code for the expression
502 /// The Emit method is invoked to generate the code
503 /// for the expression.
505 public abstract void Emit (EmitContext ec);
507 public virtual void EmitBranchable (EmitContext ec, Label target, bool onTrue)
510 ec.ig.Emit (onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target);
514 /// Protected constructor. Only derivate types should
515 /// be able to be created
518 protected Expression ()
520 eclass = ExprClass.Invalid;
525 /// Returns a literalized version of a literal FieldInfo
529 /// The possible return values are:
530 /// IntConstant, UIntConstant
531 /// LongLiteral, ULongConstant
532 /// FloatConstant, DoubleConstant
535 /// The value returned is already resolved.
537 public static Constant Constantify (object v, Type t)
539 if (t == TypeManager.int32_type)
540 return new IntConstant ((int) v, Location.Null);
541 else if (t == TypeManager.uint32_type)
542 return new UIntConstant ((uint) v, Location.Null);
543 else if (t == TypeManager.int64_type)
544 return new LongConstant ((long) v, Location.Null);
545 else if (t == TypeManager.uint64_type)
546 return new ULongConstant ((ulong) v, Location.Null);
547 else if (t == TypeManager.float_type)
548 return new FloatConstant ((float) v, Location.Null);
549 else if (t == TypeManager.double_type)
550 return new DoubleConstant ((double) v, Location.Null);
551 else if (t == TypeManager.string_type)
552 return new StringConstant ((string) v, Location.Null);
553 else if (t == TypeManager.short_type)
554 return new ShortConstant ((short)v, Location.Null);
555 else if (t == TypeManager.ushort_type)
556 return new UShortConstant ((ushort)v, Location.Null);
557 else if (t == TypeManager.sbyte_type)
558 return new SByteConstant ((sbyte)v, Location.Null);
559 else if (t == TypeManager.byte_type)
560 return new ByteConstant ((byte)v, Location.Null);
561 else if (t == TypeManager.char_type)
562 return new CharConstant ((char)v, Location.Null);
563 else if (t == TypeManager.bool_type)
564 return new BoolConstant ((bool) v, Location.Null);
565 else if (t == TypeManager.decimal_type)
566 return new DecimalConstant ((decimal) v, Location.Null);
567 else if (TypeManager.IsEnumType (t)){
568 Type real_type = TypeManager.TypeToCoreType (v.GetType ());
570 real_type = System.Enum.GetUnderlyingType (real_type);
572 Constant e = Constantify (v, real_type);
574 return new EnumConstant (e, t);
575 } else if (v == null && !TypeManager.IsValueType (t))
576 return new NullLiteral (Location.Null);
578 throw new Exception ("Unknown type for constant (" + t +
583 /// Returns a fully formed expression after a MemberLookup
586 public static Expression ExprClassFromMemberInfo (Type containerType, MemberInfo mi, Location loc)
589 return new EventExpr ((EventInfo) mi, loc);
590 else if (mi is FieldInfo)
591 return new FieldExpr ((FieldInfo) mi, loc);
592 else if (mi is PropertyInfo)
593 return new PropertyExpr (containerType, (PropertyInfo) mi, loc);
594 else if (mi is Type){
595 return new TypeExpression ((System.Type) mi, loc);
601 protected static ArrayList almostMatchedMembers = new ArrayList (4);
604 // FIXME: Probably implement a cache for (t,name,current_access_set)?
606 // This code could use some optimizations, but we need to do some
607 // measurements. For example, we could use a delegate to `flag' when
608 // something can not any longer be a method-group (because it is something
612 // If the return value is an Array, then it is an array of
615 // If the return value is an MemberInfo, it is anything, but a Method
619 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
620 // the arguments here and have MemberLookup return only the methods that
621 // match the argument count/type, unlike we are doing now (we delay this
624 // This is so we can catch correctly attempts to invoke instance methods
625 // from a static body (scan for error 120 in ResolveSimpleName).
628 // FIXME: Potential optimization, have a static ArrayList
631 public static Expression MemberLookup (Type container_type, Type queried_type, string name,
632 MemberTypes mt, BindingFlags bf, Location loc)
634 return MemberLookup (container_type, null, queried_type, name, mt, bf, loc);
638 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
639 // `qualifier_type' or null to lookup members in the current class.
642 public static Expression MemberLookup (Type container_type,
643 Type qualifier_type, Type queried_type,
644 string name, MemberTypes mt,
645 BindingFlags bf, Location loc)
647 almostMatchedMembers.Clear ();
649 MemberInfo [] mi = TypeManager.MemberLookup (container_type, qualifier_type,
650 queried_type, mt, bf, name, almostMatchedMembers);
655 int count = mi.Length;
657 if (mi [0] is MethodBase)
658 return new MethodGroupExpr (mi, loc);
663 return ExprClassFromMemberInfo (container_type, mi [0], loc);
666 public const MemberTypes AllMemberTypes =
667 MemberTypes.Constructor |
671 MemberTypes.NestedType |
672 MemberTypes.Property;
674 public const BindingFlags AllBindingFlags =
675 BindingFlags.Public |
676 BindingFlags.Static |
677 BindingFlags.Instance;
679 public static Expression MemberLookup (Type container_type, Type queried_type,
680 string name, Location loc)
682 return MemberLookup (container_type, null, queried_type, name,
683 AllMemberTypes, AllBindingFlags, loc);
686 public static Expression MemberLookup (Type container_type, Type qualifier_type,
687 Type queried_type, string name, Location loc)
689 return MemberLookup (container_type, qualifier_type, queried_type,
690 name, AllMemberTypes, AllBindingFlags, loc);
693 public static Expression MethodLookup (EmitContext ec, Type queried_type,
694 string name, Location loc)
696 return MemberLookup (ec.ContainerType, null, queried_type, name,
697 MemberTypes.Method, AllBindingFlags, loc);
701 /// This is a wrapper for MemberLookup that is not used to "probe", but
702 /// to find a final definition. If the final definition is not found, we
703 /// look for private members and display a useful debugging message if we
706 public static Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
707 Type queried_type, string name, Location loc)
709 return MemberLookupFinal (ec, qualifier_type, queried_type, name,
710 AllMemberTypes, AllBindingFlags, loc);
713 public static Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
714 Type queried_type, string name,
715 MemberTypes mt, BindingFlags bf,
720 int errors = Report.Errors;
722 e = MemberLookup (ec.ContainerType, qualifier_type, queried_type, name, mt, bf, loc);
724 if (e == null && errors == Report.Errors)
725 // No errors were reported by MemberLookup, but there was an error.
726 MemberLookupFailed (ec.ContainerType, qualifier_type, queried_type, name, null, true, loc);
731 public static void MemberLookupFailed (Type container_type, Type qualifier_type,
732 Type queried_type, string name,
733 string class_name, bool complain_if_none_found,
736 if (almostMatchedMembers.Count != 0) {
737 for (int i = 0; i < almostMatchedMembers.Count; ++i) {
738 MemberInfo m = (MemberInfo) almostMatchedMembers [i];
739 for (int j = 0; j < i; ++j) {
740 if (m == almostMatchedMembers [j]) {
748 Type declaring_type = m.DeclaringType;
750 Report.SymbolRelatedToPreviousError (m);
751 if (qualifier_type == null) {
752 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
753 TypeManager.CSharpName (m.DeclaringType),
754 TypeManager.CSharpName (container_type));
756 } else if (qualifier_type != container_type &&
757 TypeManager.IsNestedFamilyAccessible (container_type, declaring_type)) {
758 // Although a derived class can access protected members of
759 // its base class it cannot do so through an instance of the
760 // base class (CS1540). If the qualifier_type is a base of the
761 // ec.ContainerType and the lookup succeeds with the latter one,
762 // then we are in this situation.
763 Error_CannotAccessProtected (loc, m, qualifier_type, container_type);
765 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (m));
768 almostMatchedMembers.Clear ();
772 MemberInfo[] lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
773 AllMemberTypes, AllBindingFlags |
774 BindingFlags.NonPublic, name, null);
776 if (lookup == null) {
777 if (!complain_if_none_found)
780 if (class_name != null)
781 Report.Error (103, loc, "The name `{0}' does not exist in the context of `{1}'",
784 Error_TypeDoesNotContainDefinition (loc, queried_type, name);
788 if (TypeManager.MemberLookup (queried_type, null, queried_type,
789 AllMemberTypes, AllBindingFlags |
790 BindingFlags.NonPublic, name, null) == null) {
791 if ((lookup.Length == 1) && (lookup [0] is Type)) {
792 Type t = (Type) lookup [0];
794 Report.Error (305, loc,
795 "Using the generic type `{0}' " +
796 "requires {1} type arguments",
797 TypeManager.CSharpName (t),
798 TypeManager.GetNumberOfTypeArguments (t).ToString ());
803 MemberList ml = TypeManager.FindMembers (queried_type, MemberTypes.Constructor,
804 BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly, null, null);
805 if (name == ".ctor" && ml.Count == 0)
807 Report.Error (143, loc, "The type `{0}' has no constructors defined", TypeManager.CSharpName (queried_type));
811 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (lookup [0]));
815 /// Returns an expression that can be used to invoke operator true
816 /// on the expression if it exists.
818 static public Expression GetOperatorTrue (EmitContext ec, Expression e, Location loc)
820 return GetOperatorTrueOrFalse (ec, e, true, loc);
824 /// Returns an expression that can be used to invoke operator false
825 /// on the expression if it exists.
827 static public Expression GetOperatorFalse (EmitContext ec, Expression e, Location loc)
829 return GetOperatorTrueOrFalse (ec, e, false, loc);
832 static Expression GetOperatorTrueOrFalse (EmitContext ec, Expression e, bool is_true, Location loc)
835 Expression operator_group;
837 if (TypeManager.IsNullableType (e.Type))
838 return new Nullable.OperatorTrueOrFalse (e, is_true, loc).Resolve (ec);
840 operator_group = MethodLookup (ec, e.Type, is_true ? "op_True" : "op_False", loc);
841 if (operator_group == null)
844 ArrayList arguments = new ArrayList ();
845 arguments.Add (new Argument (e, Argument.AType.Expression));
846 method = Invocation.OverloadResolve (
847 ec, (MethodGroupExpr) operator_group, arguments, false, loc);
852 return new StaticCallExpr ((MethodInfo) method, arguments, loc);
856 /// Resolves the expression `e' into a boolean expression: either through
857 /// an implicit conversion, or through an `operator true' invocation
859 public static Expression ResolveBoolean (EmitContext ec, Expression e, Location loc)
865 if (e.Type == TypeManager.bool_type)
868 Expression converted = Convert.ImplicitConversion (ec, e, TypeManager.bool_type, Location.Null);
870 if (converted != null)
874 // If no implicit conversion to bool exists, try using `operator true'
876 converted = Expression.GetOperatorTrue (ec, e, loc);
877 if (converted == null){
878 e.Error_ValueCannotBeConverted (loc, TypeManager.bool_type, false);
884 public virtual string ExprClassName
888 case ExprClass.Invalid:
890 case ExprClass.Value:
892 case ExprClass.Variable:
894 case ExprClass.Namespace:
898 case ExprClass.MethodGroup:
899 return "method group";
900 case ExprClass.PropertyAccess:
901 return "property access";
902 case ExprClass.EventAccess:
903 return "event access";
904 case ExprClass.IndexerAccess:
905 return "indexer access";
906 case ExprClass.Nothing:
909 throw new Exception ("Should not happen");
914 /// Reports that we were expecting `expr' to be of class `expected'
916 public void Error_UnexpectedKind (DeclSpace ds, string expected, Location loc)
918 Error_UnexpectedKind (ds, expected, ExprClassName, loc);
921 public void Error_UnexpectedKind (DeclSpace ds, string expected, string was, Location loc)
923 string name = GetSignatureForError ();
925 name = ds.GetSignatureForError () + '.' + name;
927 Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
928 name, was, expected);
931 public void Error_UnexpectedKind (ResolveFlags flags, Location loc)
933 string [] valid = new string [4];
936 if ((flags & ResolveFlags.VariableOrValue) != 0) {
937 valid [count++] = "variable";
938 valid [count++] = "value";
941 if ((flags & ResolveFlags.Type) != 0)
942 valid [count++] = "type";
944 if ((flags & ResolveFlags.MethodGroup) != 0)
945 valid [count++] = "method group";
948 valid [count++] = "unknown";
950 StringBuilder sb = new StringBuilder (valid [0]);
951 for (int i = 1; i < count - 1; i++) {
953 sb.Append (valid [i]);
956 sb.Append ("' or `");
957 sb.Append (valid [count - 1]);
960 Report.Error (119, loc,
961 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
964 public static void UnsafeError (Location loc)
966 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
970 // Load the object from the pointer.
972 public static void LoadFromPtr (ILGenerator ig, Type t)
974 if (t == TypeManager.int32_type)
975 ig.Emit (OpCodes.Ldind_I4);
976 else if (t == TypeManager.uint32_type)
977 ig.Emit (OpCodes.Ldind_U4);
978 else if (t == TypeManager.short_type)
979 ig.Emit (OpCodes.Ldind_I2);
980 else if (t == TypeManager.ushort_type)
981 ig.Emit (OpCodes.Ldind_U2);
982 else if (t == TypeManager.char_type)
983 ig.Emit (OpCodes.Ldind_U2);
984 else if (t == TypeManager.byte_type)
985 ig.Emit (OpCodes.Ldind_U1);
986 else if (t == TypeManager.sbyte_type)
987 ig.Emit (OpCodes.Ldind_I1);
988 else if (t == TypeManager.uint64_type)
989 ig.Emit (OpCodes.Ldind_I8);
990 else if (t == TypeManager.int64_type)
991 ig.Emit (OpCodes.Ldind_I8);
992 else if (t == TypeManager.float_type)
993 ig.Emit (OpCodes.Ldind_R4);
994 else if (t == TypeManager.double_type)
995 ig.Emit (OpCodes.Ldind_R8);
996 else if (t == TypeManager.bool_type)
997 ig.Emit (OpCodes.Ldind_I1);
998 else if (t == TypeManager.intptr_type)
999 ig.Emit (OpCodes.Ldind_I);
1000 else if (TypeManager.IsEnumType (t)) {
1001 if (t == TypeManager.enum_type)
1002 ig.Emit (OpCodes.Ldind_Ref);
1004 LoadFromPtr (ig, TypeManager.EnumToUnderlying (t));
1005 } else if (t.IsValueType || t.IsGenericParameter)
1006 ig.Emit (OpCodes.Ldobj, t);
1007 else if (t.IsPointer)
1008 ig.Emit (OpCodes.Ldind_I);
1010 ig.Emit (OpCodes.Ldind_Ref);
1014 // The stack contains the pointer and the value of type `type'
1016 public static void StoreFromPtr (ILGenerator ig, Type type)
1018 if (TypeManager.IsEnumType (type))
1019 type = TypeManager.EnumToUnderlying (type);
1020 if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
1021 ig.Emit (OpCodes.Stind_I4);
1022 else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
1023 ig.Emit (OpCodes.Stind_I8);
1024 else if (type == TypeManager.char_type || type == TypeManager.short_type ||
1025 type == TypeManager.ushort_type)
1026 ig.Emit (OpCodes.Stind_I2);
1027 else if (type == TypeManager.float_type)
1028 ig.Emit (OpCodes.Stind_R4);
1029 else if (type == TypeManager.double_type)
1030 ig.Emit (OpCodes.Stind_R8);
1031 else if (type == TypeManager.byte_type || type == TypeManager.sbyte_type ||
1032 type == TypeManager.bool_type)
1033 ig.Emit (OpCodes.Stind_I1);
1034 else if (type == TypeManager.intptr_type)
1035 ig.Emit (OpCodes.Stind_I);
1036 else if (type.IsValueType || type.IsGenericParameter)
1037 ig.Emit (OpCodes.Stobj, type);
1039 ig.Emit (OpCodes.Stind_Ref);
1043 // Returns the size of type `t' if known, otherwise, 0
1045 public static int GetTypeSize (Type t)
1047 t = TypeManager.TypeToCoreType (t);
1048 if (t == TypeManager.int32_type ||
1049 t == TypeManager.uint32_type ||
1050 t == TypeManager.float_type)
1052 else if (t == TypeManager.int64_type ||
1053 t == TypeManager.uint64_type ||
1054 t == TypeManager.double_type)
1056 else if (t == TypeManager.byte_type ||
1057 t == TypeManager.sbyte_type ||
1058 t == TypeManager.bool_type)
1060 else if (t == TypeManager.short_type ||
1061 t == TypeManager.char_type ||
1062 t == TypeManager.ushort_type)
1064 else if (t == TypeManager.decimal_type)
1070 public static void Error_NegativeArrayIndex (Location loc)
1072 Report.Error (248, loc, "Cannot create an array with a negative size");
1075 protected void Error_CannotCallAbstractBase (string name)
1077 Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
1081 // Converts `source' to an int, uint, long or ulong.
1083 public Expression ExpressionToArrayArgument (EmitContext ec, Expression source, Location loc)
1087 bool old_checked = ec.CheckState;
1088 ec.CheckState = true;
1090 target = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, loc);
1091 if (target == null){
1092 target = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, loc);
1093 if (target == null){
1094 target = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, loc);
1095 if (target == null){
1096 target = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, loc);
1098 source.Error_ValueCannotBeConverted (loc, TypeManager.int32_type, false);
1102 ec.CheckState = old_checked;
1105 // Only positive constants are allowed at compile time
1107 if (target is Constant){
1108 if (target is IntConstant){
1109 if (((IntConstant) target).Value < 0){
1110 Error_NegativeArrayIndex (loc);
1115 if (target is LongConstant){
1116 if (((LongConstant) target).Value < 0){
1117 Error_NegativeArrayIndex (loc);
1130 /// This is just a base class for expressions that can
1131 /// appear on statements (invocations, object creation,
1132 /// assignments, post/pre increment and decrement). The idea
1133 /// being that they would support an extra Emition interface that
1134 /// does not leave a result on the stack.
1136 public abstract class ExpressionStatement : Expression {
1138 public virtual ExpressionStatement ResolveStatement (EmitContext ec)
1140 Expression e = Resolve (ec);
1144 ExpressionStatement es = e as ExpressionStatement;
1146 Error (201, "Only assignment, call, increment, decrement and new object " +
1147 "expressions can be used as a statement");
1153 /// Requests the expression to be emitted in a `statement'
1154 /// context. This means that no new value is left on the
1155 /// stack after invoking this method (constrasted with
1156 /// Emit that will always leave a value on the stack).
1158 public abstract void EmitStatement (EmitContext ec);
1162 /// This kind of cast is used to encapsulate the child
1163 /// whose type is child.Type into an expression that is
1164 /// reported to return "return_type". This is used to encapsulate
1165 /// expressions which have compatible types, but need to be dealt
1166 /// at higher levels with.
1168 /// For example, a "byte" expression could be encapsulated in one
1169 /// of these as an "unsigned int". The type for the expression
1170 /// would be "unsigned int".
1173 public class EmptyCast : Expression {
1174 protected readonly Expression child;
1176 public EmptyCast (Expression child, Type return_type)
1178 eclass = child.eclass;
1179 loc = child.Location;
1184 public override Expression DoResolve (EmitContext ec)
1186 // This should never be invoked, we are born in fully
1187 // initialized state.
1192 public override void Emit (EmitContext ec)
1197 public override bool GetAttributableValue (Type valueType, out object value)
1199 return child.GetAttributableValue (valueType, out value);
1204 /// This is a numeric cast to a Decimal
1206 public class CastToDecimal : EmptyCast {
1208 MethodInfo conversion_operator;
1210 public CastToDecimal (Expression child)
1211 : this (child, false)
1215 public CastToDecimal (Expression child, bool find_explicit)
1216 : base (child, TypeManager.decimal_type)
1218 conversion_operator = GetConversionOperator (find_explicit);
1220 if (conversion_operator == null)
1221 throw new InternalErrorException ("Outer conversion routine is out of sync");
1224 // Returns the implicit operator that converts from
1225 // 'child.Type' to System.Decimal.
1226 MethodInfo GetConversionOperator (bool find_explicit)
1228 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1230 MemberInfo [] mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1231 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1233 foreach (MethodInfo oper in mi) {
1234 ParameterData pd = TypeManager.GetParameterData (oper);
1236 if (pd.ParameterType (0) == child.Type && oper.ReturnType == type)
1242 public override void Emit (EmitContext ec)
1244 ILGenerator ig = ec.ig;
1247 ig.Emit (OpCodes.Call, conversion_operator);
1252 /// This is an explicit numeric cast from a Decimal
1254 public class CastFromDecimal : EmptyCast
1256 static IDictionary operators;
1258 public CastFromDecimal (Expression child, Type return_type)
1259 : base (child, return_type)
1261 if (child.Type != TypeManager.decimal_type)
1262 throw new InternalErrorException (
1263 "The expected type is Decimal, instead it is " + child.Type.FullName);
1266 // Returns the explicit operator that converts from an
1267 // express of type System.Decimal to 'type'.
1268 public Expression Resolve ()
1270 if (operators == null) {
1271 MemberInfo[] all_oper = TypeManager.MemberLookup (TypeManager.decimal_type,
1272 TypeManager.decimal_type, TypeManager.decimal_type, MemberTypes.Method,
1273 BindingFlags.Static | BindingFlags.Public, "op_Explicit", null);
1275 operators = new System.Collections.Specialized.HybridDictionary ();
1276 foreach (MethodInfo oper in all_oper) {
1277 ParameterData pd = TypeManager.GetParameterData (oper);
1278 if (pd.ParameterType (0) == TypeManager.decimal_type)
1279 operators.Add (oper.ReturnType, oper);
1283 return operators.Contains (type) ? this : null;
1286 public override void Emit (EmitContext ec)
1288 ILGenerator ig = ec.ig;
1291 ig.Emit (OpCodes.Call, (MethodInfo)operators [type]);
1296 // We need to special case this since an empty cast of
1297 // a NullLiteral is still a Constant
1299 public class NullCast : Constant {
1300 public Constant child;
1302 public NullCast (Constant child, Type return_type):
1303 base (Location.Null)
1305 eclass = child.eclass;
1310 override public string AsString ()
1315 public override object GetValue ()
1320 public override Expression DoResolve (EmitContext ec)
1322 // This should never be invoked, we are born in fully
1323 // initialized state.
1328 public override void Emit (EmitContext ec)
1333 public override Constant Increment ()
1335 throw new NotSupportedException ();
1338 public override bool IsDefaultValue {
1344 public override bool IsNegative {
1350 public override Constant Reduce (bool inCheckedContext, Type target_type)
1352 if (type == target_type)
1353 return child.Reduce (inCheckedContext, target_type);
1362 /// This class is used to wrap literals which belong inside Enums
1364 public class EnumConstant : Constant {
1365 public Constant Child;
1367 public EnumConstant (Constant child, Type enum_type):
1368 base (child.Location)
1370 eclass = child.eclass;
1375 public override Expression DoResolve (EmitContext ec)
1377 // This should never be invoked, we are born in fully
1378 // initialized state.
1383 public override void Emit (EmitContext ec)
1388 public override bool GetAttributableValue (Type valueType, out object value)
1390 value = GetTypedValue ();
1394 public override string GetSignatureForError()
1396 return TypeManager.CSharpName (Type);
1399 public override object GetValue ()
1401 return Child.GetValue ();
1404 public override object GetTypedValue ()
1406 // FIXME: runtime is not ready to work with just emited enums
1407 if (!RootContext.StdLib) {
1408 return Child.GetValue ();
1411 return System.Enum.ToObject (type, Child.GetValue ());
1414 public override string AsString ()
1416 return Child.AsString ();
1419 public override DoubleConstant ConvertToDouble ()
1421 return Child.ConvertToDouble ();
1424 public override FloatConstant ConvertToFloat ()
1426 return Child.ConvertToFloat ();
1429 public override ULongConstant ConvertToULong ()
1431 return Child.ConvertToULong ();
1434 public override LongConstant ConvertToLong ()
1436 return Child.ConvertToLong ();
1439 public override UIntConstant ConvertToUInt ()
1441 return Child.ConvertToUInt ();
1444 public override IntConstant ConvertToInt ()
1446 return Child.ConvertToInt ();
1449 public override Constant Increment()
1451 return new EnumConstant (Child.Increment (), type);
1454 public override bool IsDefaultValue {
1456 return Child.IsDefaultValue;
1460 public override bool IsZeroInteger {
1461 get { return Child.IsZeroInteger; }
1464 public override bool IsNegative {
1466 return Child.IsNegative;
1470 public override Constant Reduce(bool inCheckedContext, Type target_type)
1472 if (Child.Type == target_type)
1475 return Child.Reduce (inCheckedContext, target_type);
1478 public override Constant ToType (Type type, Location loc)
1481 // This is workaround of mono bug. It can be removed when the latest corlib spreads enough
1482 if (TypeManager.IsEnumType (type.UnderlyingSystemType))
1485 if (type.UnderlyingSystemType != Child.Type)
1486 Child = Child.ToType (type.UnderlyingSystemType, loc);
1490 if (!Convert.ImplicitStandardConversionExists (this, type)){
1491 Error_ValueCannotBeConverted (loc, type, false);
1495 return Child.ToType (type, loc);
1501 /// This kind of cast is used to encapsulate Value Types in objects.
1503 /// The effect of it is to box the value type emitted by the previous
1506 public class BoxedCast : EmptyCast {
1508 public BoxedCast (Expression expr, Type target_type)
1509 : base (expr, target_type)
1511 eclass = ExprClass.Value;
1514 public override Expression DoResolve (EmitContext ec)
1516 // This should never be invoked, we are born in fully
1517 // initialized state.
1522 public override void Emit (EmitContext ec)
1526 ec.ig.Emit (OpCodes.Box, child.Type);
1530 public class UnboxCast : EmptyCast {
1531 public UnboxCast (Expression expr, Type return_type)
1532 : base (expr, return_type)
1536 public override Expression DoResolve (EmitContext ec)
1538 // This should never be invoked, we are born in fully
1539 // initialized state.
1544 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1546 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
1547 Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
1548 return base.DoResolveLValue (ec, right_side);
1551 public override void Emit (EmitContext ec)
1554 ILGenerator ig = ec.ig;
1557 if (t.IsGenericParameter)
1558 ig.Emit (OpCodes.Unbox_Any, t);
1560 ig.Emit (OpCodes.Unbox, t);
1562 LoadFromPtr (ig, t);
1568 /// This is used to perform explicit numeric conversions.
1570 /// Explicit numeric conversions might trigger exceptions in a checked
1571 /// context, so they should generate the conv.ovf opcodes instead of
1574 public class ConvCast : EmptyCast {
1575 public enum Mode : byte {
1576 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1578 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1579 U2_I1, U2_U1, U2_I2, U2_CH,
1580 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1581 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1582 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH,
1583 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH,
1584 CH_I1, CH_U1, CH_I2,
1585 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1586 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4
1591 public ConvCast (Expression child, Type return_type, Mode m)
1592 : base (child, return_type)
1597 public override Expression DoResolve (EmitContext ec)
1599 // This should never be invoked, we are born in fully
1600 // initialized state.
1605 public override string ToString ()
1607 return String.Format ("ConvCast ({0}, {1})", mode, child);
1610 public override void Emit (EmitContext ec)
1612 ILGenerator ig = ec.ig;
1618 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1619 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1620 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1621 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1622 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1624 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1625 case Mode.U1_CH: /* nothing */ break;
1627 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1628 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1629 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1630 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1631 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1632 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1634 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1635 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1636 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1637 case Mode.U2_CH: /* nothing */ break;
1639 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1640 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1641 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1642 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1643 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1644 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1645 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1647 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1648 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1649 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1650 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1651 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1652 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1654 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1655 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1656 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1657 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1658 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1659 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1660 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1661 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1663 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1664 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1665 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1666 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1667 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1668 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1669 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1670 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1672 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1673 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1674 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1676 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1677 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1678 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1679 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1680 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1681 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1682 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1683 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1684 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1686 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1687 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1688 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1689 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1690 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1691 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1692 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1693 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1694 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1695 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1699 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
1700 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
1701 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
1702 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
1703 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
1705 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
1706 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
1708 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
1709 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
1710 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
1711 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
1712 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
1713 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
1715 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
1716 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
1717 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
1718 case Mode.U2_CH: /* nothing */ break;
1720 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
1721 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
1722 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
1723 case Mode.I4_U4: /* nothing */ break;
1724 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
1725 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
1726 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
1728 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
1729 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
1730 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
1731 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
1732 case Mode.U4_I4: /* nothing */ break;
1733 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
1735 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
1736 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
1737 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
1738 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
1739 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
1740 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
1741 case Mode.I8_U8: /* nothing */ break;
1742 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
1744 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
1745 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
1746 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
1747 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
1748 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
1749 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
1750 case Mode.U8_I8: /* nothing */ break;
1751 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
1753 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
1754 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
1755 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
1757 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
1758 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
1759 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
1760 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
1761 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
1762 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
1763 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
1764 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
1765 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
1767 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
1768 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
1769 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
1770 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
1771 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
1772 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
1773 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
1774 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
1775 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
1776 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1782 public class OpcodeCast : EmptyCast {
1786 public OpcodeCast (Expression child, Type return_type, OpCode op)
1787 : base (child, return_type)
1791 second_valid = false;
1794 public OpcodeCast (Expression child, Type return_type, OpCode op, OpCode op2)
1795 : base (child, return_type)
1800 second_valid = true;
1803 public override Expression DoResolve (EmitContext ec)
1805 // This should never be invoked, we are born in fully
1806 // initialized state.
1811 public override void Emit (EmitContext ec)
1822 /// This kind of cast is used to encapsulate a child and cast it
1823 /// to the class requested
1825 public class ClassCast : EmptyCast {
1826 public ClassCast (Expression child, Type return_type)
1827 : base (child, return_type)
1832 public override Expression DoResolve (EmitContext ec)
1834 // This should never be invoked, we are born in fully
1835 // initialized state.
1840 public override void Emit (EmitContext ec)
1844 if (child.Type.IsGenericParameter)
1845 ec.ig.Emit (OpCodes.Box, child.Type);
1847 if (type.IsGenericParameter)
1848 ec.ig.Emit (OpCodes.Unbox_Any, type);
1850 ec.ig.Emit (OpCodes.Castclass, type);
1855 /// SimpleName expressions are formed of a single word and only happen at the beginning
1856 /// of a dotted-name.
1858 public class SimpleName : Expression {
1860 public readonly TypeArguments Arguments;
1863 public SimpleName (string name, Location l)
1869 public SimpleName (string name, TypeArguments args, Location l)
1876 public SimpleName (string name, TypeParameter[] type_params, Location l)
1881 Arguments = new TypeArguments (l);
1882 foreach (TypeParameter type_param in type_params)
1883 Arguments.Add (new TypeParameterExpr (type_param, l));
1886 public static string RemoveGenericArity (string name)
1889 StringBuilder sb = new StringBuilder ();
1890 while (start < name.Length) {
1891 int pos = name.IndexOf ('`', start);
1893 sb.Append (name.Substring (start));
1897 sb.Append (name.Substring (start, pos-start));
1900 while ((pos < name.Length) && Char.IsNumber (name [pos]))
1906 return sb.ToString ();
1909 public SimpleName GetMethodGroup ()
1911 return new SimpleName (RemoveGenericArity (Name), Arguments, loc);
1914 public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
1916 if (ec.IsFieldInitializer)
1917 Report.Error (236, l,
1918 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
1921 if (name.LastIndexOf ('.') > 0)
1922 name = name.Substring (name.LastIndexOf ('.') + 1);
1925 120, l, "`{0}': An object reference is required for the nonstatic field, method or property",
1930 public bool IdenticalNameAndTypeName (EmitContext ec, Expression resolved_to, Location loc)
1932 return resolved_to != null && resolved_to.Type != null &&
1933 resolved_to.Type.Name == Name &&
1934 (ec.DeclContainer.LookupType (Name, loc, /* ignore_cs0104 = */ true) != null);
1937 public override Expression DoResolve (EmitContext ec)
1939 return SimpleNameResolve (ec, null, false);
1942 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1944 return SimpleNameResolve (ec, right_side, false);
1948 public Expression DoResolve (EmitContext ec, bool intermediate)
1950 return SimpleNameResolve (ec, null, intermediate);
1953 private bool IsNestedChild (Type t, Type parent)
1958 while (parent != null) {
1959 parent = TypeManager.DropGenericTypeArguments (parent);
1960 if (TypeManager.IsNestedChildOf (t, parent))
1963 parent = parent.BaseType;
1969 FullNamedExpression ResolveNested (IResolveContext ec, Type t)
1971 if (!t.IsGenericTypeDefinition)
1974 DeclSpace ds = ec.DeclContainer;
1975 while (ds != null) {
1976 if (IsNestedChild (t, ds.TypeBuilder))
1985 Type[] gen_params = t.GetGenericArguments ();
1987 int arg_count = Arguments != null ? Arguments.Count : 0;
1989 for (; (ds != null) && ds.IsGeneric; ds = ds.Parent) {
1990 if (arg_count + ds.CountTypeParameters == gen_params.Length) {
1991 TypeArguments new_args = new TypeArguments (loc);
1992 foreach (TypeParameter param in ds.TypeParameters)
1993 new_args.Add (new TypeParameterExpr (param, loc));
1995 if (Arguments != null)
1996 new_args.Add (Arguments);
1998 return new ConstructedType (t, new_args, loc);
2005 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2007 FullNamedExpression fne = ec.DeclContainer.LookupGeneric (Name, loc);
2009 return fne.ResolveAsTypeStep (ec, silent);
2011 int errors = Report.Errors;
2012 fne = ec.DeclContainer.LookupType (Name, loc, /*ignore_cs0104=*/ false);
2015 if (fne.Type == null)
2018 FullNamedExpression nested = ResolveNested (ec, fne.Type);
2020 return nested.ResolveAsTypeStep (ec, false);
2022 if (Arguments != null) {
2023 ConstructedType ct = new ConstructedType (fne, Arguments, loc);
2024 return ct.ResolveAsTypeStep (ec, false);
2030 if (silent || errors != Report.Errors)
2033 MemberCore mc = ec.DeclContainer.GetDefinition (Name);
2035 Error_UnexpectedKind (ec.DeclContainer, "type", GetMemberType (mc), loc);
2039 string ns = ec.DeclContainer.NamespaceEntry.NS.Name;
2040 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2041 foreach (Assembly a in RootNamespace.Global.Assemblies) {
2042 Type type = a.GetType (fullname);
2044 Report.SymbolRelatedToPreviousError (type);
2045 Expression.ErrorIsInaccesible (loc, fullname);
2050 NamespaceEntry.Error_NamespaceNotFound (loc, Name);
2054 // TODO: I am still not convinced about this. If someone else will need it
2055 // implement this as virtual property in MemberCore hierarchy
2056 string GetMemberType (MemberCore mc)
2058 if (mc is PropertyBase)
2062 if (mc is FieldBase)
2064 if (mc is MethodCore)
2066 if (mc is EnumMember)
2072 Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2078 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2082 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2089 /// 7.5.2: Simple Names.
2091 /// Local Variables and Parameters are handled at
2092 /// parse time, so they never occur as SimpleNames.
2094 /// The `intermediate' flag is used by MemberAccess only
2095 /// and it is used to inform us that it is ok for us to
2096 /// avoid the static check, because MemberAccess might end
2097 /// up resolving the Name as a Type name and the access as
2098 /// a static type access.
2100 /// ie: Type Type; .... { Type.GetType (""); }
2102 /// Type is both an instance variable and a Type; Type.GetType
2103 /// is the static method not an instance method of type.
2105 Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2107 Expression e = null;
2110 // Stage 1: Performed by the parser (binding to locals or parameters).
2112 Block current_block = ec.CurrentBlock;
2113 if (current_block != null){
2114 LocalInfo vi = current_block.GetLocalInfo (Name);
2116 LocalVariableReference var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2117 if (right_side != null) {
2118 return var.ResolveLValue (ec, right_side, loc);
2120 ResolveFlags rf = ResolveFlags.VariableOrValue;
2122 rf |= ResolveFlags.DisableFlowAnalysis;
2123 return var.Resolve (ec, rf);
2127 ParameterReference pref = current_block.Toplevel.GetParameterReference (Name, loc);
2129 if (right_side != null)
2130 return pref.ResolveLValue (ec, right_side, loc);
2132 return pref.Resolve (ec);
2137 // Stage 2: Lookup members
2140 DeclSpace lookup_ds = ec.DeclContainer;
2141 Type almost_matched_type = null;
2142 ArrayList almost_matched = null;
2144 if (lookup_ds.TypeBuilder == null)
2147 e = MemberLookup (ec.ContainerType, lookup_ds.TypeBuilder, Name, loc);
2151 if (almost_matched == null && almostMatchedMembers.Count > 0) {
2152 almost_matched_type = lookup_ds.TypeBuilder;
2153 almost_matched = (ArrayList) almostMatchedMembers.Clone ();
2156 lookup_ds =lookup_ds.Parent;
2157 } while (lookup_ds != null);
2159 if (e == null && ec.ContainerType != null)
2160 e = MemberLookup (ec.ContainerType, ec.ContainerType, Name, loc);
2163 if (almost_matched == null && almostMatchedMembers.Count > 0) {
2164 almost_matched_type = ec.ContainerType;
2165 almost_matched = (ArrayList) almostMatchedMembers.Clone ();
2167 e = ResolveAsTypeStep (ec, true);
2171 if (almost_matched != null)
2172 almostMatchedMembers = almost_matched;
2173 if (almost_matched_type == null)
2174 almost_matched_type = ec.ContainerType;
2175 MemberLookupFailed (ec.ContainerType, null, almost_matched_type, ((SimpleName) this).Name, ec.DeclContainer.Name, true, loc);
2182 if (e is MemberExpr) {
2183 MemberExpr me = (MemberExpr) e;
2186 if (me.IsInstance) {
2187 if (ec.IsStatic || ec.IsFieldInitializer) {
2189 // Note that an MemberExpr can be both IsInstance and IsStatic.
2190 // An unresolved MethodGroupExpr can contain both kinds of methods
2191 // and each predicate is true if the MethodGroupExpr contains
2192 // at least one of that kind of method.
2196 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2197 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2198 return EmptyExpression.Null;
2202 // Pass the buck to MemberAccess and Invocation.
2204 left = EmptyExpression.Null;
2206 left = ec.GetThis (loc);
2209 left = new TypeExpression (ec.ContainerType, loc);
2212 e = me.ResolveMemberAccess (ec, left, loc, null);
2216 me = e as MemberExpr;
2220 if (Arguments != null) {
2221 MethodGroupExpr mg = me as MethodGroupExpr;
2225 return mg.ResolveGeneric (ec, Arguments);
2229 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2230 me.InstanceExpression.Type != me.DeclaringType &&
2231 !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2232 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2233 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2234 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2238 return (right_side != null)
2239 ? me.DoResolveLValue (ec, right_side)
2240 : me.DoResolve (ec);
2246 public override void Emit (EmitContext ec)
2249 // If this is ever reached, then we failed to
2250 // find the name as a namespace
2253 Error (103, "The name `" + Name +
2254 "' does not exist in the class `" +
2255 ec.DeclContainer.Name + "'");
2258 public override string ToString ()
2263 public override string GetSignatureForError ()
2270 /// Represents a namespace or a type. The name of the class was inspired by
2271 /// section 10.8.1 (Fully Qualified Names).
2273 public abstract class FullNamedExpression : Expression {
2274 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2279 public abstract string FullName {
2285 /// Expression that evaluates to a type
2287 public abstract class TypeExpr : FullNamedExpression {
2288 override public FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2290 TypeExpr t = DoResolveAsTypeStep (ec);
2294 eclass = ExprClass.Type;
2298 override public Expression DoResolve (EmitContext ec)
2300 return ResolveAsTypeTerminal (ec, false);
2303 override public void Emit (EmitContext ec)
2305 throw new Exception ("Should never be called");
2308 public virtual bool CheckAccessLevel (DeclSpace ds)
2310 return ds.CheckAccessLevel (Type);
2313 public virtual bool AsAccessible (DeclSpace ds, int flags)
2315 return ds.AsAccessible (Type, flags);
2318 public virtual bool IsClass {
2319 get { return Type.IsClass; }
2322 public virtual bool IsValueType {
2323 get { return Type.IsValueType; }
2326 public virtual bool IsInterface {
2327 get { return Type.IsInterface; }
2330 public virtual bool IsSealed {
2331 get { return Type.IsSealed; }
2334 public virtual bool CanInheritFrom ()
2336 if (Type == TypeManager.enum_type ||
2337 (Type == TypeManager.value_type && RootContext.StdLib) ||
2338 Type == TypeManager.multicast_delegate_type ||
2339 Type == TypeManager.delegate_type ||
2340 Type == TypeManager.array_type)
2346 protected abstract TypeExpr DoResolveAsTypeStep (IResolveContext ec);
2348 public abstract string Name {
2352 public override bool Equals (object obj)
2354 TypeExpr tobj = obj as TypeExpr;
2358 return Type == tobj.Type;
2361 public override int GetHashCode ()
2363 return Type.GetHashCode ();
2366 public override string ToString ()
2373 /// Fully resolved Expression that already evaluated to a type
2375 public class TypeExpression : TypeExpr {
2376 public TypeExpression (Type t, Location l)
2379 eclass = ExprClass.Type;
2383 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2388 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2393 public override string Name {
2394 get { return Type.ToString (); }
2397 public override string FullName {
2398 get { return Type.FullName; }
2403 /// Used to create types from a fully qualified name. These are just used
2404 /// by the parser to setup the core types. A TypeLookupExpression is always
2405 /// classified as a type.
2407 public sealed class TypeLookupExpression : TypeExpr {
2408 readonly string name;
2410 public TypeLookupExpression (string name)
2413 eclass = ExprClass.Type;
2416 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2418 // It's null for corlib compilation only
2420 return DoResolveAsTypeStep (ec);
2425 static readonly char [] dot_array = { '.' };
2426 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2428 // If name is of the form `N.I', first lookup `N', then search a member `I' in it.
2430 string lookup_name = name;
2431 int pos = name.IndexOf ('.');
2433 rest = name.Substring (pos + 1);
2434 lookup_name = name.Substring (0, pos);
2437 FullNamedExpression resolved = RootNamespace.Global.Lookup (ec.DeclContainer, lookup_name, Location.Null);
2439 if (resolved != null && rest != null) {
2440 // Now handle the rest of the the name.
2441 string [] elements = rest.Split (dot_array);
2443 int count = elements.Length;
2445 while (i < count && resolved != null && resolved is Namespace) {
2446 Namespace ns = resolved as Namespace;
2447 element = elements [i++];
2448 lookup_name += "." + element;
2449 resolved = ns.Lookup (ec.DeclContainer, element, Location.Null);
2452 if (resolved != null && resolved is TypeExpr) {
2453 Type t = ((TypeExpr) resolved).Type;
2455 if (!ec.DeclContainer.CheckAccessLevel (t)) {
2457 lookup_name = t.FullName;
2464 t = TypeManager.GetNestedType (t, elements [i++]);
2469 if (resolved == null) {
2470 NamespaceEntry.Error_NamespaceNotFound (loc, lookup_name);
2474 if (!(resolved is TypeExpr)) {
2475 resolved.Error_UnexpectedKind (ec.DeclContainer, "type", loc);
2479 type = resolved.Type;
2483 public override string Name {
2484 get { return name; }
2487 public override string FullName {
2488 get { return name; }
2493 /// Represents an "unbound generic type", ie. typeof (Foo<>).
2496 public class UnboundTypeExpression : TypeExpr
2500 public UnboundTypeExpression (MemberName name, Location l)
2506 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2509 if (name.Left != null) {
2510 Expression lexpr = name.Left.GetTypeExpression ();
2511 expr = new MemberAccess (lexpr, name.Basename);
2513 expr = new SimpleName (name.Basename, loc);
2516 FullNamedExpression fne = expr.ResolveAsTypeStep (ec, false);
2521 return new TypeExpression (type, loc);
2524 public override string Name {
2525 get { return name.FullName; }
2528 public override string FullName {
2529 get { return name.FullName; }
2533 public class TypeAliasExpression : TypeExpr {
2534 FullNamedExpression alias;
2539 public TypeAliasExpression (FullNamedExpression alias, TypeArguments args, Location l)
2545 eclass = ExprClass.Type;
2547 name = alias.FullName + "<" + args.ToString () + ">";
2549 name = alias.FullName;
2552 public override string Name {
2553 get { return alias.FullName; }
2556 public override string FullName {
2557 get { return name; }
2560 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2562 texpr = alias.ResolveAsTypeTerminal (ec, false);
2566 Type type = texpr.Type;
2567 int num_args = TypeManager.GetNumberOfTypeArguments (type);
2570 if (num_args == 0) {
2571 Report.Error (308, loc,
2572 "The non-generic type `{0}' cannot " +
2573 "be used with type arguments.",
2574 TypeManager.CSharpName (type));
2578 ConstructedType ctype = new ConstructedType (type, args, loc);
2579 return ctype.ResolveAsTypeTerminal (ec, false);
2580 } else if (num_args > 0) {
2581 Report.Error (305, loc,
2582 "Using the generic type `{0}' " +
2583 "requires {1} type arguments",
2584 TypeManager.CSharpName (type), num_args.ToString ());
2591 public override bool CheckAccessLevel (DeclSpace ds)
2593 return texpr.CheckAccessLevel (ds);
2596 public override bool AsAccessible (DeclSpace ds, int flags)
2598 return texpr.AsAccessible (ds, flags);
2601 public override bool IsClass {
2602 get { return texpr.IsClass; }
2605 public override bool IsValueType {
2606 get { return texpr.IsValueType; }
2609 public override bool IsInterface {
2610 get { return texpr.IsInterface; }
2613 public override bool IsSealed {
2614 get { return texpr.IsSealed; }
2619 /// This class denotes an expression which evaluates to a member
2620 /// of a struct or a class.
2622 public abstract class MemberExpr : Expression
2625 /// The name of this member.
2627 public abstract string Name {
2632 /// Whether this is an instance member.
2634 public abstract bool IsInstance {
2639 /// Whether this is a static member.
2641 public abstract bool IsStatic {
2646 /// The type which declares this member.
2648 public abstract Type DeclaringType {
2653 /// The instance expression associated with this member, if it's a
2654 /// non-static member.
2656 public Expression InstanceExpression;
2658 public static void error176 (Location loc, string name)
2660 Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
2661 "with an instance reference, qualify it with a type name instead", name);
2664 // TODO: possible optimalization
2665 // Cache resolved constant result in FieldBuilder <-> expression map
2666 public virtual Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
2667 SimpleName original)
2671 // original == null || original.Resolve (...) ==> left
2674 if (left is TypeExpr) {
2676 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
2684 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
2687 error176 (loc, GetSignatureForError ());
2691 InstanceExpression = left;
2696 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
2701 if (InstanceExpression == EmptyExpression.Null) {
2702 SimpleName.Error_ObjectRefRequired (ec, loc, Name);
2706 if (InstanceExpression.Type.IsValueType) {
2707 if (InstanceExpression is IMemoryLocation) {
2708 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
2710 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
2711 InstanceExpression.Emit (ec);
2713 t.AddressOf (ec, AddressOp.Store);
2716 InstanceExpression.Emit (ec);
2718 if (prepare_for_load)
2719 ec.ig.Emit (OpCodes.Dup);
2724 /// MethodGroup Expression.
2726 /// This is a fully resolved expression that evaluates to a type
2728 public class MethodGroupExpr : MemberExpr {
2729 public MethodBase [] Methods;
2730 bool has_type_arguments = false;
2731 bool identical_type_name = false;
2734 public MethodGroupExpr (MemberInfo [] mi, Location l)
2736 Methods = new MethodBase [mi.Length];
2737 mi.CopyTo (Methods, 0);
2738 eclass = ExprClass.MethodGroup;
2739 type = TypeManager.object_type;
2743 public MethodGroupExpr (ArrayList list, Location l)
2745 Methods = new MethodBase [list.Count];
2748 list.CopyTo (Methods, 0);
2750 foreach (MemberInfo m in list){
2751 if (!(m is MethodBase)){
2752 Console.WriteLine ("Name " + m.Name);
2753 Console.WriteLine ("Found a: " + m.GetType ().FullName);
2760 eclass = ExprClass.MethodGroup;
2761 type = TypeManager.object_type;
2764 public override Type DeclaringType {
2767 // We assume that the top-level type is in the end
2769 return Methods [Methods.Length - 1].DeclaringType;
2770 //return Methods [0].DeclaringType;
2774 public bool HasTypeArguments {
2776 return has_type_arguments;
2780 has_type_arguments = value;
2784 public bool IdenticalTypeName {
2786 return identical_type_name;
2790 identical_type_name = value;
2794 public bool IsBase {
2803 public override string GetSignatureForError ()
2805 return TypeManager.CSharpSignature (Methods [0]);
2808 public override string Name {
2810 return Methods [0].Name;
2814 public override bool IsInstance {
2816 foreach (MethodBase mb in Methods)
2824 public override bool IsStatic {
2826 foreach (MethodBase mb in Methods)
2834 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
2835 SimpleName original)
2837 if (!(left is TypeExpr) &&
2838 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
2839 IdenticalTypeName = true;
2841 return base.ResolveMemberAccess (ec, left, loc, original);
2844 override public Expression DoResolve (EmitContext ec)
2847 InstanceExpression = null;
2849 if (InstanceExpression != null) {
2850 InstanceExpression = InstanceExpression.DoResolve (ec);
2851 if (InstanceExpression == null)
2858 public void ReportUsageError ()
2860 Report.Error (654, loc, "Method `" + DeclaringType + "." +
2861 Name + "()' is referenced without parentheses");
2864 override public void Emit (EmitContext ec)
2866 ReportUsageError ();
2869 bool RemoveMethods (bool keep_static)
2871 ArrayList smethods = new ArrayList ();
2873 foreach (MethodBase mb in Methods){
2874 if (mb.IsStatic == keep_static)
2878 if (smethods.Count == 0)
2881 Methods = new MethodBase [smethods.Count];
2882 smethods.CopyTo (Methods, 0);
2888 /// Removes any instance methods from the MethodGroup, returns
2889 /// false if the resulting set is empty.
2891 public bool RemoveInstanceMethods ()
2893 return RemoveMethods (true);
2897 /// Removes any static methods from the MethodGroup, returns
2898 /// false if the resulting set is empty.
2900 public bool RemoveStaticMethods ()
2902 return RemoveMethods (false);
2905 public Expression ResolveGeneric (EmitContext ec, TypeArguments args)
2907 if (args.Resolve (ec) == false)
2910 Type[] atypes = args.Arguments;
2912 int first_count = 0;
2913 MethodInfo first = null;
2915 ArrayList list = new ArrayList ();
2916 foreach (MethodBase mb in Methods) {
2917 MethodInfo mi = mb as MethodInfo;
2918 if ((mi == null) || !mi.IsGenericMethod)
2921 Type[] gen_params = mi.GetGenericArguments ();
2923 if (first == null) {
2925 first_count = gen_params.Length;
2928 if (gen_params.Length != atypes.Length)
2931 list.Add (mi.MakeGenericMethod (atypes));
2934 if (list.Count > 0) {
2935 MethodGroupExpr new_mg = new MethodGroupExpr (list, Location);
2936 new_mg.InstanceExpression = InstanceExpression;
2937 new_mg.HasTypeArguments = true;
2938 new_mg.IsBase = IsBase;
2944 305, loc, "Using the generic method `{0}' " +
2945 "requires {1} type arguments", Name,
2946 first_count.ToString ());
2949 308, loc, "The non-generic method `{0}' " +
2950 "cannot be used with type arguments", Name);
2957 /// Fully resolved expression that evaluates to a Field
2959 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariable {
2960 public readonly FieldInfo FieldInfo;
2961 VariableInfo variable_info;
2963 LocalTemporary temp;
2965 bool in_initializer;
2967 public FieldExpr (FieldInfo fi, Location l, bool in_initializer):
2970 this.in_initializer = in_initializer;
2973 public FieldExpr (FieldInfo fi, Location l)
2976 eclass = ExprClass.Variable;
2977 type = TypeManager.TypeToCoreType (fi.FieldType);
2981 public override string Name {
2983 return FieldInfo.Name;
2987 public override bool IsInstance {
2989 return !FieldInfo.IsStatic;
2993 public override bool IsStatic {
2995 return FieldInfo.IsStatic;
2999 public override Type DeclaringType {
3001 return FieldInfo.DeclaringType;
3005 public override string GetSignatureForError ()
3007 return TypeManager.GetFullNameSignature (FieldInfo);
3010 public VariableInfo VariableInfo {
3012 return variable_info;
3016 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3017 SimpleName original)
3019 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
3021 Type t = fi.FieldType;
3023 if (fi.IsLiteral || (fi.IsInitOnly && t == TypeManager.decimal_type)) {
3024 IConstant ic = TypeManager.GetConstant (fi);
3027 ic = new ExternalConstant (fi);
3029 ic = ExternalConstant.CreateDecimal (fi);
3031 return base.ResolveMemberAccess (ec, left, loc, original);
3034 TypeManager.RegisterConstant (fi, ic);
3037 bool left_is_type = left is TypeExpr;
3038 if (!left_is_type && (original == null || !original.IdenticalNameAndTypeName (ec, left, loc))) {
3039 Report.SymbolRelatedToPreviousError (FieldInfo);
3040 error176 (loc, TypeManager.GetFullNameSignature (FieldInfo));
3044 if (ic.ResolveValue ()) {
3045 if (!ec.IsInObsoleteScope)
3046 ic.CheckObsoleteness (loc);
3052 if (t.IsPointer && !ec.InUnsafe) {
3057 return base.ResolveMemberAccess (ec, left, loc, original);
3060 override public Expression DoResolve (EmitContext ec)
3062 return DoResolve (ec, false, false);
3065 Expression DoResolve (EmitContext ec, bool lvalue_instance, bool out_access)
3067 if (!FieldInfo.IsStatic){
3068 if (InstanceExpression == null){
3070 // This can happen when referencing an instance field using
3071 // a fully qualified type expression: TypeName.InstanceField = xxx
3073 SimpleName.Error_ObjectRefRequired (ec, loc, FieldInfo.Name);
3077 // Resolve the field's instance expression while flow analysis is turned
3078 // off: when accessing a field "a.b", we must check whether the field
3079 // "a.b" is initialized, not whether the whole struct "a" is initialized.
3081 if (lvalue_instance) {
3082 bool old_do_flow_analysis = ec.DoFlowAnalysis;
3083 ec.DoFlowAnalysis = false;
3084 Expression right_side =
3085 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
3086 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side, loc);
3087 ec.DoFlowAnalysis = old_do_flow_analysis;
3089 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
3090 InstanceExpression = InstanceExpression.Resolve (ec, rf);
3093 if (InstanceExpression == null)
3096 InstanceExpression.CheckMarshalByRefAccess ();
3099 if (!in_initializer && !ec.IsFieldInitializer) {
3100 ObsoleteAttribute oa;
3101 FieldBase f = TypeManager.GetField (FieldInfo);
3103 if (!ec.IsInObsoleteScope)
3104 f.CheckObsoleteness (loc);
3106 // To be sure that type is external because we do not register generated fields
3107 } else if (!(FieldInfo.DeclaringType is TypeBuilder)) {
3108 oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
3110 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
3114 AnonymousContainer am = ec.CurrentAnonymousMethod;
3116 if (!FieldInfo.IsStatic){
3117 if (!am.IsIterator && (ec.TypeContainer is Struct)){
3118 Report.Error (1673, loc,
3119 "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",
3123 if ((am.ContainerAnonymousMethod == null) && (InstanceExpression is This))
3124 ec.CaptureField (this);
3128 // If the instance expression is a local variable or parameter.
3129 IVariable var = InstanceExpression as IVariable;
3130 if ((var == null) || (var.VariableInfo == null))
3133 VariableInfo vi = var.VariableInfo;
3134 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
3137 variable_info = vi.GetSubStruct (FieldInfo.Name);
3141 static readonly int [] codes = {
3142 191, // instance, write access
3143 192, // instance, out access
3144 198, // static, write access
3145 199, // static, out access
3146 1648, // member of value instance, write access
3147 1649, // member of value instance, out access
3148 1650, // member of value static, write access
3149 1651 // member of value static, out access
3152 static readonly string [] msgs = {
3153 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
3154 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
3155 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
3156 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
3157 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
3158 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
3159 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
3160 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
3163 // The return value is always null. Returning a value simplifies calling code.
3164 Expression Report_AssignToReadonly (Expression right_side)
3167 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
3171 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
3173 Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
3178 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3180 IVariable var = InstanceExpression as IVariable;
3181 if ((var != null) && (var.VariableInfo != null))
3182 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
3184 bool lvalue_instance = !FieldInfo.IsStatic && FieldInfo.DeclaringType.IsValueType;
3185 bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
3187 Expression e = DoResolve (ec, lvalue_instance, out_access);
3192 FieldBase fb = TypeManager.GetField (FieldInfo);
3196 if (FieldInfo.IsInitOnly) {
3197 // InitOnly fields can only be assigned in constructors or initializers
3198 if (!ec.IsFieldInitializer && !ec.IsConstructor)
3199 return Report_AssignToReadonly (right_side);
3201 if (ec.IsConstructor) {
3202 Type ctype = ec.TypeContainer.CurrentType;
3204 ctype = ec.ContainerType;
3206 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
3207 if (!TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
3208 return Report_AssignToReadonly (right_side);
3209 // static InitOnly fields cannot be assigned-to in an instance constructor
3210 if (IsStatic && !ec.IsStatic)
3211 return Report_AssignToReadonly (right_side);
3212 // instance constructors can't modify InitOnly fields of other instances of the same type
3213 if (!IsStatic && !(InstanceExpression is This))
3214 return Report_AssignToReadonly (right_side);
3218 if (right_side == EmptyExpression.OutAccess &&
3219 !IsStatic && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
3220 Report.SymbolRelatedToPreviousError (DeclaringType);
3221 Report.Warning (197, 1, loc,
3222 "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",
3223 GetSignatureForError ());
3229 public override void CheckMarshalByRefAccess ()
3231 if (!IsStatic && Type.IsValueType && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
3232 Report.SymbolRelatedToPreviousError (DeclaringType);
3233 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",
3234 GetSignatureForError ());
3238 public bool VerifyFixed ()
3240 IVariable variable = InstanceExpression as IVariable;
3241 // A variable of the form V.I is fixed when V is a fixed variable of a struct type.
3242 // We defer the InstanceExpression check after the variable check to avoid a
3243 // separate null check on InstanceExpression.
3244 return variable != null && InstanceExpression.Type.IsValueType && variable.VerifyFixed ();
3247 public override int GetHashCode ()
3249 return FieldInfo.GetHashCode ();
3252 public override bool Equals (object obj)
3254 FieldExpr fe = obj as FieldExpr;
3258 if (FieldInfo != fe.FieldInfo)
3261 if (InstanceExpression == null || fe.InstanceExpression == null)
3264 return InstanceExpression.Equals (fe.InstanceExpression);
3267 public void Emit (EmitContext ec, bool leave_copy)
3269 ILGenerator ig = ec.ig;
3270 bool is_volatile = false;
3272 FieldBase f = TypeManager.GetField (FieldInfo);
3274 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
3277 f.SetMemberIsUsed ();
3280 if (FieldInfo.IsStatic){
3282 ig.Emit (OpCodes.Volatile);
3284 ig.Emit (OpCodes.Ldsfld, FieldInfo);
3287 EmitInstance (ec, false);
3290 ig.Emit (OpCodes.Volatile);
3292 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
3295 ig.Emit (OpCodes.Ldflda, FieldInfo);
3296 ig.Emit (OpCodes.Ldflda, ff.Element);
3299 ig.Emit (OpCodes.Ldfld, FieldInfo);
3304 ec.ig.Emit (OpCodes.Dup);
3305 if (!FieldInfo.IsStatic) {
3306 temp = new LocalTemporary (this.Type);
3312 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
3314 FieldAttributes fa = FieldInfo.Attributes;
3315 bool is_static = (fa & FieldAttributes.Static) != 0;
3316 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
3317 ILGenerator ig = ec.ig;
3318 prepared = prepare_for_load;
3320 if (is_readonly && !ec.IsConstructor){
3321 Report_AssignToReadonly (source);
3325 EmitInstance (ec, prepare_for_load);
3329 ec.ig.Emit (OpCodes.Dup);
3330 if (!FieldInfo.IsStatic) {
3331 temp = new LocalTemporary (this.Type);
3336 if (FieldInfo is FieldBuilder){
3337 FieldBase f = TypeManager.GetField (FieldInfo);
3339 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
3340 ig.Emit (OpCodes.Volatile);
3347 ig.Emit (OpCodes.Stsfld, FieldInfo);
3349 ig.Emit (OpCodes.Stfld, FieldInfo);
3355 public override void Emit (EmitContext ec)
3360 public void AddressOf (EmitContext ec, AddressOp mode)
3362 ILGenerator ig = ec.ig;
3364 if (FieldInfo is FieldBuilder){
3365 FieldBase f = TypeManager.GetField (FieldInfo);
3367 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
3368 Report.Warning (420, 1, loc, "`{0}': A volatile fields cannot be passed using a ref or out parameter",
3369 f.GetSignatureForError ());
3373 if ((mode & AddressOp.Store) != 0)
3375 if ((mode & AddressOp.Load) != 0)
3376 f.SetMemberIsUsed ();
3381 // Handle initonly fields specially: make a copy and then
3382 // get the address of the copy.
3385 if (FieldInfo.IsInitOnly){
3387 if (ec.IsConstructor){
3388 if (FieldInfo.IsStatic){
3400 local = ig.DeclareLocal (type);
3401 ig.Emit (OpCodes.Stloc, local);
3402 ig.Emit (OpCodes.Ldloca, local);
3407 if (FieldInfo.IsStatic){
3408 ig.Emit (OpCodes.Ldsflda, FieldInfo);
3411 EmitInstance (ec, false);
3412 ig.Emit (OpCodes.Ldflda, FieldInfo);
3418 // A FieldExpr whose address can not be taken
3420 public class FieldExprNoAddress : FieldExpr, IMemoryLocation {
3421 public FieldExprNoAddress (FieldInfo fi, Location loc) : base (fi, loc)
3425 public new void AddressOf (EmitContext ec, AddressOp mode)
3427 Report.Error (-215, "Report this: Taking the address of a remapped parameter not supported");
3432 /// Expression that evaluates to a Property. The Assign class
3433 /// might set the `Value' expression if we are in an assignment.
3435 /// This is not an LValue because we need to re-write the expression, we
3436 /// can not take data from the stack and store it.
3438 public class PropertyExpr : MemberExpr, IAssignMethod {
3439 public readonly PropertyInfo PropertyInfo;
3442 // This is set externally by the `BaseAccess' class
3445 MethodInfo getter, setter;
3450 LocalTemporary temp;
3453 internal static PtrHashtable AccessorTable = new PtrHashtable ();
3455 public PropertyExpr (Type containerType, PropertyInfo pi, Location l)
3458 eclass = ExprClass.PropertyAccess;
3462 type = TypeManager.TypeToCoreType (pi.PropertyType);
3464 ResolveAccessors (containerType);
3467 public override string Name {
3469 return PropertyInfo.Name;
3473 public override bool IsInstance {
3479 public override bool IsStatic {
3485 public override Type DeclaringType {
3487 return PropertyInfo.DeclaringType;
3491 public override string GetSignatureForError ()
3493 return TypeManager.GetFullNameSignature (PropertyInfo);
3496 void FindAccessors (Type invocation_type)
3498 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
3499 BindingFlags.Static | BindingFlags.Instance |
3500 BindingFlags.DeclaredOnly;
3502 Type current = PropertyInfo.DeclaringType;
3503 for (; current != null; current = current.BaseType) {
3504 MemberInfo[] group = TypeManager.MemberLookup (
3505 invocation_type, invocation_type, current,
3506 MemberTypes.Property, flags, PropertyInfo.Name, null);
3511 if (group.Length != 1)
3512 // Oooops, can this ever happen ?
3515 PropertyInfo pi = (PropertyInfo) group [0];
3518 getter = pi.GetGetMethod (true);
3521 setter = pi.GetSetMethod (true);
3523 MethodInfo accessor = getter != null ? getter : setter;
3525 if (!accessor.IsVirtual)
3531 // We also perform the permission checking here, as the PropertyInfo does not
3532 // hold the information for the accessibility of its setter/getter
3534 // TODO: can use TypeManager.GetProperty to boost performance
3535 void ResolveAccessors (Type containerType)
3537 FindAccessors (containerType);
3539 if (getter != null) {
3540 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
3541 IMethodData md = TypeManager.GetMethod (the_getter);
3543 md.SetMemberIsUsed ();
3545 AccessorTable [getter] = PropertyInfo;
3546 is_static = getter.IsStatic;
3549 if (setter != null) {
3550 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
3551 IMethodData md = TypeManager.GetMethod (the_setter);
3553 md.SetMemberIsUsed ();
3555 AccessorTable [setter] = PropertyInfo;
3556 is_static = setter.IsStatic;
3560 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
3563 InstanceExpression = null;
3567 if (InstanceExpression == null) {
3568 SimpleName.Error_ObjectRefRequired (ec, loc, PropertyInfo.Name);
3572 if (lvalue_instance)
3573 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
3575 InstanceExpression = InstanceExpression.DoResolve (ec);
3576 if (InstanceExpression == null)
3579 InstanceExpression.CheckMarshalByRefAccess ();
3581 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
3582 InstanceExpression.Type != ec.ContainerType &&
3583 ec.ContainerType.IsSubclassOf (PropertyInfo.DeclaringType) &&
3584 !InstanceExpression.Type.IsSubclassOf (ec.ContainerType)) {
3585 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
3592 void Error_PropertyNotFound (MethodInfo mi, bool getter)
3594 // TODO: correctly we should compare arguments but it will lead to bigger changes
3595 if (mi is MethodBuilder) {
3596 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
3600 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
3602 ParameterData iparams = TypeManager.GetParameterData (mi);
3603 sig.Append (getter ? "get_" : "set_");
3605 sig.Append (iparams.GetSignatureForError ());
3607 Report.SymbolRelatedToPreviousError (mi);
3608 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
3609 Name, sig.ToString ());
3612 override public Expression DoResolve (EmitContext ec)
3617 if (getter != null){
3618 if (TypeManager.GetParameterData (getter).Count != 0){
3619 Error_PropertyNotFound (getter, true);
3624 if (getter == null){
3626 // The following condition happens if the PropertyExpr was
3627 // created, but is invalid (ie, the property is inaccessible),
3628 // and we did not want to embed the knowledge about this in
3629 // the caller routine. This only avoids double error reporting.
3634 if (InstanceExpression != EmptyExpression.Null) {
3635 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
3636 TypeManager.GetFullNameSignature (PropertyInfo));
3641 bool must_do_cs1540_check = false;
3642 if (getter != null &&
3643 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
3644 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
3645 if (pm != null && pm.HasCustomAccessModifier) {
3646 Report.SymbolRelatedToPreviousError (pm);
3647 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
3648 TypeManager.CSharpSignature (getter));
3651 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
3655 if (!InstanceResolve (ec, false, must_do_cs1540_check))
3659 // Only base will allow this invocation to happen.
3661 if (IsBase && getter.IsAbstract) {
3662 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
3666 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
3676 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3678 if (right_side == EmptyExpression.OutAccess) {
3679 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
3680 GetSignatureForError ());
3684 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
3685 Report.Error (1612, loc, "Cannot modify the return value of `{0}' because it is not a variable",
3686 GetSignatureForError ());
3690 if (setter == null){
3692 // The following condition happens if the PropertyExpr was
3693 // created, but is invalid (ie, the property is inaccessible),
3694 // and we did not want to embed the knowledge about this in
3695 // the caller routine. This only avoids double error reporting.
3699 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
3700 GetSignatureForError ());
3704 if (TypeManager.GetParameterData (setter).Count != 1){
3705 Error_PropertyNotFound (setter, false);
3709 bool must_do_cs1540_check;
3710 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
3711 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
3712 if (pm != null && pm.HasCustomAccessModifier) {
3713 Report.SymbolRelatedToPreviousError (pm);
3714 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
3715 TypeManager.CSharpSignature (setter));
3718 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
3722 if (!InstanceResolve (ec, PropertyInfo.DeclaringType.IsValueType, must_do_cs1540_check))
3726 // Only base will allow this invocation to happen.
3728 if (IsBase && setter.IsAbstract){
3729 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
3736 public override void Emit (EmitContext ec)
3741 public void Emit (EmitContext ec, bool leave_copy)
3744 // Special case: length of single dimension array property is turned into ldlen
3746 if ((getter == TypeManager.system_int_array_get_length) ||
3747 (getter == TypeManager.int_array_get_length)){
3748 Type iet = InstanceExpression.Type;
3751 // System.Array.Length can be called, but the Type does not
3752 // support invoking GetArrayRank, so test for that case first
3754 if (iet != TypeManager.array_type && (iet.GetArrayRank () == 1)) {
3756 EmitInstance (ec, false);
3757 ec.ig.Emit (OpCodes.Ldlen);
3758 ec.ig.Emit (OpCodes.Conv_I4);
3763 Invocation.EmitCall (ec, IsBase, IsStatic, InstanceExpression, getter, null, loc, prepared, false);
3766 ec.ig.Emit (OpCodes.Dup);
3768 temp = new LocalTemporary (this.Type);
3775 // Implements the IAssignMethod interface for assignments
3777 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
3779 Expression my_source = source;
3781 prepared = prepare_for_load;
3786 ec.ig.Emit (OpCodes.Dup);
3788 temp = new LocalTemporary (this.Type);
3792 } else if (leave_copy) {
3795 temp = new LocalTemporary (this.Type);
3801 ArrayList args = new ArrayList (1);
3802 args.Add (new Argument (my_source, Argument.AType.Expression));
3804 Invocation.EmitCall (ec, IsBase, IsStatic, InstanceExpression, setter, args, loc, false, prepared);
3812 /// Fully resolved expression that evaluates to an Event
3814 public class EventExpr : MemberExpr {
3815 public readonly EventInfo EventInfo;
3818 MethodInfo add_accessor, remove_accessor;
3820 public EventExpr (EventInfo ei, Location loc)
3824 eclass = ExprClass.EventAccess;
3826 add_accessor = TypeManager.GetAddMethod (ei);
3827 remove_accessor = TypeManager.GetRemoveMethod (ei);
3829 if (add_accessor.IsStatic || remove_accessor.IsStatic)
3832 if (EventInfo is MyEventBuilder){
3833 MyEventBuilder eb = (MyEventBuilder) EventInfo;
3834 type = eb.EventType;
3837 type = EventInfo.EventHandlerType;
3840 public override string Name {
3842 return EventInfo.Name;
3846 public override bool IsInstance {
3852 public override bool IsStatic {
3858 public override Type DeclaringType {
3860 return EventInfo.DeclaringType;
3864 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3865 SimpleName original)
3868 // If the event is local to this class, we transform ourselves into a FieldExpr
3871 if (EventInfo.DeclaringType == ec.ContainerType ||
3872 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
3873 MemberInfo mi = TypeManager.GetPrivateFieldOfEvent (EventInfo);
3876 MemberExpr ml = (MemberExpr) ExprClassFromMemberInfo (ec.ContainerType, mi, loc);
3879 Report.Error (-200, loc, "Internal error!!");
3883 InstanceExpression = null;
3885 return ml.ResolveMemberAccess (ec, left, loc, original);
3889 return base.ResolveMemberAccess (ec, left, loc, original);
3893 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
3896 InstanceExpression = null;
3900 if (InstanceExpression == null) {
3901 SimpleName.Error_ObjectRefRequired (ec, loc, EventInfo.Name);
3905 InstanceExpression = InstanceExpression.DoResolve (ec);
3906 if (InstanceExpression == null)
3910 // This is using the same mechanism as the CS1540 check in PropertyExpr.
3911 // However, in the Event case, we reported a CS0122 instead.
3913 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
3914 InstanceExpression.Type != ec.ContainerType &&
3915 ec.ContainerType.IsSubclassOf (InstanceExpression.Type)) {
3916 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
3923 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
3925 return DoResolve (ec);
3928 public override Expression DoResolve (EmitContext ec)
3930 bool must_do_cs1540_check;
3931 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
3932 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
3933 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
3937 if (!InstanceResolve (ec, must_do_cs1540_check))
3943 public override void Emit (EmitContext ec)
3945 if (InstanceExpression is This)
3946 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of += or -=", GetSignatureForError ());
3948 Report.Error (70, loc, "The event `{0}' can only appear on the left hand side of += or -= "+
3949 "(except on the defining type)", Name);
3952 public override string GetSignatureForError ()
3954 return TypeManager.CSharpSignature (EventInfo);
3957 public void EmitAddOrRemove (EmitContext ec, Expression source)
3959 BinaryDelegate source_del = (BinaryDelegate) source;
3960 Expression handler = source_del.Right;
3962 Argument arg = new Argument (handler, Argument.AType.Expression);
3963 ArrayList args = new ArrayList ();
3967 if (source_del.IsAddition)
3968 Invocation.EmitCall (
3969 ec, false, IsStatic, InstanceExpression, add_accessor, args, loc);
3971 Invocation.EmitCall (
3972 ec, false, IsStatic, InstanceExpression, remove_accessor, args, loc);
3977 public class TemporaryVariable : Expression, IMemoryLocation
3981 public TemporaryVariable (Type type, Location loc)
3985 eclass = ExprClass.Value;
3988 public override Expression DoResolve (EmitContext ec)
3993 TypeExpr te = new TypeExpression (type, loc);
3994 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
3995 if (!li.Resolve (ec))
3998 AnonymousContainer am = ec.CurrentAnonymousMethod;
3999 if ((am != null) && am.IsIterator)
4000 ec.CaptureVariable (li);
4005 public override void Emit (EmitContext ec)
4007 ILGenerator ig = ec.ig;
4009 if (li.FieldBuilder != null) {
4010 ig.Emit (OpCodes.Ldarg_0);
4011 ig.Emit (OpCodes.Ldfld, li.FieldBuilder);
4013 ig.Emit (OpCodes.Ldloc, li.LocalBuilder);
4017 public void EmitLoadAddress (EmitContext ec)
4019 ILGenerator ig = ec.ig;
4021 if (li.FieldBuilder != null) {
4022 ig.Emit (OpCodes.Ldarg_0);
4023 ig.Emit (OpCodes.Ldflda, li.FieldBuilder);
4025 ig.Emit (OpCodes.Ldloca, li.LocalBuilder);
4029 public void Store (EmitContext ec, Expression right_side)
4031 if (li.FieldBuilder != null)
4032 ec.ig.Emit (OpCodes.Ldarg_0);
4034 right_side.Emit (ec);
4035 if (li.FieldBuilder != null) {
4036 ec.ig.Emit (OpCodes.Stfld, li.FieldBuilder);
4038 ec.ig.Emit (OpCodes.Stloc, li.LocalBuilder);
4042 public void EmitThis (EmitContext ec)
4044 if (li.FieldBuilder != null) {
4045 ec.ig.Emit (OpCodes.Ldarg_0);
4049 public void EmitStore (ILGenerator ig)
4051 if (li.FieldBuilder != null)
4052 ig.Emit (OpCodes.Stfld, li.FieldBuilder);
4054 ig.Emit (OpCodes.Stloc, li.LocalBuilder);
4057 public void AddressOf (EmitContext ec, AddressOp mode)
4059 EmitLoadAddress (ec);