2 // ecore.cs: Core of the Expression representation for the intermediate tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@seznam.cz)
8 // (C) 2001, 2002, 2003 Ximian, Inc.
12 namespace Mono.CSharp {
14 using System.Collections;
15 using System.Diagnostics;
16 using System.Reflection;
17 using System.Reflection.Emit;
21 /// The ExprClass class contains the is used to pass the
22 /// classification of an expression (value, variable, namespace,
23 /// type, method group, property access, event access, indexer access,
26 public enum ExprClass : byte {
41 /// This is used to tell Resolve in which types of expressions we're
45 public enum ResolveFlags {
46 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
49 // Returns a type expression.
52 // Returns a method group.
55 // Mask of all the expression class flags.
58 // Disable control flow analysis while resolving the expression.
59 // This is used when resolving the instance expression of a field expression.
60 DisableFlowAnalysis = 8,
62 // Set if this is resolving the first part of a MemberAccess.
65 // Disable control flow analysis _of struct_ while resolving the expression.
66 // This is used when resolving the instance expression of a field expression.
67 DisableStructFlowAnalysis = 32,
72 // This is just as a hint to AddressOf of what will be done with the
75 public enum AddressOp {
82 /// This interface is implemented by variables
84 public interface IMemoryLocation {
86 /// The AddressOf method should generate code that loads
87 /// the address of the object and leaves it on the stack.
89 /// The `mode' argument is used to notify the expression
90 /// of whether this will be used to read from the address or
91 /// write to the address.
93 /// This is just a hint that can be used to provide good error
94 /// reporting, and should have no other side effects.
96 void AddressOf (EmitContext ec, AddressOp mode);
100 /// This interface is implemented by variables
102 public interface IVariable {
103 VariableInfo VariableInfo {
111 /// Base class for expressions
113 public abstract class Expression {
114 public ExprClass eclass;
116 protected Location loc;
120 set { type = value; }
123 public virtual Location Location {
128 /// Utility wrapper routine for Error, just to beautify the code
130 public void Error (int error, string s)
132 Report.Error (error, loc, s);
135 // Not nice but we have broken hierarchy.
136 public virtual void CheckMarshalByRefAccess ()
140 public virtual bool GetAttributableValue (Type valueType, out object value)
142 Attribute.Error_AttributeArgumentNotValid (loc);
147 public virtual string GetSignatureForError ()
149 return TypeManager.CSharpName (type);
152 public static bool IsAccessorAccessible (Type invocation_type, MethodInfo mi, out bool must_do_cs1540_check)
154 MethodAttributes ma = mi.Attributes & MethodAttributes.MemberAccessMask;
156 must_do_cs1540_check = false; // by default we do not check for this
158 if (ma == MethodAttributes.Public)
162 // If only accessible to the current class or children
164 if (ma == MethodAttributes.Private)
165 return TypeManager.IsPrivateAccessible (invocation_type, mi.DeclaringType) ||
166 TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType);
168 if (mi.DeclaringType.Assembly == invocation_type.Assembly ||
169 TypeManager.IsFriendAssembly (mi.DeclaringType.Assembly)) {
170 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamORAssem)
173 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamANDAssem)
177 // Family and FamANDAssem require that we derive.
178 // FamORAssem requires that we derive if in different assemblies.
179 if (!TypeManager.IsNestedFamilyAccessible (invocation_type, mi.DeclaringType))
182 if (!TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType))
183 must_do_cs1540_check = true;
189 /// Performs semantic analysis on the Expression
193 /// The Resolve method is invoked to perform the semantic analysis
196 /// The return value is an expression (it can be the
197 /// same expression in some cases) or a new
198 /// expression that better represents this node.
200 /// For example, optimizations of Unary (LiteralInt)
201 /// would return a new LiteralInt with a negated
204 /// If there is an error during semantic analysis,
205 /// then an error should be reported (using Report)
206 /// and a null value should be returned.
208 /// There are two side effects expected from calling
209 /// Resolve(): the the field variable "eclass" should
210 /// be set to any value of the enumeration
211 /// `ExprClass' and the type variable should be set
212 /// to a valid type (this is the type of the
215 public abstract Expression DoResolve (EmitContext ec);
217 public virtual Expression DoResolveLValue (EmitContext ec, Expression right_side)
223 // This is used if the expression should be resolved as a type or namespace name.
224 // the default implementation fails.
226 public virtual FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
232 // This is used to resolve the expression as a type, a null
233 // value will be returned if the expression is not a type
236 public virtual TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
238 TypeExpr te = ResolveAsBaseTerminal (ec, silent);
242 ObsoleteAttribute obsolete_attr = AttributeTester.GetObsoleteAttribute (te.Type);
243 if (obsolete_attr != null && !ec.IsInObsoleteScope) {
244 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location);
247 // Constrains don't need to be checked for overrides
248 GenericMethod gm = ec.GenericDeclContainer as GenericMethod;
249 if (gm != null && (gm.ModFlags & Modifiers.OVERRIDE) != 0) {
254 ConstructedType ct = te as ConstructedType;
255 if ((ct != null) && !ct.CheckConstraints (ec))
261 public TypeExpr ResolveAsBaseTerminal (IResolveContext ec, bool silent)
263 int errors = Report.Errors;
265 FullNamedExpression fne = ResolveAsTypeStep (ec, silent);
268 if (!silent && errors == Report.Errors)
269 Report.Error (118, loc, "Expecting a type.");
273 if (fne.eclass != ExprClass.Type) {
274 if (!silent && errors == Report.Errors)
275 fne.Error_UnexpectedKind (null, "type", loc);
279 TypeExpr te = fne as TypeExpr;
281 if (!te.CheckAccessLevel (ec.DeclContainer)) {
282 Report.SymbolRelatedToPreviousError (te.Type);
283 ErrorIsInaccesible (loc, TypeManager.CSharpName (te.Type));
291 public static void ErrorIsInaccesible (Location loc, string name)
293 Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", name);
296 protected static void Error_CannotAccessProtected (Location loc, MemberInfo m, Type qualifier, Type container)
298 Report.Error (1540, loc, "Cannot access protected member `{0}' via a qualifier of type `{1}';"
299 + " the qualifier must be of type `{2}' (or derived from it)",
300 TypeManager.GetFullNameSignature (m),
301 TypeManager.CSharpName (qualifier),
302 TypeManager.CSharpName (container));
306 public static void Error_VoidInvalidInTheContext (Location loc)
308 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
311 public virtual void Error_ValueCannotBeConverted (Location loc, Type target, bool expl)
313 if (Type.FullName == target.FullName){
314 Report.ExtraInformation (loc,
316 "The type {0} has two conflicting definitions, one comes from {1} and the other from {2}",
317 Type.FullName, Type.Assembly.FullName, target.Assembly.FullName));
322 Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
323 GetSignatureForError (), TypeManager.CSharpName (target));
327 Expression e = (this is EnumConstant) ? ((EnumConstant)this).Child : this;
328 bool b = Convert.ExplicitNumericConversion (e, target) != null;
330 if (b || Convert.ExplicitReferenceConversionExists (Type, target) || Convert.ExplicitUnsafe (e, target) != null) {
331 Report.Error (266, loc, "Cannot implicitly convert type `{0}' to `{1}'. An explicit conversion exists (are you missing a cast?)",
332 TypeManager.CSharpName (Type), TypeManager.CSharpName (target));
336 if (Type != TypeManager.string_type && this is Constant && !(this is NullCast)) {
337 Report.Error (31, loc, "Constant value `{0}' cannot be converted to a `{1}'",
338 GetSignatureForError (), TypeManager.CSharpName (target));
342 Report.Error (29, loc, "Cannot implicitly convert type {0} to `{1}'",
343 Type == TypeManager.anonymous_method_type ?
344 "anonymous method" : "`" + GetSignatureForError () + "'",
345 TypeManager.CSharpName (target));
348 protected static void Error_TypeDoesNotContainDefinition (Location loc, Type type, string name)
350 Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
351 TypeManager.CSharpName (type), name);
354 ResolveFlags ExprClassToResolveFlags
359 case ExprClass.Namespace:
360 return ResolveFlags.Type;
362 case ExprClass.MethodGroup:
363 return ResolveFlags.MethodGroup;
365 case ExprClass.Value:
366 case ExprClass.Variable:
367 case ExprClass.PropertyAccess:
368 case ExprClass.EventAccess:
369 case ExprClass.IndexerAccess:
370 return ResolveFlags.VariableOrValue;
373 throw new Exception ("Expression " + GetType () +
374 " ExprClass is Invalid after resolve");
380 /// Resolves an expression and performs semantic analysis on it.
384 /// Currently Resolve wraps DoResolve to perform sanity
385 /// checking and assertion checking on what we expect from Resolve.
387 public Expression Resolve (EmitContext ec, ResolveFlags flags)
389 if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type)
390 return ResolveAsTypeStep (ec, false);
392 bool do_flow_analysis = ec.DoFlowAnalysis;
393 bool omit_struct_analysis = ec.OmitStructFlowAnalysis;
394 if ((flags & ResolveFlags.DisableFlowAnalysis) != 0)
395 do_flow_analysis = false;
396 if ((flags & ResolveFlags.DisableStructFlowAnalysis) != 0)
397 omit_struct_analysis = true;
400 using (ec.WithFlowAnalysis (do_flow_analysis, omit_struct_analysis)) {
401 if (this is SimpleName) {
402 bool intermediate = (flags & ResolveFlags.Intermediate) == ResolveFlags.Intermediate;
403 e = ((SimpleName) this).DoResolve (ec, intermediate);
412 if ((flags & e.ExprClassToResolveFlags) == 0) {
413 e.Error_UnexpectedKind (flags, loc);
417 if (e.type == null && !(e is Namespace)) {
418 throw new Exception (
419 "Expression " + e.GetType () +
420 " did not set its type after Resolve\n" +
421 "called from: " + this.GetType ());
428 /// Resolves an expression and performs semantic analysis on it.
430 public Expression Resolve (EmitContext ec)
432 Expression e = Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
434 if (e != null && e.eclass == ExprClass.MethodGroup && RootContext.Version == LanguageVersion.ISO_1) {
435 ((MethodGroupExpr) e).ReportUsageError ();
441 public Constant ResolveAsConstant (EmitContext ec, MemberCore mc)
443 Expression e = Resolve (ec);
447 Constant c = e as Constant;
451 Type constant_type = null;
452 if (mc is MemberBase) {
453 constant_type = ((MemberBase)mc).MemberType;
456 Const.Error_ExpressionMustBeConstant (constant_type, loc, mc.GetSignatureForError ());
461 /// Resolves an expression for LValue assignment
465 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
466 /// checking and assertion checking on what we expect from Resolve
468 public Expression ResolveLValue (EmitContext ec, Expression right_side, Location loc)
470 int errors = Report.Errors;
471 bool out_access = right_side == EmptyExpression.OutAccess;
473 Expression e = DoResolveLValue (ec, right_side);
475 if (e != null && out_access && !(e is IMemoryLocation)) {
476 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
477 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
479 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
480 // e.GetType () + " " + e.GetSignatureForError ());
485 if (errors == Report.Errors) {
487 Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
489 Report.Error (131, loc, "The left-hand side of an assignment or mutating operation must be a variable, property or indexer");
494 if (e.eclass == ExprClass.Invalid)
495 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
497 if (e.eclass == ExprClass.MethodGroup) {
498 ((MethodGroupExpr) e).ReportUsageError ();
502 if ((e.type == null) && !(e is ConstructedType))
503 throw new Exception ("Expression " + e + " did not set its type after Resolve");
509 /// Emits the code for the expression
513 /// The Emit method is invoked to generate the code
514 /// for the expression.
516 public abstract void Emit (EmitContext ec);
518 public virtual void EmitBranchable (EmitContext ec, Label target, bool onTrue)
521 ec.ig.Emit (onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target);
525 /// Protected constructor. Only derivate types should
526 /// be able to be created
529 protected Expression ()
531 eclass = ExprClass.Invalid;
536 /// Returns a literalized version of a literal FieldInfo
540 /// The possible return values are:
541 /// IntConstant, UIntConstant
542 /// LongLiteral, ULongConstant
543 /// FloatConstant, DoubleConstant
546 /// The value returned is already resolved.
548 public static Constant Constantify (object v, Type t)
550 if (t == TypeManager.int32_type)
551 return new IntConstant ((int) v, Location.Null);
552 else if (t == TypeManager.uint32_type)
553 return new UIntConstant ((uint) v, Location.Null);
554 else if (t == TypeManager.int64_type)
555 return new LongConstant ((long) v, Location.Null);
556 else if (t == TypeManager.uint64_type)
557 return new ULongConstant ((ulong) v, Location.Null);
558 else if (t == TypeManager.float_type)
559 return new FloatConstant ((float) v, Location.Null);
560 else if (t == TypeManager.double_type)
561 return new DoubleConstant ((double) v, Location.Null);
562 else if (t == TypeManager.string_type)
563 return new StringConstant ((string) v, Location.Null);
564 else if (t == TypeManager.short_type)
565 return new ShortConstant ((short)v, Location.Null);
566 else if (t == TypeManager.ushort_type)
567 return new UShortConstant ((ushort)v, Location.Null);
568 else if (t == TypeManager.sbyte_type)
569 return new SByteConstant ((sbyte)v, Location.Null);
570 else if (t == TypeManager.byte_type)
571 return new ByteConstant ((byte)v, Location.Null);
572 else if (t == TypeManager.char_type)
573 return new CharConstant ((char)v, Location.Null);
574 else if (t == TypeManager.bool_type)
575 return new BoolConstant ((bool) v, Location.Null);
576 else if (t == TypeManager.decimal_type)
577 return new DecimalConstant ((decimal) v, Location.Null);
578 else if (TypeManager.IsEnumType (t)){
579 Type real_type = TypeManager.TypeToCoreType (v.GetType ());
581 real_type = System.Enum.GetUnderlyingType (real_type);
583 Constant e = Constantify (v, real_type);
585 return new EnumConstant (e, t);
586 } else if (v == null && !TypeManager.IsValueType (t))
587 return new NullLiteral (Location.Null);
589 throw new Exception ("Unknown type for constant (" + t +
594 /// Returns a fully formed expression after a MemberLookup
597 public static Expression ExprClassFromMemberInfo (Type containerType, MemberInfo mi, Location loc)
600 return new EventExpr ((EventInfo) mi, loc);
601 else if (mi is FieldInfo)
602 return new FieldExpr ((FieldInfo) mi, loc);
603 else if (mi is PropertyInfo)
604 return new PropertyExpr (containerType, (PropertyInfo) mi, loc);
605 else if (mi is Type){
606 return new TypeExpression ((System.Type) mi, loc);
612 protected static ArrayList almostMatchedMembers = new ArrayList (4);
615 // FIXME: Probably implement a cache for (t,name,current_access_set)?
617 // This code could use some optimizations, but we need to do some
618 // measurements. For example, we could use a delegate to `flag' when
619 // something can not any longer be a method-group (because it is something
623 // If the return value is an Array, then it is an array of
626 // If the return value is an MemberInfo, it is anything, but a Method
630 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
631 // the arguments here and have MemberLookup return only the methods that
632 // match the argument count/type, unlike we are doing now (we delay this
635 // This is so we can catch correctly attempts to invoke instance methods
636 // from a static body (scan for error 120 in ResolveSimpleName).
639 // FIXME: Potential optimization, have a static ArrayList
642 public static Expression MemberLookup (Type container_type, Type queried_type, string name,
643 MemberTypes mt, BindingFlags bf, Location loc)
645 return MemberLookup (container_type, null, queried_type, name, mt, bf, loc);
649 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
650 // `qualifier_type' or null to lookup members in the current class.
653 public static Expression MemberLookup (Type container_type,
654 Type qualifier_type, Type queried_type,
655 string name, MemberTypes mt,
656 BindingFlags bf, Location loc)
658 almostMatchedMembers.Clear ();
660 MemberInfo [] mi = TypeManager.MemberLookup (container_type, qualifier_type,
661 queried_type, mt, bf, name, almostMatchedMembers);
667 bool is_interface = qualifier_type != null && qualifier_type.IsInterface;
668 MemberInfo non_method = null;
669 ArrayList methods = new ArrayList (2);
671 foreach (MemberInfo m in mi) {
672 if (m is MethodBase) {
677 if (non_method == null) {
685 Report.SymbolRelatedToPreviousError (m);
686 Report.SymbolRelatedToPreviousError (non_method);
687 Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
688 TypeManager.GetFullNameSignature (m), TypeManager.GetFullNameSignature (non_method));
692 if (non_method != null && is_interface) {
693 MethodBase method = (MethodBase)methods[0];
694 Report.SymbolRelatedToPreviousError (method);
695 Report.SymbolRelatedToPreviousError (non_method);
696 Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and non-method `{1}'. Using method `{0}'",
697 TypeManager.CSharpSignature (method), TypeManager.GetFullNameSignature (non_method));
700 if (methods.Count == 0)
701 return new MethodGroupExpr (mi, loc);
703 return new MethodGroupExpr (methods, loc);
706 if (mi [0] is MethodBase)
707 return new MethodGroupExpr (mi, loc);
709 return ExprClassFromMemberInfo (container_type, mi [0], loc);
712 public const MemberTypes AllMemberTypes =
713 MemberTypes.Constructor |
717 MemberTypes.NestedType |
718 MemberTypes.Property;
720 public const BindingFlags AllBindingFlags =
721 BindingFlags.Public |
722 BindingFlags.Static |
723 BindingFlags.Instance;
725 public static Expression MemberLookup (Type container_type, Type queried_type,
726 string name, Location loc)
728 return MemberLookup (container_type, null, queried_type, name,
729 AllMemberTypes, AllBindingFlags, loc);
732 public static Expression MemberLookup (Type container_type, Type qualifier_type,
733 Type queried_type, string name, Location loc)
735 return MemberLookup (container_type, qualifier_type, queried_type,
736 name, AllMemberTypes, AllBindingFlags, loc);
739 public static Expression MethodLookup (EmitContext ec, Type queried_type,
740 string name, Location loc)
742 return MemberLookup (ec.ContainerType, null, queried_type, name,
743 MemberTypes.Method, AllBindingFlags, loc);
747 /// This is a wrapper for MemberLookup that is not used to "probe", but
748 /// to find a final definition. If the final definition is not found, we
749 /// look for private members and display a useful debugging message if we
752 public static Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
753 Type queried_type, string name, Location loc)
755 return MemberLookupFinal (ec, qualifier_type, queried_type, name,
756 AllMemberTypes, AllBindingFlags, loc);
759 public static Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
760 Type queried_type, string name,
761 MemberTypes mt, BindingFlags bf,
766 int errors = Report.Errors;
768 e = MemberLookup (ec.ContainerType, qualifier_type, queried_type, name, mt, bf, loc);
770 if (e == null && errors == Report.Errors)
771 // No errors were reported by MemberLookup, but there was an error.
772 MemberLookupFailed (ec.ContainerType, qualifier_type, queried_type, name, null, true, loc);
777 public static void MemberLookupFailed (Type container_type, Type qualifier_type,
778 Type queried_type, string name,
779 string class_name, bool complain_if_none_found,
782 if (almostMatchedMembers.Count != 0) {
783 for (int i = 0; i < almostMatchedMembers.Count; ++i) {
784 MemberInfo m = (MemberInfo) almostMatchedMembers [i];
785 for (int j = 0; j < i; ++j) {
786 if (m == almostMatchedMembers [j]) {
794 Type declaring_type = m.DeclaringType;
796 Report.SymbolRelatedToPreviousError (m);
797 if (qualifier_type == null) {
798 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
799 TypeManager.CSharpName (m.DeclaringType),
800 TypeManager.CSharpName (container_type));
802 } else if (qualifier_type != container_type &&
803 TypeManager.IsNestedFamilyAccessible (container_type, declaring_type)) {
804 // Although a derived class can access protected members of
805 // its base class it cannot do so through an instance of the
806 // base class (CS1540). If the qualifier_type is a base of the
807 // ec.ContainerType and the lookup succeeds with the latter one,
808 // then we are in this situation.
809 Error_CannotAccessProtected (loc, m, qualifier_type, container_type);
811 Report.SymbolRelatedToPreviousError (m);
812 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (m));
815 almostMatchedMembers.Clear ();
819 MemberInfo[] lookup = null;
820 if (queried_type == null) {
821 class_name = "global::";
823 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
824 AllMemberTypes, AllBindingFlags |
825 BindingFlags.NonPublic, name, null);
828 if (lookup == null) {
829 if (!complain_if_none_found)
832 if (class_name != null)
833 Report.Error (103, loc, "The name `{0}' does not exist in the context of `{1}'",
836 Error_TypeDoesNotContainDefinition (loc, queried_type, name);
840 if (TypeManager.MemberLookup (queried_type, null, queried_type,
841 AllMemberTypes, AllBindingFlags |
842 BindingFlags.NonPublic, name, null) == null) {
843 if ((lookup.Length == 1) && (lookup [0] is Type)) {
844 Type t = (Type) lookup [0];
846 Report.Error (305, loc,
847 "Using the generic type `{0}' " +
848 "requires {1} type arguments",
849 TypeManager.CSharpName (t),
850 TypeManager.GetNumberOfTypeArguments (t).ToString ());
855 MemberList ml = TypeManager.FindMembers (queried_type, MemberTypes.Constructor,
856 BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly, null, null);
857 if (name == ".ctor" && ml.Count == 0)
859 Report.Error (143, loc, "The type `{0}' has no constructors defined", TypeManager.CSharpName (queried_type));
863 Report.SymbolRelatedToPreviousError (lookup [0]);
864 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (lookup [0]));
868 /// Returns an expression that can be used to invoke operator true
869 /// on the expression if it exists.
871 static public Expression GetOperatorTrue (EmitContext ec, Expression e, Location loc)
873 return GetOperatorTrueOrFalse (ec, e, true, loc);
877 /// Returns an expression that can be used to invoke operator false
878 /// on the expression if it exists.
880 static public Expression GetOperatorFalse (EmitContext ec, Expression e, Location loc)
882 return GetOperatorTrueOrFalse (ec, e, false, loc);
885 static Expression GetOperatorTrueOrFalse (EmitContext ec, Expression e, bool is_true, Location loc)
888 Expression operator_group;
890 if (TypeManager.IsNullableType (e.Type))
891 return new Nullable.OperatorTrueOrFalse (e, is_true, loc).Resolve (ec);
893 operator_group = MethodLookup (ec, e.Type, is_true ? "op_True" : "op_False", loc);
894 if (operator_group == null)
897 ArrayList arguments = new ArrayList ();
898 arguments.Add (new Argument (e, Argument.AType.Expression));
899 method = Invocation.OverloadResolve (
900 ec, (MethodGroupExpr) operator_group, arguments, false, loc);
905 return new StaticCallExpr ((MethodInfo) method, arguments, loc);
909 /// Resolves the expression `e' into a boolean expression: either through
910 /// an implicit conversion, or through an `operator true' invocation
912 public static Expression ResolveBoolean (EmitContext ec, Expression e, Location loc)
918 if (e.Type == TypeManager.bool_type)
921 Expression converted = Convert.ImplicitConversion (ec, e, TypeManager.bool_type, Location.Null);
923 if (converted != null)
927 // If no implicit conversion to bool exists, try using `operator true'
929 converted = Expression.GetOperatorTrue (ec, e, loc);
930 if (converted == null){
931 e.Error_ValueCannotBeConverted (loc, TypeManager.bool_type, false);
937 public virtual string ExprClassName
941 case ExprClass.Invalid:
943 case ExprClass.Value:
945 case ExprClass.Variable:
947 case ExprClass.Namespace:
951 case ExprClass.MethodGroup:
952 return "method group";
953 case ExprClass.PropertyAccess:
954 return "property access";
955 case ExprClass.EventAccess:
956 return "event access";
957 case ExprClass.IndexerAccess:
958 return "indexer access";
959 case ExprClass.Nothing:
962 throw new Exception ("Should not happen");
967 /// Reports that we were expecting `expr' to be of class `expected'
969 public void Error_UnexpectedKind (DeclSpace ds, string expected, Location loc)
971 Error_UnexpectedKind (ds, expected, ExprClassName, loc);
974 public void Error_UnexpectedKind (DeclSpace ds, string expected, string was, Location loc)
976 string name = GetSignatureForError ();
978 name = ds.GetSignatureForError () + '.' + name;
980 Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
981 name, was, expected);
984 public void Error_UnexpectedKind (ResolveFlags flags, Location loc)
986 string [] valid = new string [4];
989 if ((flags & ResolveFlags.VariableOrValue) != 0) {
990 valid [count++] = "variable";
991 valid [count++] = "value";
994 if ((flags & ResolveFlags.Type) != 0)
995 valid [count++] = "type";
997 if ((flags & ResolveFlags.MethodGroup) != 0)
998 valid [count++] = "method group";
1001 valid [count++] = "unknown";
1003 StringBuilder sb = new StringBuilder (valid [0]);
1004 for (int i = 1; i < count - 1; i++) {
1006 sb.Append (valid [i]);
1009 sb.Append ("' or `");
1010 sb.Append (valid [count - 1]);
1013 Report.Error (119, loc,
1014 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1017 public static void UnsafeError (Location loc)
1019 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1023 // Load the object from the pointer.
1025 public static void LoadFromPtr (ILGenerator ig, Type t)
1027 if (t == TypeManager.int32_type)
1028 ig.Emit (OpCodes.Ldind_I4);
1029 else if (t == TypeManager.uint32_type)
1030 ig.Emit (OpCodes.Ldind_U4);
1031 else if (t == TypeManager.short_type)
1032 ig.Emit (OpCodes.Ldind_I2);
1033 else if (t == TypeManager.ushort_type)
1034 ig.Emit (OpCodes.Ldind_U2);
1035 else if (t == TypeManager.char_type)
1036 ig.Emit (OpCodes.Ldind_U2);
1037 else if (t == TypeManager.byte_type)
1038 ig.Emit (OpCodes.Ldind_U1);
1039 else if (t == TypeManager.sbyte_type)
1040 ig.Emit (OpCodes.Ldind_I1);
1041 else if (t == TypeManager.uint64_type)
1042 ig.Emit (OpCodes.Ldind_I8);
1043 else if (t == TypeManager.int64_type)
1044 ig.Emit (OpCodes.Ldind_I8);
1045 else if (t == TypeManager.float_type)
1046 ig.Emit (OpCodes.Ldind_R4);
1047 else if (t == TypeManager.double_type)
1048 ig.Emit (OpCodes.Ldind_R8);
1049 else if (t == TypeManager.bool_type)
1050 ig.Emit (OpCodes.Ldind_I1);
1051 else if (t == TypeManager.intptr_type)
1052 ig.Emit (OpCodes.Ldind_I);
1053 else if (TypeManager.IsEnumType (t)) {
1054 if (t == TypeManager.enum_type)
1055 ig.Emit (OpCodes.Ldind_Ref);
1057 LoadFromPtr (ig, TypeManager.EnumToUnderlying (t));
1058 } else if (t.IsValueType || t.IsGenericParameter)
1059 ig.Emit (OpCodes.Ldobj, t);
1060 else if (t.IsPointer)
1061 ig.Emit (OpCodes.Ldind_I);
1063 ig.Emit (OpCodes.Ldind_Ref);
1067 // The stack contains the pointer and the value of type `type'
1069 public static void StoreFromPtr (ILGenerator ig, Type type)
1071 if (TypeManager.IsEnumType (type))
1072 type = TypeManager.EnumToUnderlying (type);
1073 if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
1074 ig.Emit (OpCodes.Stind_I4);
1075 else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
1076 ig.Emit (OpCodes.Stind_I8);
1077 else if (type == TypeManager.char_type || type == TypeManager.short_type ||
1078 type == TypeManager.ushort_type)
1079 ig.Emit (OpCodes.Stind_I2);
1080 else if (type == TypeManager.float_type)
1081 ig.Emit (OpCodes.Stind_R4);
1082 else if (type == TypeManager.double_type)
1083 ig.Emit (OpCodes.Stind_R8);
1084 else if (type == TypeManager.byte_type || type == TypeManager.sbyte_type ||
1085 type == TypeManager.bool_type)
1086 ig.Emit (OpCodes.Stind_I1);
1087 else if (type == TypeManager.intptr_type)
1088 ig.Emit (OpCodes.Stind_I);
1089 else if (type.IsValueType || type.IsGenericParameter)
1090 ig.Emit (OpCodes.Stobj, type);
1092 ig.Emit (OpCodes.Stind_Ref);
1096 // Returns the size of type `t' if known, otherwise, 0
1098 public static int GetTypeSize (Type t)
1100 t = TypeManager.TypeToCoreType (t);
1101 if (t == TypeManager.int32_type ||
1102 t == TypeManager.uint32_type ||
1103 t == TypeManager.float_type)
1105 else if (t == TypeManager.int64_type ||
1106 t == TypeManager.uint64_type ||
1107 t == TypeManager.double_type)
1109 else if (t == TypeManager.byte_type ||
1110 t == TypeManager.sbyte_type ||
1111 t == TypeManager.bool_type)
1113 else if (t == TypeManager.short_type ||
1114 t == TypeManager.char_type ||
1115 t == TypeManager.ushort_type)
1117 else if (t == TypeManager.decimal_type)
1123 public static void Error_NegativeArrayIndex (Location loc)
1125 Report.Error (248, loc, "Cannot create an array with a negative size");
1128 protected void Error_CannotCallAbstractBase (string name)
1130 Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
1134 // Converts `source' to an int, uint, long or ulong.
1136 public Expression ExpressionToArrayArgument (EmitContext ec, Expression source, Location loc)
1140 using (ec.With (EmitContext.Flags.CheckState, true)) {
1141 target = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, loc);
1143 target = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, loc);
1145 target = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, loc);
1147 target = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, loc);
1149 if (target == null) {
1150 source.Error_ValueCannotBeConverted (loc, TypeManager.int32_type, false);
1156 // Only positive constants are allowed at compile time
1158 if (target is Constant){
1159 if (target is IntConstant){
1160 if (((IntConstant) target).Value < 0){
1161 Error_NegativeArrayIndex (loc);
1166 if (target is LongConstant){
1167 if (((LongConstant) target).Value < 0){
1168 Error_NegativeArrayIndex (loc);
1181 /// This is just a base class for expressions that can
1182 /// appear on statements (invocations, object creation,
1183 /// assignments, post/pre increment and decrement). The idea
1184 /// being that they would support an extra Emition interface that
1185 /// does not leave a result on the stack.
1187 public abstract class ExpressionStatement : Expression {
1189 public virtual ExpressionStatement ResolveStatement (EmitContext ec)
1191 Expression e = Resolve (ec);
1195 ExpressionStatement es = e as ExpressionStatement;
1197 Error (201, "Only assignment, call, increment, decrement and new object " +
1198 "expressions can be used as a statement");
1204 /// Requests the expression to be emitted in a `statement'
1205 /// context. This means that no new value is left on the
1206 /// stack after invoking this method (constrasted with
1207 /// Emit that will always leave a value on the stack).
1209 public abstract void EmitStatement (EmitContext ec);
1213 /// This kind of cast is used to encapsulate the child
1214 /// whose type is child.Type into an expression that is
1215 /// reported to return "return_type". This is used to encapsulate
1216 /// expressions which have compatible types, but need to be dealt
1217 /// at higher levels with.
1219 /// For example, a "byte" expression could be encapsulated in one
1220 /// of these as an "unsigned int". The type for the expression
1221 /// would be "unsigned int".
1224 public class EmptyCast : Expression {
1225 protected readonly Expression child;
1227 public EmptyCast (Expression child, Type return_type)
1229 eclass = child.eclass;
1230 loc = child.Location;
1235 public override Expression DoResolve (EmitContext ec)
1237 // This should never be invoked, we are born in fully
1238 // initialized state.
1243 public override void Emit (EmitContext ec)
1248 public override bool GetAttributableValue (Type valueType, out object value)
1250 return child.GetAttributableValue (valueType, out value);
1255 /// This is a numeric cast to a Decimal
1257 public class CastToDecimal : EmptyCast {
1259 MethodInfo conversion_operator;
1261 public CastToDecimal (Expression child)
1262 : this (child, false)
1266 public CastToDecimal (Expression child, bool find_explicit)
1267 : base (child, TypeManager.decimal_type)
1269 conversion_operator = GetConversionOperator (find_explicit);
1271 if (conversion_operator == null)
1272 throw new InternalErrorException ("Outer conversion routine is out of sync");
1275 // Returns the implicit operator that converts from
1276 // 'child.Type' to System.Decimal.
1277 MethodInfo GetConversionOperator (bool find_explicit)
1279 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1281 MemberInfo [] mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1282 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1284 foreach (MethodInfo oper in mi) {
1285 ParameterData pd = TypeManager.GetParameterData (oper);
1287 if (pd.ParameterType (0) == child.Type && oper.ReturnType == type)
1293 public override void Emit (EmitContext ec)
1295 ILGenerator ig = ec.ig;
1298 ig.Emit (OpCodes.Call, conversion_operator);
1303 /// This is an explicit numeric cast from a Decimal
1305 public class CastFromDecimal : EmptyCast
1307 static IDictionary operators;
1309 public CastFromDecimal (Expression child, Type return_type)
1310 : base (child, return_type)
1312 if (child.Type != TypeManager.decimal_type)
1313 throw new InternalErrorException (
1314 "The expected type is Decimal, instead it is " + child.Type.FullName);
1317 // Returns the explicit operator that converts from an
1318 // express of type System.Decimal to 'type'.
1319 public Expression Resolve ()
1321 if (operators == null) {
1322 MemberInfo[] all_oper = TypeManager.MemberLookup (TypeManager.decimal_type,
1323 TypeManager.decimal_type, TypeManager.decimal_type, MemberTypes.Method,
1324 BindingFlags.Static | BindingFlags.Public, "op_Explicit", null);
1326 operators = new System.Collections.Specialized.HybridDictionary ();
1327 foreach (MethodInfo oper in all_oper) {
1328 ParameterData pd = TypeManager.GetParameterData (oper);
1329 if (pd.ParameterType (0) == TypeManager.decimal_type)
1330 operators.Add (oper.ReturnType, oper);
1334 return operators.Contains (type) ? this : null;
1337 public override void Emit (EmitContext ec)
1339 ILGenerator ig = ec.ig;
1342 ig.Emit (OpCodes.Call, (MethodInfo)operators [type]);
1347 // We need to special case this since an empty cast of
1348 // a NullLiteral is still a Constant
1350 public class NullCast : Constant {
1351 public Constant child;
1353 public NullCast (Constant child, Type return_type):
1354 base (Location.Null)
1356 eclass = child.eclass;
1361 override public string AsString ()
1366 public override object GetValue ()
1371 public override Expression DoResolve (EmitContext ec)
1373 // This should never be invoked, we are born in fully
1374 // initialized state.
1379 public override void Emit (EmitContext ec)
1384 public override Constant Increment ()
1386 throw new NotSupportedException ();
1389 public override bool IsDefaultValue {
1395 public override bool IsNegative {
1401 public override Constant Reduce (bool inCheckedContext, Type target_type)
1403 if (type == target_type)
1404 return child.Reduce (inCheckedContext, target_type);
1413 /// This class is used to wrap literals which belong inside Enums
1415 public class EnumConstant : Constant {
1416 public Constant Child;
1418 public EnumConstant (Constant child, Type enum_type):
1419 base (child.Location)
1421 eclass = child.eclass;
1426 public override Expression DoResolve (EmitContext ec)
1428 // This should never be invoked, we are born in fully
1429 // initialized state.
1434 public override void Emit (EmitContext ec)
1439 public override bool GetAttributableValue (Type valueType, out object value)
1441 value = GetTypedValue ();
1445 public override string GetSignatureForError()
1447 return TypeManager.CSharpName (Type);
1450 public override object GetValue ()
1452 return Child.GetValue ();
1455 public override object GetTypedValue ()
1457 // FIXME: runtime is not ready to work with just emited enums
1458 if (!RootContext.StdLib) {
1459 return Child.GetValue ();
1462 return System.Enum.ToObject (type, Child.GetValue ());
1465 public override string AsString ()
1467 return Child.AsString ();
1470 public override DoubleConstant ConvertToDouble ()
1472 return Child.ConvertToDouble ();
1475 public override FloatConstant ConvertToFloat ()
1477 return Child.ConvertToFloat ();
1480 public override ULongConstant ConvertToULong ()
1482 return Child.ConvertToULong ();
1485 public override LongConstant ConvertToLong ()
1487 return Child.ConvertToLong ();
1490 public override UIntConstant ConvertToUInt ()
1492 return Child.ConvertToUInt ();
1495 public override IntConstant ConvertToInt ()
1497 return Child.ConvertToInt ();
1500 public override Constant Increment()
1502 return new EnumConstant (Child.Increment (), type);
1505 public override bool IsDefaultValue {
1507 return Child.IsDefaultValue;
1511 public override bool IsZeroInteger {
1512 get { return Child.IsZeroInteger; }
1515 public override bool IsNegative {
1517 return Child.IsNegative;
1521 public override Constant Reduce(bool inCheckedContext, Type target_type)
1523 if (Child.Type == target_type)
1526 return Child.Reduce (inCheckedContext, target_type);
1529 public override Constant ToType (Type type, Location loc)
1532 // This is workaround of mono bug. It can be removed when the latest corlib spreads enough
1533 if (TypeManager.IsEnumType (type.UnderlyingSystemType))
1536 if (type.UnderlyingSystemType != Child.Type)
1537 Child = Child.ToType (type.UnderlyingSystemType, loc);
1541 if (!Convert.ImplicitStandardConversionExists (this, type)){
1542 Error_ValueCannotBeConverted (loc, type, false);
1546 return Child.ToType (type, loc);
1552 /// This kind of cast is used to encapsulate Value Types in objects.
1554 /// The effect of it is to box the value type emitted by the previous
1557 public class BoxedCast : EmptyCast {
1559 public BoxedCast (Expression expr, Type target_type)
1560 : base (expr, target_type)
1562 eclass = ExprClass.Value;
1565 public override Expression DoResolve (EmitContext ec)
1567 // This should never be invoked, we are born in fully
1568 // initialized state.
1573 public override void Emit (EmitContext ec)
1577 ec.ig.Emit (OpCodes.Box, child.Type);
1581 public class UnboxCast : EmptyCast {
1582 public UnboxCast (Expression expr, Type return_type)
1583 : base (expr, return_type)
1587 public override Expression DoResolve (EmitContext ec)
1589 // This should never be invoked, we are born in fully
1590 // initialized state.
1595 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1597 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
1598 Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
1599 return base.DoResolveLValue (ec, right_side);
1602 public override void Emit (EmitContext ec)
1605 ILGenerator ig = ec.ig;
1608 if (t.IsGenericParameter || t.IsGenericType && t.IsValueType)
1609 ig.Emit (OpCodes.Unbox_Any, t);
1611 ig.Emit (OpCodes.Unbox, t);
1613 LoadFromPtr (ig, t);
1619 /// This is used to perform explicit numeric conversions.
1621 /// Explicit numeric conversions might trigger exceptions in a checked
1622 /// context, so they should generate the conv.ovf opcodes instead of
1625 public class ConvCast : EmptyCast {
1626 public enum Mode : byte {
1627 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1629 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1630 U2_I1, U2_U1, U2_I2, U2_CH,
1631 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1632 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1633 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH,
1634 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH,
1635 CH_I1, CH_U1, CH_I2,
1636 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1637 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4
1642 public ConvCast (Expression child, Type return_type, Mode m)
1643 : base (child, return_type)
1648 public override Expression DoResolve (EmitContext ec)
1650 // This should never be invoked, we are born in fully
1651 // initialized state.
1656 public override string ToString ()
1658 return String.Format ("ConvCast ({0}, {1})", mode, child);
1661 public override void Emit (EmitContext ec)
1663 ILGenerator ig = ec.ig;
1669 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1670 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1671 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1672 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1673 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1675 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1676 case Mode.U1_CH: /* nothing */ break;
1678 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1679 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1680 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1681 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1682 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1683 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1685 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1686 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1687 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1688 case Mode.U2_CH: /* nothing */ break;
1690 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1691 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1692 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1693 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1694 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1695 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1696 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1698 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1699 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1700 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1701 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1702 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1703 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1705 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1706 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1707 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1708 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1709 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1710 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1711 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1712 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1714 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1715 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1716 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1717 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1718 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1719 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1720 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1721 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1723 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1724 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1725 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1727 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1728 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1729 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1730 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1731 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1732 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1733 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1734 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1735 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1737 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1738 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1739 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1740 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1741 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1742 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1743 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1744 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1745 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1746 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1750 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
1751 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
1752 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
1753 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
1754 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
1756 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
1757 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
1759 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
1760 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
1761 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
1762 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
1763 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
1764 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
1766 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
1767 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
1768 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
1769 case Mode.U2_CH: /* nothing */ break;
1771 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
1772 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
1773 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
1774 case Mode.I4_U4: /* nothing */ break;
1775 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
1776 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
1777 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
1779 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
1780 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
1781 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
1782 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
1783 case Mode.U4_I4: /* nothing */ break;
1784 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
1786 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
1787 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
1788 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
1789 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
1790 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
1791 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
1792 case Mode.I8_U8: /* nothing */ break;
1793 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
1795 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
1796 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
1797 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
1798 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
1799 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
1800 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
1801 case Mode.U8_I8: /* nothing */ break;
1802 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
1804 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
1805 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
1806 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
1808 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
1809 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
1810 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
1811 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
1812 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
1813 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
1814 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
1815 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
1816 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
1818 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
1819 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
1820 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
1821 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
1822 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
1823 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
1824 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
1825 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
1826 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
1827 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1833 public class OpcodeCast : EmptyCast {
1837 public OpcodeCast (Expression child, Type return_type, OpCode op)
1838 : base (child, return_type)
1842 second_valid = false;
1845 public OpcodeCast (Expression child, Type return_type, OpCode op, OpCode op2)
1846 : base (child, return_type)
1851 second_valid = true;
1854 public override Expression DoResolve (EmitContext ec)
1856 // This should never be invoked, we are born in fully
1857 // initialized state.
1862 public override void Emit (EmitContext ec)
1873 /// This kind of cast is used to encapsulate a child and cast it
1874 /// to the class requested
1876 public class ClassCast : EmptyCast {
1877 public ClassCast (Expression child, Type return_type)
1878 : base (child, return_type)
1883 public override Expression DoResolve (EmitContext ec)
1885 // This should never be invoked, we are born in fully
1886 // initialized state.
1891 public override void Emit (EmitContext ec)
1895 if (child.Type.IsGenericParameter)
1896 ec.ig.Emit (OpCodes.Box, child.Type);
1898 if (type.IsGenericParameter)
1899 ec.ig.Emit (OpCodes.Unbox_Any, type);
1901 ec.ig.Emit (OpCodes.Castclass, type);
1906 /// SimpleName expressions are formed of a single word and only happen at the beginning
1907 /// of a dotted-name.
1909 public class SimpleName : Expression {
1911 public readonly TypeArguments Arguments;
1914 public SimpleName (string name, Location l)
1920 public SimpleName (string name, TypeArguments args, Location l)
1927 public SimpleName (string name, TypeParameter[] type_params, Location l)
1932 Arguments = new TypeArguments (l);
1933 foreach (TypeParameter type_param in type_params)
1934 Arguments.Add (new TypeParameterExpr (type_param, l));
1937 public static string RemoveGenericArity (string name)
1940 StringBuilder sb = new StringBuilder ();
1941 while (start < name.Length) {
1942 int pos = name.IndexOf ('`', start);
1944 sb.Append (name.Substring (start));
1948 sb.Append (name.Substring (start, pos-start));
1951 while ((pos < name.Length) && Char.IsNumber (name [pos]))
1957 return sb.ToString ();
1960 public SimpleName GetMethodGroup ()
1962 return new SimpleName (RemoveGenericArity (Name), Arguments, loc);
1965 public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
1967 if (ec.IsFieldInitializer)
1968 Report.Error (236, l,
1969 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
1973 120, l, "`{0}': An object reference is required for the nonstatic field, method or property",
1977 public bool IdenticalNameAndTypeName (EmitContext ec, Expression resolved_to, Location loc)
1979 return resolved_to != null && resolved_to.Type != null &&
1980 resolved_to.Type.Name == Name &&
1981 (ec.DeclContainer.LookupType (Name, loc, /* ignore_cs0104 = */ true) != null);
1984 public override Expression DoResolve (EmitContext ec)
1986 return SimpleNameResolve (ec, null, false);
1989 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1991 return SimpleNameResolve (ec, right_side, false);
1995 public Expression DoResolve (EmitContext ec, bool intermediate)
1997 return SimpleNameResolve (ec, null, intermediate);
2000 private bool IsNestedChild (Type t, Type parent)
2005 while (parent != null) {
2006 parent = TypeManager.DropGenericTypeArguments (parent);
2007 if (TypeManager.IsNestedChildOf (t, parent))
2010 parent = parent.BaseType;
2016 FullNamedExpression ResolveNested (IResolveContext ec, Type t)
2018 if (!t.IsGenericTypeDefinition)
2021 DeclSpace ds = ec.DeclContainer;
2022 while (ds != null) {
2023 if (IsNestedChild (t, ds.TypeBuilder))
2032 Type[] gen_params = t.GetGenericArguments ();
2034 int arg_count = Arguments != null ? Arguments.Count : 0;
2036 for (; (ds != null) && ds.IsGeneric; ds = ds.Parent) {
2037 if (arg_count + ds.CountTypeParameters == gen_params.Length) {
2038 TypeArguments new_args = new TypeArguments (loc);
2039 foreach (TypeParameter param in ds.TypeParameters)
2040 new_args.Add (new TypeParameterExpr (param, loc));
2042 if (Arguments != null)
2043 new_args.Add (Arguments);
2045 return new ConstructedType (t, new_args, loc);
2052 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2054 FullNamedExpression fne = ec.GenericDeclContainer.LookupGeneric (Name, loc);
2056 return fne.ResolveAsTypeStep (ec, silent);
2058 int errors = Report.Errors;
2059 fne = ec.DeclContainer.LookupType (Name, loc, /*ignore_cs0104=*/ false);
2062 if (fne.Type == null)
2065 FullNamedExpression nested = ResolveNested (ec, fne.Type);
2067 return nested.ResolveAsTypeStep (ec, false);
2069 if (Arguments != null) {
2070 ConstructedType ct = new ConstructedType (fne, Arguments, loc);
2071 return ct.ResolveAsTypeStep (ec, false);
2077 if (silent || errors != Report.Errors)
2080 MemberCore mc = ec.DeclContainer.GetDefinition (Name);
2082 Error_UnexpectedKind (ec.DeclContainer, "type", GetMemberType (mc), loc);
2086 string ns = ec.DeclContainer.NamespaceEntry.NS.Name;
2087 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2088 foreach (Assembly a in RootNamespace.Global.Assemblies) {
2089 Type type = a.GetType (fullname);
2091 Report.SymbolRelatedToPreviousError (type);
2092 Expression.ErrorIsInaccesible (loc, fullname);
2097 NamespaceEntry.Error_NamespaceNotFound (loc, Name);
2101 // TODO: I am still not convinced about this. If someone else will need it
2102 // implement this as virtual property in MemberCore hierarchy
2103 string GetMemberType (MemberCore mc)
2105 if (mc is PropertyBase)
2109 if (mc is FieldBase)
2111 if (mc is MethodCore)
2113 if (mc is EnumMember)
2119 Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2125 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2129 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2136 /// 7.5.2: Simple Names.
2138 /// Local Variables and Parameters are handled at
2139 /// parse time, so they never occur as SimpleNames.
2141 /// The `intermediate' flag is used by MemberAccess only
2142 /// and it is used to inform us that it is ok for us to
2143 /// avoid the static check, because MemberAccess might end
2144 /// up resolving the Name as a Type name and the access as
2145 /// a static type access.
2147 /// ie: Type Type; .... { Type.GetType (""); }
2149 /// Type is both an instance variable and a Type; Type.GetType
2150 /// is the static method not an instance method of type.
2152 Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2154 Expression e = null;
2157 // Stage 1: Performed by the parser (binding to locals or parameters).
2159 Block current_block = ec.CurrentBlock;
2160 if (current_block != null){
2161 LocalInfo vi = current_block.GetLocalInfo (Name);
2163 if (Arguments != null) {
2164 Report.Error (307, loc,
2165 "The variable `{0}' cannot be used with type arguments",
2170 LocalVariableReference var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2171 if (right_side != null) {
2172 return var.ResolveLValue (ec, right_side, loc);
2174 ResolveFlags rf = ResolveFlags.VariableOrValue;
2176 rf |= ResolveFlags.DisableFlowAnalysis;
2177 return var.Resolve (ec, rf);
2181 ParameterReference pref = current_block.Toplevel.GetParameterReference (Name, loc);
2183 if (Arguments != null) {
2184 Report.Error (307, loc,
2185 "The variable `{0}' cannot be used with type arguments",
2190 if (right_side != null)
2191 return pref.ResolveLValue (ec, right_side, loc);
2193 return pref.Resolve (ec);
2198 // Stage 2: Lookup members
2201 DeclSpace lookup_ds = ec.DeclContainer;
2202 Type almost_matched_type = null;
2203 ArrayList almost_matched = null;
2205 if (lookup_ds.TypeBuilder == null)
2208 e = MemberLookup (ec.ContainerType, lookup_ds.TypeBuilder, Name, loc);
2212 if (almost_matched == null && almostMatchedMembers.Count > 0) {
2213 almost_matched_type = lookup_ds.TypeBuilder;
2214 almost_matched = (ArrayList) almostMatchedMembers.Clone ();
2217 lookup_ds =lookup_ds.Parent;
2218 } while (lookup_ds != null);
2220 if (e == null && ec.ContainerType != null)
2221 e = MemberLookup (ec.ContainerType, ec.ContainerType, Name, loc);
2224 if (almost_matched == null && almostMatchedMembers.Count > 0) {
2225 almost_matched_type = ec.ContainerType;
2226 almost_matched = (ArrayList) almostMatchedMembers.Clone ();
2228 e = ResolveAsTypeStep (ec, true);
2232 if (almost_matched != null)
2233 almostMatchedMembers = almost_matched;
2234 if (almost_matched_type == null)
2235 almost_matched_type = ec.ContainerType;
2236 MemberLookupFailed (ec.ContainerType, null, almost_matched_type, ((SimpleName) this).Name, ec.DeclContainer.Name, true, loc);
2240 if (e is TypeExpr) {
2241 if (Arguments == null)
2244 ConstructedType ct = new ConstructedType (
2245 (FullNamedExpression) e, Arguments, loc);
2246 return ct.ResolveAsTypeStep (ec, false);
2249 if (e is MemberExpr) {
2250 MemberExpr me = (MemberExpr) e;
2253 if (me.IsInstance) {
2254 if (ec.IsStatic || ec.IsFieldInitializer) {
2256 // Note that an MemberExpr can be both IsInstance and IsStatic.
2257 // An unresolved MethodGroupExpr can contain both kinds of methods
2258 // and each predicate is true if the MethodGroupExpr contains
2259 // at least one of that kind of method.
2263 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2264 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2265 return EmptyExpression.Null;
2269 // Pass the buck to MemberAccess and Invocation.
2271 left = EmptyExpression.Null;
2273 left = ec.GetThis (loc);
2276 left = new TypeExpression (ec.ContainerType, loc);
2279 e = me.ResolveMemberAccess (ec, left, loc, null);
2283 me = e as MemberExpr;
2287 if (Arguments != null) {
2288 MethodGroupExpr mg = me as MethodGroupExpr;
2292 return mg.ResolveGeneric (ec, Arguments);
2296 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2297 me.InstanceExpression.Type != me.DeclaringType &&
2298 !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2299 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2300 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2301 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2305 return (right_side != null)
2306 ? me.DoResolveLValue (ec, right_side)
2307 : me.DoResolve (ec);
2313 public override void Emit (EmitContext ec)
2316 // If this is ever reached, then we failed to
2317 // find the name as a namespace
2320 Error (103, "The name `" + Name +
2321 "' does not exist in the class `" +
2322 ec.DeclContainer.Name + "'");
2325 public override string ToString ()
2330 public override string GetSignatureForError ()
2337 /// Represents a namespace or a type. The name of the class was inspired by
2338 /// section 10.8.1 (Fully Qualified Names).
2340 public abstract class FullNamedExpression : Expression {
2341 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2346 public abstract string FullName {
2352 /// Expression that evaluates to a type
2354 public abstract class TypeExpr : FullNamedExpression {
2355 override public FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2357 TypeExpr t = DoResolveAsTypeStep (ec);
2361 eclass = ExprClass.Type;
2365 override public Expression DoResolve (EmitContext ec)
2367 return ResolveAsTypeTerminal (ec, false);
2370 override public void Emit (EmitContext ec)
2372 throw new Exception ("Should never be called");
2375 public virtual bool CheckAccessLevel (DeclSpace ds)
2377 return ds.CheckAccessLevel (Type);
2380 public virtual bool AsAccessible (DeclSpace ds, int flags)
2382 return ds.AsAccessible (Type, flags);
2385 public virtual bool IsClass {
2386 get { return Type.IsClass; }
2389 public virtual bool IsValueType {
2390 get { return Type.IsValueType; }
2393 public virtual bool IsInterface {
2394 get { return Type.IsInterface; }
2397 public virtual bool IsSealed {
2398 get { return Type.IsSealed; }
2401 public virtual bool CanInheritFrom ()
2403 if (Type == TypeManager.enum_type ||
2404 (Type == TypeManager.value_type && RootContext.StdLib) ||
2405 Type == TypeManager.multicast_delegate_type ||
2406 Type == TypeManager.delegate_type ||
2407 Type == TypeManager.array_type)
2413 protected abstract TypeExpr DoResolveAsTypeStep (IResolveContext ec);
2415 public abstract string Name {
2419 public override bool Equals (object obj)
2421 TypeExpr tobj = obj as TypeExpr;
2425 return Type == tobj.Type;
2428 public override int GetHashCode ()
2430 return Type.GetHashCode ();
2433 public override string ToString ()
2440 /// Fully resolved Expression that already evaluated to a type
2442 public class TypeExpression : TypeExpr {
2443 public TypeExpression (Type t, Location l)
2446 eclass = ExprClass.Type;
2450 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2455 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2460 public override string Name {
2461 get { return Type.ToString (); }
2464 public override string FullName {
2465 get { return Type.FullName; }
2470 /// Used to create types from a fully qualified name. These are just used
2471 /// by the parser to setup the core types. A TypeLookupExpression is always
2472 /// classified as a type.
2474 public sealed class TypeLookupExpression : TypeExpr {
2475 readonly string name;
2477 public TypeLookupExpression (string name)
2480 eclass = ExprClass.Type;
2483 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2485 // It's null for corlib compilation only
2487 return DoResolveAsTypeStep (ec);
2492 static readonly char [] dot_array = { '.' };
2493 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2495 // If name is of the form `N.I', first lookup `N', then search a member `I' in it.
2497 string lookup_name = name;
2498 int pos = name.IndexOf ('.');
2500 rest = name.Substring (pos + 1);
2501 lookup_name = name.Substring (0, pos);
2504 FullNamedExpression resolved = RootNamespace.Global.Lookup (ec.DeclContainer, lookup_name, Location.Null);
2506 if (resolved != null && rest != null) {
2507 // Now handle the rest of the the name.
2508 string [] elements = rest.Split (dot_array);
2510 int count = elements.Length;
2512 while (i < count && resolved != null && resolved is Namespace) {
2513 Namespace ns = resolved as Namespace;
2514 element = elements [i++];
2515 lookup_name += "." + element;
2516 resolved = ns.Lookup (ec.DeclContainer, element, Location.Null);
2519 if (resolved != null && resolved is TypeExpr) {
2520 Type t = ((TypeExpr) resolved).Type;
2522 if (!ec.DeclContainer.CheckAccessLevel (t)) {
2524 lookup_name = t.FullName;
2531 t = TypeManager.GetNestedType (t, elements [i++]);
2536 if (resolved == null) {
2537 NamespaceEntry.Error_NamespaceNotFound (loc, lookup_name);
2541 if (!(resolved is TypeExpr)) {
2542 resolved.Error_UnexpectedKind (ec.DeclContainer, "type", loc);
2546 type = resolved.Type;
2550 public override string Name {
2551 get { return name; }
2554 public override string FullName {
2555 get { return name; }
2560 /// Represents an "unbound generic type", ie. typeof (Foo<>).
2563 public class UnboundTypeExpression : TypeExpr
2567 public UnboundTypeExpression (MemberName name, Location l)
2573 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2576 if (name.Left != null) {
2577 Expression lexpr = name.Left.GetTypeExpression ();
2578 expr = new MemberAccess (lexpr, name.Basename);
2580 expr = new SimpleName (name.Basename, loc);
2583 FullNamedExpression fne = expr.ResolveAsTypeStep (ec, false);
2588 return new TypeExpression (type, loc);
2591 public override string Name {
2592 get { return name.FullName; }
2595 public override string FullName {
2596 get { return name.FullName; }
2600 public class TypeAliasExpression : TypeExpr {
2601 FullNamedExpression alias;
2606 public TypeAliasExpression (FullNamedExpression alias, TypeArguments args, Location l)
2612 eclass = ExprClass.Type;
2614 name = alias.FullName + "<" + args.ToString () + ">";
2616 name = alias.FullName;
2619 public override string Name {
2620 get { return alias.FullName; }
2623 public override string FullName {
2624 get { return name; }
2627 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2629 texpr = alias.ResolveAsTypeTerminal (ec, false);
2633 Type type = texpr.Type;
2634 int num_args = TypeManager.GetNumberOfTypeArguments (type);
2637 if (num_args == 0) {
2638 Report.Error (308, loc,
2639 "The non-generic type `{0}' cannot " +
2640 "be used with type arguments.",
2641 TypeManager.CSharpName (type));
2645 ConstructedType ctype = new ConstructedType (type, args, loc);
2646 return ctype.ResolveAsTypeTerminal (ec, false);
2647 } else if (num_args > 0) {
2648 Report.Error (305, loc,
2649 "Using the generic type `{0}' " +
2650 "requires {1} type arguments",
2651 TypeManager.CSharpName (type), num_args.ToString ());
2658 public override bool CheckAccessLevel (DeclSpace ds)
2660 return texpr.CheckAccessLevel (ds);
2663 public override bool AsAccessible (DeclSpace ds, int flags)
2665 return texpr.AsAccessible (ds, flags);
2668 public override bool IsClass {
2669 get { return texpr.IsClass; }
2672 public override bool IsValueType {
2673 get { return texpr.IsValueType; }
2676 public override bool IsInterface {
2677 get { return texpr.IsInterface; }
2680 public override bool IsSealed {
2681 get { return texpr.IsSealed; }
2686 /// This class denotes an expression which evaluates to a member
2687 /// of a struct or a class.
2689 public abstract class MemberExpr : Expression
2692 /// The name of this member.
2694 public abstract string Name {
2699 /// Whether this is an instance member.
2701 public abstract bool IsInstance {
2706 /// Whether this is a static member.
2708 public abstract bool IsStatic {
2713 /// The type which declares this member.
2715 public abstract Type DeclaringType {
2720 /// The instance expression associated with this member, if it's a
2721 /// non-static member.
2723 public Expression InstanceExpression;
2725 public static void error176 (Location loc, string name)
2727 Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
2728 "with an instance reference, qualify it with a type name instead", name);
2731 // TODO: possible optimalization
2732 // Cache resolved constant result in FieldBuilder <-> expression map
2733 public virtual Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
2734 SimpleName original)
2738 // original == null || original.Resolve (...) ==> left
2741 if (left is TypeExpr) {
2743 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
2751 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
2754 error176 (loc, GetSignatureForError ());
2758 InstanceExpression = left;
2763 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
2768 if (InstanceExpression == EmptyExpression.Null) {
2769 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
2773 if (InstanceExpression.Type.IsValueType) {
2774 if (InstanceExpression is IMemoryLocation) {
2775 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
2777 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
2778 InstanceExpression.Emit (ec);
2780 t.AddressOf (ec, AddressOp.Store);
2783 InstanceExpression.Emit (ec);
2785 if (prepare_for_load)
2786 ec.ig.Emit (OpCodes.Dup);
2791 /// MethodGroup Expression.
2793 /// This is a fully resolved expression that evaluates to a type
2795 public class MethodGroupExpr : MemberExpr {
2796 public MethodBase [] Methods;
2797 bool has_type_arguments = false;
2798 bool identical_type_name = false;
2801 public MethodGroupExpr (MemberInfo [] mi, Location l)
2803 Methods = new MethodBase [mi.Length];
2804 mi.CopyTo (Methods, 0);
2805 eclass = ExprClass.MethodGroup;
2806 type = TypeManager.object_type;
2810 public MethodGroupExpr (ArrayList list, Location l)
2812 Methods = new MethodBase [list.Count];
2815 list.CopyTo (Methods, 0);
2817 foreach (MemberInfo m in list){
2818 if (!(m is MethodBase)){
2819 Console.WriteLine ("Name " + m.Name);
2820 Console.WriteLine ("Found a: " + m.GetType ().FullName);
2827 eclass = ExprClass.MethodGroup;
2828 type = TypeManager.object_type;
2831 public override Type DeclaringType {
2834 // We assume that the top-level type is in the end
2836 return Methods [Methods.Length - 1].DeclaringType;
2837 //return Methods [0].DeclaringType;
2841 public bool HasTypeArguments {
2843 return has_type_arguments;
2847 has_type_arguments = value;
2851 public bool IdenticalTypeName {
2853 return identical_type_name;
2857 identical_type_name = value;
2861 public bool IsBase {
2870 public override string GetSignatureForError ()
2872 return TypeManager.CSharpSignature (Methods [0]);
2875 public override string Name {
2877 return Methods [0].Name;
2881 public override bool IsInstance {
2883 foreach (MethodBase mb in Methods)
2891 public override bool IsStatic {
2893 foreach (MethodBase mb in Methods)
2901 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
2902 SimpleName original)
2904 if (!(left is TypeExpr) &&
2905 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
2906 IdenticalTypeName = true;
2908 return base.ResolveMemberAccess (ec, left, loc, original);
2911 override public Expression DoResolve (EmitContext ec)
2914 InstanceExpression = null;
2916 if (InstanceExpression != null) {
2917 InstanceExpression = InstanceExpression.DoResolve (ec);
2918 if (InstanceExpression == null)
2925 public void ReportUsageError ()
2927 Report.Error (654, loc, "Method `" + DeclaringType + "." +
2928 Name + "()' is referenced without parentheses");
2931 override public void Emit (EmitContext ec)
2933 ReportUsageError ();
2936 bool RemoveMethods (bool keep_static)
2938 ArrayList smethods = new ArrayList ();
2940 foreach (MethodBase mb in Methods){
2941 if (mb.IsStatic == keep_static)
2945 if (smethods.Count == 0)
2948 Methods = new MethodBase [smethods.Count];
2949 smethods.CopyTo (Methods, 0);
2955 /// Removes any instance methods from the MethodGroup, returns
2956 /// false if the resulting set is empty.
2958 public bool RemoveInstanceMethods ()
2960 return RemoveMethods (true);
2964 /// Removes any static methods from the MethodGroup, returns
2965 /// false if the resulting set is empty.
2967 public bool RemoveStaticMethods ()
2969 return RemoveMethods (false);
2972 public Expression ResolveGeneric (EmitContext ec, TypeArguments args)
2974 if (args.Resolve (ec) == false)
2977 Type[] atypes = args.Arguments;
2979 int first_count = 0;
2980 MethodInfo first = null;
2982 ArrayList list = new ArrayList ();
2983 foreach (MethodBase mb in Methods) {
2984 MethodInfo mi = mb as MethodInfo;
2985 if ((mi == null) || !mi.IsGenericMethod)
2988 Type[] gen_params = mi.GetGenericArguments ();
2990 if (first == null) {
2992 first_count = gen_params.Length;
2995 if (gen_params.Length != atypes.Length)
2998 list.Add (mi.MakeGenericMethod (atypes));
3001 if (list.Count > 0) {
3002 MethodGroupExpr new_mg = new MethodGroupExpr (list, Location);
3003 new_mg.InstanceExpression = InstanceExpression;
3004 new_mg.HasTypeArguments = true;
3005 new_mg.IsBase = IsBase;
3011 305, loc, "Using the generic method `{0}' " +
3012 "requires {1} type arguments", Name,
3013 first_count.ToString ());
3016 308, loc, "The non-generic method `{0}' " +
3017 "cannot be used with type arguments", Name);
3024 /// Fully resolved expression that evaluates to a Field
3026 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariable {
3027 public readonly FieldInfo FieldInfo;
3028 VariableInfo variable_info;
3030 LocalTemporary temp;
3032 bool in_initializer;
3034 public FieldExpr (FieldInfo fi, Location l, bool in_initializer):
3037 this.in_initializer = in_initializer;
3040 public FieldExpr (FieldInfo fi, Location l)
3043 eclass = ExprClass.Variable;
3044 type = TypeManager.TypeToCoreType (fi.FieldType);
3048 public override string Name {
3050 return FieldInfo.Name;
3054 public override bool IsInstance {
3056 return !FieldInfo.IsStatic;
3060 public override bool IsStatic {
3062 return FieldInfo.IsStatic;
3066 public override Type DeclaringType {
3068 return FieldInfo.DeclaringType;
3072 public override string GetSignatureForError ()
3074 return TypeManager.GetFullNameSignature (FieldInfo);
3077 public VariableInfo VariableInfo {
3079 return variable_info;
3083 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3084 SimpleName original)
3086 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
3088 Type t = fi.FieldType;
3090 if (fi.IsLiteral || (fi.IsInitOnly && t == TypeManager.decimal_type)) {
3091 IConstant ic = TypeManager.GetConstant (fi);
3094 ic = new ExternalConstant (fi);
3096 ic = ExternalConstant.CreateDecimal (fi);
3098 return base.ResolveMemberAccess (ec, left, loc, original);
3101 TypeManager.RegisterConstant (fi, ic);
3104 bool left_is_type = left is TypeExpr;
3105 if (!left_is_type && (original == null || !original.IdenticalNameAndTypeName (ec, left, loc))) {
3106 Report.SymbolRelatedToPreviousError (FieldInfo);
3107 error176 (loc, TypeManager.GetFullNameSignature (FieldInfo));
3111 if (ic.ResolveValue ()) {
3112 if (!ec.IsInObsoleteScope)
3113 ic.CheckObsoleteness (loc);
3119 if (t.IsPointer && !ec.InUnsafe) {
3124 return base.ResolveMemberAccess (ec, left, loc, original);
3127 override public Expression DoResolve (EmitContext ec)
3129 return DoResolve (ec, false, false);
3132 Expression DoResolve (EmitContext ec, bool lvalue_instance, bool out_access)
3134 if (!FieldInfo.IsStatic){
3135 if (InstanceExpression == null){
3137 // This can happen when referencing an instance field using
3138 // a fully qualified type expression: TypeName.InstanceField = xxx
3140 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3144 // Resolve the field's instance expression while flow analysis is turned
3145 // off: when accessing a field "a.b", we must check whether the field
3146 // "a.b" is initialized, not whether the whole struct "a" is initialized.
3148 if (lvalue_instance) {
3149 using (ec.With (EmitContext.Flags.DoFlowAnalysis, false)) {
3150 Expression right_side =
3151 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
3152 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side, loc);
3155 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
3156 InstanceExpression = InstanceExpression.Resolve (ec, rf);
3159 if (InstanceExpression == null)
3162 InstanceExpression.CheckMarshalByRefAccess ();
3165 if (!in_initializer && !ec.IsFieldInitializer) {
3166 ObsoleteAttribute oa;
3167 FieldBase f = TypeManager.GetField (FieldInfo);
3169 if (!ec.IsInObsoleteScope)
3170 f.CheckObsoleteness (loc);
3172 // To be sure that type is external because we do not register generated fields
3173 } else if (!(FieldInfo.DeclaringType is TypeBuilder)) {
3174 oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
3176 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
3180 AnonymousContainer am = ec.CurrentAnonymousMethod;
3182 if (!FieldInfo.IsStatic){
3183 if (!am.IsIterator && (ec.TypeContainer is Struct)){
3184 Report.Error (1673, loc,
3185 "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",
3189 if ((am.ContainerAnonymousMethod == null) && (InstanceExpression is This))
3190 ec.CaptureField (this);
3194 // If the instance expression is a local variable or parameter.
3195 IVariable var = InstanceExpression as IVariable;
3196 if ((var == null) || (var.VariableInfo == null))
3199 VariableInfo vi = var.VariableInfo;
3200 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
3203 variable_info = vi.GetSubStruct (FieldInfo.Name);
3207 static readonly int [] codes = {
3208 191, // instance, write access
3209 192, // instance, out access
3210 198, // static, write access
3211 199, // static, out access
3212 1648, // member of value instance, write access
3213 1649, // member of value instance, out access
3214 1650, // member of value static, write access
3215 1651 // member of value static, out access
3218 static readonly string [] msgs = {
3219 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
3220 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
3221 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
3222 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
3223 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
3224 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
3225 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
3226 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
3229 // The return value is always null. Returning a value simplifies calling code.
3230 Expression Report_AssignToReadonly (Expression right_side)
3233 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
3237 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
3239 Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
3244 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3246 IVariable var = InstanceExpression as IVariable;
3247 if ((var != null) && (var.VariableInfo != null))
3248 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
3250 bool lvalue_instance = !FieldInfo.IsStatic && FieldInfo.DeclaringType.IsValueType;
3251 bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
3253 Expression e = DoResolve (ec, lvalue_instance, out_access);
3258 FieldBase fb = TypeManager.GetField (FieldInfo);
3262 if (FieldInfo.IsInitOnly) {
3263 // InitOnly fields can only be assigned in constructors or initializers
3264 if (!ec.IsFieldInitializer && !ec.IsConstructor)
3265 return Report_AssignToReadonly (right_side);
3267 if (ec.IsConstructor) {
3268 Type ctype = ec.TypeContainer.CurrentType;
3270 ctype = ec.ContainerType;
3272 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
3273 if (!TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
3274 return Report_AssignToReadonly (right_side);
3275 // static InitOnly fields cannot be assigned-to in an instance constructor
3276 if (IsStatic && !ec.IsStatic)
3277 return Report_AssignToReadonly (right_side);
3278 // instance constructors can't modify InitOnly fields of other instances of the same type
3279 if (!IsStatic && !(InstanceExpression is This))
3280 return Report_AssignToReadonly (right_side);
3284 if (right_side == EmptyExpression.OutAccess &&
3285 !IsStatic && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
3286 Report.SymbolRelatedToPreviousError (DeclaringType);
3287 Report.Warning (197, 1, loc,
3288 "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",
3289 GetSignatureForError ());
3295 public override void CheckMarshalByRefAccess ()
3297 if (!IsStatic && Type.IsValueType && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
3298 Report.SymbolRelatedToPreviousError (DeclaringType);
3299 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",
3300 GetSignatureForError ());
3304 public bool VerifyFixed ()
3306 IVariable variable = InstanceExpression as IVariable;
3307 // A variable of the form V.I is fixed when V is a fixed variable of a struct type.
3308 // We defer the InstanceExpression check after the variable check to avoid a
3309 // separate null check on InstanceExpression.
3310 return variable != null && InstanceExpression.Type.IsValueType && variable.VerifyFixed ();
3313 public override int GetHashCode ()
3315 return FieldInfo.GetHashCode ();
3318 public override bool Equals (object obj)
3320 FieldExpr fe = obj as FieldExpr;
3324 if (FieldInfo != fe.FieldInfo)
3327 if (InstanceExpression == null || fe.InstanceExpression == null)
3330 return InstanceExpression.Equals (fe.InstanceExpression);
3333 public void Emit (EmitContext ec, bool leave_copy)
3335 ILGenerator ig = ec.ig;
3336 bool is_volatile = false;
3338 FieldBase f = TypeManager.GetField (FieldInfo);
3340 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
3343 f.SetMemberIsUsed ();
3346 if (FieldInfo.IsStatic){
3348 ig.Emit (OpCodes.Volatile);
3350 ig.Emit (OpCodes.Ldsfld, FieldInfo);
3353 EmitInstance (ec, false);
3356 ig.Emit (OpCodes.Volatile);
3358 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
3361 ig.Emit (OpCodes.Ldflda, FieldInfo);
3362 ig.Emit (OpCodes.Ldflda, ff.Element);
3365 ig.Emit (OpCodes.Ldfld, FieldInfo);
3370 ec.ig.Emit (OpCodes.Dup);
3371 if (!FieldInfo.IsStatic) {
3372 temp = new LocalTemporary (this.Type);
3378 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
3380 FieldAttributes fa = FieldInfo.Attributes;
3381 bool is_static = (fa & FieldAttributes.Static) != 0;
3382 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
3383 ILGenerator ig = ec.ig;
3384 prepared = prepare_for_load;
3386 if (is_readonly && !ec.IsConstructor){
3387 Report_AssignToReadonly (source);
3391 EmitInstance (ec, prepare_for_load);
3395 ec.ig.Emit (OpCodes.Dup);
3396 if (!FieldInfo.IsStatic) {
3397 temp = new LocalTemporary (this.Type);
3402 FieldBase f = TypeManager.GetField (FieldInfo);
3404 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
3405 ig.Emit (OpCodes.Volatile);
3411 ig.Emit (OpCodes.Stsfld, FieldInfo);
3413 ig.Emit (OpCodes.Stfld, FieldInfo);
3421 public override void Emit (EmitContext ec)
3426 public void AddressOf (EmitContext ec, AddressOp mode)
3428 ILGenerator ig = ec.ig;
3430 FieldBase f = TypeManager.GetField (FieldInfo);
3432 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
3433 Report.Warning (420, 1, loc, "`{0}': A volatile fields cannot be passed using a ref or out parameter",
3434 f.GetSignatureForError ());
3438 if ((mode & AddressOp.Store) != 0)
3440 if ((mode & AddressOp.Load) != 0)
3441 f.SetMemberIsUsed ();
3445 // Handle initonly fields specially: make a copy and then
3446 // get the address of the copy.
3449 if (FieldInfo.IsInitOnly){
3451 if (ec.IsConstructor){
3452 if (FieldInfo.IsStatic){
3464 local = ig.DeclareLocal (type);
3465 ig.Emit (OpCodes.Stloc, local);
3466 ig.Emit (OpCodes.Ldloca, local);
3471 if (FieldInfo.IsStatic){
3472 ig.Emit (OpCodes.Ldsflda, FieldInfo);
3475 EmitInstance (ec, false);
3476 ig.Emit (OpCodes.Ldflda, FieldInfo);
3482 // A FieldExpr whose address can not be taken
3484 public class FieldExprNoAddress : FieldExpr, IMemoryLocation {
3485 public FieldExprNoAddress (FieldInfo fi, Location loc) : base (fi, loc)
3489 public new void AddressOf (EmitContext ec, AddressOp mode)
3491 Report.Error (-215, "Report this: Taking the address of a remapped parameter not supported");
3496 /// Expression that evaluates to a Property. The Assign class
3497 /// might set the `Value' expression if we are in an assignment.
3499 /// This is not an LValue because we need to re-write the expression, we
3500 /// can not take data from the stack and store it.
3502 public class PropertyExpr : MemberExpr, IAssignMethod {
3503 public readonly PropertyInfo PropertyInfo;
3506 // This is set externally by the `BaseAccess' class
3509 MethodInfo getter, setter;
3514 LocalTemporary temp;
3517 internal static PtrHashtable AccessorTable = new PtrHashtable ();
3519 public PropertyExpr (Type containerType, PropertyInfo pi, Location l)
3522 eclass = ExprClass.PropertyAccess;
3526 type = TypeManager.TypeToCoreType (pi.PropertyType);
3528 ResolveAccessors (containerType);
3531 public override string Name {
3533 return PropertyInfo.Name;
3537 public override bool IsInstance {
3543 public override bool IsStatic {
3549 public override Type DeclaringType {
3551 return PropertyInfo.DeclaringType;
3555 public override string GetSignatureForError ()
3557 return TypeManager.GetFullNameSignature (PropertyInfo);
3560 void FindAccessors (Type invocation_type)
3562 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
3563 BindingFlags.Static | BindingFlags.Instance |
3564 BindingFlags.DeclaredOnly;
3566 Type current = PropertyInfo.DeclaringType;
3567 for (; current != null; current = current.BaseType) {
3568 MemberInfo[] group = TypeManager.MemberLookup (
3569 invocation_type, invocation_type, current,
3570 MemberTypes.Property, flags, PropertyInfo.Name, null);
3575 if (group.Length != 1)
3576 // Oooops, can this ever happen ?
3579 PropertyInfo pi = (PropertyInfo) group [0];
3582 getter = pi.GetGetMethod (true);
3585 setter = pi.GetSetMethod (true);
3587 MethodInfo accessor = getter != null ? getter : setter;
3589 if (!accessor.IsVirtual)
3595 // We also perform the permission checking here, as the PropertyInfo does not
3596 // hold the information for the accessibility of its setter/getter
3598 // TODO: can use TypeManager.GetProperty to boost performance
3599 void ResolveAccessors (Type containerType)
3601 FindAccessors (containerType);
3603 if (getter != null) {
3604 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
3605 IMethodData md = TypeManager.GetMethod (the_getter);
3607 md.SetMemberIsUsed ();
3609 AccessorTable [getter] = PropertyInfo;
3610 is_static = getter.IsStatic;
3613 if (setter != null) {
3614 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
3615 IMethodData md = TypeManager.GetMethod (the_setter);
3617 md.SetMemberIsUsed ();
3619 AccessorTable [setter] = PropertyInfo;
3620 is_static = setter.IsStatic;
3624 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
3627 InstanceExpression = null;
3631 if (InstanceExpression == null) {
3632 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3636 if (lvalue_instance)
3637 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
3639 InstanceExpression = InstanceExpression.DoResolve (ec);
3640 if (InstanceExpression == null)
3643 InstanceExpression.CheckMarshalByRefAccess ();
3645 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
3646 InstanceExpression.Type != ec.ContainerType &&
3647 ec.ContainerType.IsSubclassOf (PropertyInfo.DeclaringType) &&
3648 !InstanceExpression.Type.IsSubclassOf (ec.ContainerType)) {
3649 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
3656 void Error_PropertyNotFound (MethodInfo mi, bool getter)
3658 // TODO: correctly we should compare arguments but it will lead to bigger changes
3659 if (mi is MethodBuilder) {
3660 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
3664 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
3666 ParameterData iparams = TypeManager.GetParameterData (mi);
3667 sig.Append (getter ? "get_" : "set_");
3669 sig.Append (iparams.GetSignatureForError ());
3671 Report.SymbolRelatedToPreviousError (mi);
3672 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
3673 Name, sig.ToString ());
3676 override public Expression DoResolve (EmitContext ec)
3681 if (getter != null){
3682 if (TypeManager.GetParameterData (getter).Count != 0){
3683 Error_PropertyNotFound (getter, true);
3688 if (getter == null){
3690 // The following condition happens if the PropertyExpr was
3691 // created, but is invalid (ie, the property is inaccessible),
3692 // and we did not want to embed the knowledge about this in
3693 // the caller routine. This only avoids double error reporting.
3698 if (InstanceExpression != EmptyExpression.Null) {
3699 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
3700 TypeManager.GetFullNameSignature (PropertyInfo));
3705 bool must_do_cs1540_check = false;
3706 if (getter != null &&
3707 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
3708 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
3709 if (pm != null && pm.HasCustomAccessModifier) {
3710 Report.SymbolRelatedToPreviousError (pm);
3711 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
3712 TypeManager.CSharpSignature (getter));
3715 Report.SymbolRelatedToPreviousError (getter);
3716 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
3721 if (!InstanceResolve (ec, false, must_do_cs1540_check))
3725 // Only base will allow this invocation to happen.
3727 if (IsBase && getter.IsAbstract) {
3728 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
3732 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
3742 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3744 if (right_side == EmptyExpression.OutAccess) {
3745 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
3746 GetSignatureForError ());
3750 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
3751 Report.Error (1612, loc, "Cannot modify the return value of `{0}' because it is not a variable",
3752 GetSignatureForError ());
3756 if (setter == null){
3758 // The following condition happens if the PropertyExpr was
3759 // created, but is invalid (ie, the property is inaccessible),
3760 // and we did not want to embed the knowledge about this in
3761 // the caller routine. This only avoids double error reporting.
3765 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
3766 GetSignatureForError ());
3770 if (TypeManager.GetParameterData (setter).Count != 1){
3771 Error_PropertyNotFound (setter, false);
3775 bool must_do_cs1540_check;
3776 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
3777 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
3778 if (pm != null && pm.HasCustomAccessModifier) {
3779 Report.SymbolRelatedToPreviousError (pm);
3780 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
3781 TypeManager.CSharpSignature (setter));
3784 Report.SymbolRelatedToPreviousError (setter);
3785 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
3790 if (!InstanceResolve (ec, PropertyInfo.DeclaringType.IsValueType, must_do_cs1540_check))
3794 // Only base will allow this invocation to happen.
3796 if (IsBase && setter.IsAbstract){
3797 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
3804 public override void Emit (EmitContext ec)
3809 public void Emit (EmitContext ec, bool leave_copy)
3812 // Special case: length of single dimension array property is turned into ldlen
3814 if ((getter == TypeManager.system_int_array_get_length) ||
3815 (getter == TypeManager.int_array_get_length)){
3816 Type iet = InstanceExpression.Type;
3819 // System.Array.Length can be called, but the Type does not
3820 // support invoking GetArrayRank, so test for that case first
3822 if (iet != TypeManager.array_type && (iet.GetArrayRank () == 1)) {
3824 EmitInstance (ec, false);
3825 ec.ig.Emit (OpCodes.Ldlen);
3826 ec.ig.Emit (OpCodes.Conv_I4);
3831 Invocation.EmitCall (ec, IsBase, IsStatic, InstanceExpression, getter, null, loc, prepared, false);
3834 ec.ig.Emit (OpCodes.Dup);
3836 temp = new LocalTemporary (this.Type);
3843 // Implements the IAssignMethod interface for assignments
3845 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
3847 Expression my_source = source;
3849 prepared = prepare_for_load;
3854 ec.ig.Emit (OpCodes.Dup);
3856 temp = new LocalTemporary (this.Type);
3860 } else if (leave_copy) {
3863 temp = new LocalTemporary (this.Type);
3869 ArrayList args = new ArrayList (1);
3870 args.Add (new Argument (my_source, Argument.AType.Expression));
3872 Invocation.EmitCall (ec, IsBase, IsStatic, InstanceExpression, setter, args, loc, false, prepared);
3882 /// Fully resolved expression that evaluates to an Event
3884 public class EventExpr : MemberExpr {
3885 public readonly EventInfo EventInfo;
3888 MethodInfo add_accessor, remove_accessor;
3890 internal static PtrHashtable AccessorTable = new PtrHashtable ();
3892 public EventExpr (EventInfo ei, Location loc)
3896 eclass = ExprClass.EventAccess;
3898 add_accessor = TypeManager.GetAddMethod (ei);
3899 remove_accessor = TypeManager.GetRemoveMethod (ei);
3900 if (add_accessor != null)
3901 AccessorTable [add_accessor] = ei;
3902 if (remove_accessor != null)
3903 AccessorTable [remove_accessor] = ei;
3905 if (add_accessor.IsStatic || remove_accessor.IsStatic)
3908 if (EventInfo is MyEventBuilder){
3909 MyEventBuilder eb = (MyEventBuilder) EventInfo;
3910 type = eb.EventType;
3913 type = EventInfo.EventHandlerType;
3916 public override string Name {
3918 return EventInfo.Name;
3922 public override bool IsInstance {
3928 public override bool IsStatic {
3934 public override Type DeclaringType {
3936 return EventInfo.DeclaringType;
3940 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3941 SimpleName original)
3944 // If the event is local to this class, we transform ourselves into a FieldExpr
3947 if (EventInfo.DeclaringType == ec.ContainerType ||
3948 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
3949 MemberInfo mi = TypeManager.GetPrivateFieldOfEvent (EventInfo);
3952 MemberExpr ml = (MemberExpr) ExprClassFromMemberInfo (ec.ContainerType, mi, loc);
3955 Report.Error (-200, loc, "Internal error!!");
3959 InstanceExpression = null;
3961 return ml.ResolveMemberAccess (ec, left, loc, original);
3965 return base.ResolveMemberAccess (ec, left, loc, original);
3969 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
3972 InstanceExpression = null;
3976 if (InstanceExpression == null) {
3977 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3981 InstanceExpression = InstanceExpression.DoResolve (ec);
3982 if (InstanceExpression == null)
3986 // This is using the same mechanism as the CS1540 check in PropertyExpr.
3987 // However, in the Event case, we reported a CS0122 instead.
3989 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
3990 InstanceExpression.Type != ec.ContainerType &&
3991 ec.ContainerType.IsSubclassOf (InstanceExpression.Type)) {
3992 Report.SymbolRelatedToPreviousError (EventInfo);
3993 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
4000 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
4002 return DoResolve (ec);
4005 public override Expression DoResolve (EmitContext ec)
4007 bool must_do_cs1540_check;
4008 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
4009 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
4010 Report.SymbolRelatedToPreviousError (EventInfo);
4011 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
4015 if (!InstanceResolve (ec, must_do_cs1540_check))
4021 public override void Emit (EmitContext ec)
4023 if (InstanceExpression is This)
4024 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of += or -=", GetSignatureForError ());
4026 Report.Error (70, loc, "The event `{0}' can only appear on the left hand side of += or -= "+
4027 "(except on the defining type)", Name);
4030 public override string GetSignatureForError ()
4032 return TypeManager.CSharpSignature (EventInfo);
4035 public void EmitAddOrRemove (EmitContext ec, Expression source)
4037 BinaryDelegate source_del = (BinaryDelegate) source;
4038 Expression handler = source_del.Right;
4040 Argument arg = new Argument (handler, Argument.AType.Expression);
4041 ArrayList args = new ArrayList ();
4045 if (source_del.IsAddition)
4046 Invocation.EmitCall (
4047 ec, false, IsStatic, InstanceExpression, add_accessor, args, loc);
4049 Invocation.EmitCall (
4050 ec, false, IsStatic, InstanceExpression, remove_accessor, args, loc);
4055 public class TemporaryVariable : Expression, IMemoryLocation
4059 public TemporaryVariable (Type type, Location loc)
4063 eclass = ExprClass.Value;
4066 public override Expression DoResolve (EmitContext ec)
4071 TypeExpr te = new TypeExpression (type, loc);
4072 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
4073 if (!li.Resolve (ec))
4076 AnonymousContainer am = ec.CurrentAnonymousMethod;
4077 if ((am != null) && am.IsIterator)
4078 ec.CaptureVariable (li);
4083 public override void Emit (EmitContext ec)
4085 ILGenerator ig = ec.ig;
4087 if (li.FieldBuilder != null) {
4088 ig.Emit (OpCodes.Ldarg_0);
4089 ig.Emit (OpCodes.Ldfld, li.FieldBuilder);
4091 ig.Emit (OpCodes.Ldloc, li.LocalBuilder);
4095 public void EmitLoadAddress (EmitContext ec)
4097 ILGenerator ig = ec.ig;
4099 if (li.FieldBuilder != null) {
4100 ig.Emit (OpCodes.Ldarg_0);
4101 ig.Emit (OpCodes.Ldflda, li.FieldBuilder);
4103 ig.Emit (OpCodes.Ldloca, li.LocalBuilder);
4107 public void Store (EmitContext ec, Expression right_side)
4109 if (li.FieldBuilder != null)
4110 ec.ig.Emit (OpCodes.Ldarg_0);
4112 right_side.Emit (ec);
4113 if (li.FieldBuilder != null) {
4114 ec.ig.Emit (OpCodes.Stfld, li.FieldBuilder);
4116 ec.ig.Emit (OpCodes.Stloc, li.LocalBuilder);
4120 public void EmitThis (EmitContext ec)
4122 if (li.FieldBuilder != null) {
4123 ec.ig.Emit (OpCodes.Ldarg_0);
4127 public void EmitStore (ILGenerator ig)
4129 if (li.FieldBuilder != null)
4130 ig.Emit (OpCodes.Stfld, li.FieldBuilder);
4132 ig.Emit (OpCodes.Stloc, li.LocalBuilder);
4135 public void AddressOf (EmitContext ec, AddressOp mode)
4137 EmitLoadAddress (ec);