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.DeclContainer 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 virtual void Error_ValueCannotBeConverted (Location loc, Type target, bool expl)
308 if (Type.FullName == target.FullName){
309 Report.ExtraInformation (loc,
311 "The type {0} has two conflicting definitions, one comes from {1} and the other from {2}",
312 Type.FullName, Type.Assembly.FullName, target.Assembly.FullName));
317 Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
318 GetSignatureForError (), TypeManager.CSharpName (target));
322 Expression e = (this is EnumConstant) ? ((EnumConstant)this).Child : this;
323 bool b = Convert.ExplicitNumericConversion (e, target) != null;
325 if (b || Convert.ExplicitReferenceConversionExists (Type, target) || Convert.ExplicitUnsafe (e, target) != null) {
326 Report.Error (266, loc, "Cannot implicitly convert type `{0}' to `{1}'. An explicit conversion exists (are you missing a cast?)",
327 TypeManager.CSharpName (Type), TypeManager.CSharpName (target));
331 if (Type != TypeManager.string_type && this is Constant && !(this is NullCast)) {
332 Report.Error (31, loc, "Constant value `{0}' cannot be converted to a `{1}'",
333 GetSignatureForError (), TypeManager.CSharpName (target));
337 Report.Error (29, loc, "Cannot implicitly convert type {0} to `{1}'",
338 Type == TypeManager.anonymous_method_type ?
339 "anonymous method" : "`" + GetSignatureForError () + "'",
340 TypeManager.CSharpName (target));
343 protected static void Error_TypeDoesNotContainDefinition (Location loc, Type type, string name)
345 Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
346 TypeManager.CSharpName (type), name);
349 ResolveFlags ExprClassToResolveFlags
354 case ExprClass.Namespace:
355 return ResolveFlags.Type;
357 case ExprClass.MethodGroup:
358 return ResolveFlags.MethodGroup;
360 case ExprClass.Value:
361 case ExprClass.Variable:
362 case ExprClass.PropertyAccess:
363 case ExprClass.EventAccess:
364 case ExprClass.IndexerAccess:
365 return ResolveFlags.VariableOrValue;
368 throw new Exception ("Expression " + GetType () +
369 " ExprClass is Invalid after resolve");
375 /// Resolves an expression and performs semantic analysis on it.
379 /// Currently Resolve wraps DoResolve to perform sanity
380 /// checking and assertion checking on what we expect from Resolve.
382 public Expression Resolve (EmitContext ec, ResolveFlags flags)
384 if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type)
385 return ResolveAsTypeStep (ec, false);
387 bool do_flow_analysis = ec.DoFlowAnalysis;
388 bool omit_struct_analysis = ec.OmitStructFlowAnalysis;
389 if ((flags & ResolveFlags.DisableFlowAnalysis) != 0)
390 do_flow_analysis = false;
391 if ((flags & ResolveFlags.DisableStructFlowAnalysis) != 0)
392 omit_struct_analysis = true;
395 using (ec.WithFlowAnalysis (do_flow_analysis, omit_struct_analysis)) {
396 if (this is SimpleName) {
397 bool intermediate = (flags & ResolveFlags.Intermediate) == ResolveFlags.Intermediate;
398 e = ((SimpleName) this).DoResolve (ec, intermediate);
407 if ((flags & e.ExprClassToResolveFlags) == 0) {
408 e.Error_UnexpectedKind (flags, loc);
412 if (e.type == null && !(e is Namespace)) {
413 throw new Exception (
414 "Expression " + e.GetType () +
415 " did not set its type after Resolve\n" +
416 "called from: " + this.GetType ());
423 /// Resolves an expression and performs semantic analysis on it.
425 public Expression Resolve (EmitContext ec)
427 Expression e = Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
429 if (e != null && e.eclass == ExprClass.MethodGroup && RootContext.Version == LanguageVersion.ISO_1) {
430 ((MethodGroupExpr) e).ReportUsageError ();
436 public Constant ResolveAsConstant (EmitContext ec, MemberCore mc)
438 Expression e = Resolve (ec);
442 Constant c = e as Constant;
446 Type constant_type = null;
447 if (mc is MemberBase) {
448 constant_type = ((MemberBase)mc).MemberType;
451 Const.Error_ExpressionMustBeConstant (constant_type, loc, mc.GetSignatureForError ());
456 /// Resolves an expression for LValue assignment
460 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
461 /// checking and assertion checking on what we expect from Resolve
463 public Expression ResolveLValue (EmitContext ec, Expression right_side, Location loc)
465 int errors = Report.Errors;
466 bool out_access = right_side == EmptyExpression.OutAccess;
468 Expression e = DoResolveLValue (ec, right_side);
470 if (e != null && out_access && !(e is IMemoryLocation)) {
471 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
472 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
474 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
475 // e.GetType () + " " + e.GetSignatureForError ());
480 if (errors == Report.Errors) {
482 Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
484 Report.Error (131, loc, "The left-hand side of an assignment or mutating operation must be a variable, property or indexer");
489 if (e.eclass == ExprClass.Invalid)
490 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
492 if (e.eclass == ExprClass.MethodGroup) {
493 ((MethodGroupExpr) e).ReportUsageError ();
497 if ((e.type == null) && !(e is ConstructedType))
498 throw new Exception ("Expression " + e + " did not set its type after Resolve");
504 /// Emits the code for the expression
508 /// The Emit method is invoked to generate the code
509 /// for the expression.
511 public abstract void Emit (EmitContext ec);
513 public virtual void EmitBranchable (EmitContext ec, Label target, bool onTrue)
516 ec.ig.Emit (onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target);
520 /// Protected constructor. Only derivate types should
521 /// be able to be created
524 protected Expression ()
526 eclass = ExprClass.Invalid;
531 /// Returns a literalized version of a literal FieldInfo
535 /// The possible return values are:
536 /// IntConstant, UIntConstant
537 /// LongLiteral, ULongConstant
538 /// FloatConstant, DoubleConstant
541 /// The value returned is already resolved.
543 public static Constant Constantify (object v, Type t)
545 if (t == TypeManager.int32_type)
546 return new IntConstant ((int) v, Location.Null);
547 else if (t == TypeManager.uint32_type)
548 return new UIntConstant ((uint) v, Location.Null);
549 else if (t == TypeManager.int64_type)
550 return new LongConstant ((long) v, Location.Null);
551 else if (t == TypeManager.uint64_type)
552 return new ULongConstant ((ulong) v, Location.Null);
553 else if (t == TypeManager.float_type)
554 return new FloatConstant ((float) v, Location.Null);
555 else if (t == TypeManager.double_type)
556 return new DoubleConstant ((double) v, Location.Null);
557 else if (t == TypeManager.string_type)
558 return new StringConstant ((string) v, Location.Null);
559 else if (t == TypeManager.short_type)
560 return new ShortConstant ((short)v, Location.Null);
561 else if (t == TypeManager.ushort_type)
562 return new UShortConstant ((ushort)v, Location.Null);
563 else if (t == TypeManager.sbyte_type)
564 return new SByteConstant ((sbyte)v, Location.Null);
565 else if (t == TypeManager.byte_type)
566 return new ByteConstant ((byte)v, Location.Null);
567 else if (t == TypeManager.char_type)
568 return new CharConstant ((char)v, Location.Null);
569 else if (t == TypeManager.bool_type)
570 return new BoolConstant ((bool) v, Location.Null);
571 else if (t == TypeManager.decimal_type)
572 return new DecimalConstant ((decimal) v, Location.Null);
573 else if (TypeManager.IsEnumType (t)){
574 Type real_type = TypeManager.TypeToCoreType (v.GetType ());
576 real_type = System.Enum.GetUnderlyingType (real_type);
578 Constant e = Constantify (v, real_type);
580 return new EnumConstant (e, t);
581 } else if (v == null && !TypeManager.IsValueType (t))
582 return new NullLiteral (Location.Null);
584 throw new Exception ("Unknown type for constant (" + t +
589 /// Returns a fully formed expression after a MemberLookup
592 public static Expression ExprClassFromMemberInfo (Type containerType, MemberInfo mi, Location loc)
595 return new EventExpr ((EventInfo) mi, loc);
596 else if (mi is FieldInfo)
597 return new FieldExpr ((FieldInfo) mi, loc);
598 else if (mi is PropertyInfo)
599 return new PropertyExpr (containerType, (PropertyInfo) mi, loc);
600 else if (mi is Type){
601 return new TypeExpression ((System.Type) mi, loc);
607 protected static ArrayList almostMatchedMembers = new ArrayList (4);
610 // FIXME: Probably implement a cache for (t,name,current_access_set)?
612 // This code could use some optimizations, but we need to do some
613 // measurements. For example, we could use a delegate to `flag' when
614 // something can not any longer be a method-group (because it is something
618 // If the return value is an Array, then it is an array of
621 // If the return value is an MemberInfo, it is anything, but a Method
625 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
626 // the arguments here and have MemberLookup return only the methods that
627 // match the argument count/type, unlike we are doing now (we delay this
630 // This is so we can catch correctly attempts to invoke instance methods
631 // from a static body (scan for error 120 in ResolveSimpleName).
634 // FIXME: Potential optimization, have a static ArrayList
637 public static Expression MemberLookup (Type container_type, Type queried_type, string name,
638 MemberTypes mt, BindingFlags bf, Location loc)
640 return MemberLookup (container_type, null, queried_type, name, mt, bf, loc);
644 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
645 // `qualifier_type' or null to lookup members in the current class.
648 public static Expression MemberLookup (Type container_type,
649 Type qualifier_type, Type queried_type,
650 string name, MemberTypes mt,
651 BindingFlags bf, Location loc)
653 almostMatchedMembers.Clear ();
655 MemberInfo [] mi = TypeManager.MemberLookup (container_type, qualifier_type,
656 queried_type, mt, bf, name, almostMatchedMembers);
662 MemberInfo non_method = null;
663 ArrayList methods = new ArrayList (2);
664 foreach (MemberInfo m in mi) {
665 if (m is MethodBase) {
670 if (non_method == null) {
675 Report.SymbolRelatedToPreviousError (m);
676 Report.SymbolRelatedToPreviousError (non_method);
677 Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
678 TypeManager.GetFullNameSignature (m), TypeManager.GetFullNameSignature (non_method));
682 if (non_method != null) {
683 MethodBase method = (MethodBase)methods[0];
684 Report.SymbolRelatedToPreviousError (method);
685 Report.SymbolRelatedToPreviousError (non_method);
686 Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and non-method `{1}'. Using method `{0}'",
687 TypeManager.CSharpSignature (method), TypeManager.GetFullNameSignature (non_method));
690 return new MethodGroupExpr (methods, loc);
693 if (mi [0] is MethodBase)
694 return new MethodGroupExpr (mi, loc);
696 return ExprClassFromMemberInfo (container_type, mi [0], loc);
699 public const MemberTypes AllMemberTypes =
700 MemberTypes.Constructor |
704 MemberTypes.NestedType |
705 MemberTypes.Property;
707 public const BindingFlags AllBindingFlags =
708 BindingFlags.Public |
709 BindingFlags.Static |
710 BindingFlags.Instance;
712 public static Expression MemberLookup (Type container_type, Type queried_type,
713 string name, Location loc)
715 return MemberLookup (container_type, null, queried_type, name,
716 AllMemberTypes, AllBindingFlags, loc);
719 public static Expression MemberLookup (Type container_type, Type qualifier_type,
720 Type queried_type, string name, Location loc)
722 return MemberLookup (container_type, qualifier_type, queried_type,
723 name, AllMemberTypes, AllBindingFlags, loc);
726 public static Expression MethodLookup (EmitContext ec, Type queried_type,
727 string name, Location loc)
729 return MemberLookup (ec.ContainerType, null, queried_type, name,
730 MemberTypes.Method, AllBindingFlags, loc);
734 /// This is a wrapper for MemberLookup that is not used to "probe", but
735 /// to find a final definition. If the final definition is not found, we
736 /// look for private members and display a useful debugging message if we
739 public static Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
740 Type queried_type, string name, Location loc)
742 return MemberLookupFinal (ec, qualifier_type, queried_type, name,
743 AllMemberTypes, AllBindingFlags, loc);
746 public static Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
747 Type queried_type, string name,
748 MemberTypes mt, BindingFlags bf,
753 int errors = Report.Errors;
755 e = MemberLookup (ec.ContainerType, qualifier_type, queried_type, name, mt, bf, loc);
757 if (e == null && errors == Report.Errors)
758 // No errors were reported by MemberLookup, but there was an error.
759 MemberLookupFailed (ec.ContainerType, qualifier_type, queried_type, name, null, true, loc);
764 public static void MemberLookupFailed (Type container_type, Type qualifier_type,
765 Type queried_type, string name,
766 string class_name, bool complain_if_none_found,
769 if (almostMatchedMembers.Count != 0) {
770 for (int i = 0; i < almostMatchedMembers.Count; ++i) {
771 MemberInfo m = (MemberInfo) almostMatchedMembers [i];
772 for (int j = 0; j < i; ++j) {
773 if (m == almostMatchedMembers [j]) {
781 Type declaring_type = m.DeclaringType;
783 Report.SymbolRelatedToPreviousError (m);
784 if (qualifier_type == null) {
785 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
786 TypeManager.CSharpName (m.DeclaringType),
787 TypeManager.CSharpName (container_type));
789 } else if (qualifier_type != container_type &&
790 TypeManager.IsNestedFamilyAccessible (container_type, declaring_type)) {
791 // Although a derived class can access protected members of
792 // its base class it cannot do so through an instance of the
793 // base class (CS1540). If the qualifier_type is a base of the
794 // ec.ContainerType and the lookup succeeds with the latter one,
795 // then we are in this situation.
796 Error_CannotAccessProtected (loc, m, qualifier_type, container_type);
798 Report.SymbolRelatedToPreviousError (m);
799 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (m));
802 almostMatchedMembers.Clear ();
806 MemberInfo[] lookup = null;
807 if (queried_type == null) {
808 class_name = "global::";
810 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
811 AllMemberTypes, AllBindingFlags |
812 BindingFlags.NonPublic, name, null);
815 if (lookup == null) {
816 if (!complain_if_none_found)
819 if (class_name != null)
820 Report.Error (103, loc, "The name `{0}' does not exist in the context of `{1}'",
823 Error_TypeDoesNotContainDefinition (loc, queried_type, name);
827 if (TypeManager.MemberLookup (queried_type, null, queried_type,
828 AllMemberTypes, AllBindingFlags |
829 BindingFlags.NonPublic, name, null) == null) {
830 if ((lookup.Length == 1) && (lookup [0] is Type)) {
831 Type t = (Type) lookup [0];
833 Report.Error (305, loc,
834 "Using the generic type `{0}' " +
835 "requires {1} type arguments",
836 TypeManager.CSharpName (t),
837 TypeManager.GetNumberOfTypeArguments (t).ToString ());
842 MemberList ml = TypeManager.FindMembers (queried_type, MemberTypes.Constructor,
843 BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly, null, null);
844 if (name == ".ctor" && ml.Count == 0)
846 Report.Error (143, loc, "The type `{0}' has no constructors defined", TypeManager.CSharpName (queried_type));
850 Report.SymbolRelatedToPreviousError (lookup [0]);
851 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (lookup [0]));
855 /// Returns an expression that can be used to invoke operator true
856 /// on the expression if it exists.
858 static public Expression GetOperatorTrue (EmitContext ec, Expression e, Location loc)
860 return GetOperatorTrueOrFalse (ec, e, true, loc);
864 /// Returns an expression that can be used to invoke operator false
865 /// on the expression if it exists.
867 static public Expression GetOperatorFalse (EmitContext ec, Expression e, Location loc)
869 return GetOperatorTrueOrFalse (ec, e, false, loc);
872 static Expression GetOperatorTrueOrFalse (EmitContext ec, Expression e, bool is_true, Location loc)
875 Expression operator_group;
877 if (TypeManager.IsNullableType (e.Type))
878 return new Nullable.OperatorTrueOrFalse (e, is_true, loc).Resolve (ec);
880 operator_group = MethodLookup (ec, e.Type, is_true ? "op_True" : "op_False", loc);
881 if (operator_group == null)
884 ArrayList arguments = new ArrayList ();
885 arguments.Add (new Argument (e, Argument.AType.Expression));
886 method = Invocation.OverloadResolve (
887 ec, (MethodGroupExpr) operator_group, arguments, false, loc);
892 return new StaticCallExpr ((MethodInfo) method, arguments, loc);
896 /// Resolves the expression `e' into a boolean expression: either through
897 /// an implicit conversion, or through an `operator true' invocation
899 public static Expression ResolveBoolean (EmitContext ec, Expression e, Location loc)
905 if (e.Type == TypeManager.bool_type)
908 Expression converted = Convert.ImplicitConversion (ec, e, TypeManager.bool_type, Location.Null);
910 if (converted != null)
914 // If no implicit conversion to bool exists, try using `operator true'
916 converted = Expression.GetOperatorTrue (ec, e, loc);
917 if (converted == null){
918 e.Error_ValueCannotBeConverted (loc, TypeManager.bool_type, false);
924 public virtual string ExprClassName
928 case ExprClass.Invalid:
930 case ExprClass.Value:
932 case ExprClass.Variable:
934 case ExprClass.Namespace:
938 case ExprClass.MethodGroup:
939 return "method group";
940 case ExprClass.PropertyAccess:
941 return "property access";
942 case ExprClass.EventAccess:
943 return "event access";
944 case ExprClass.IndexerAccess:
945 return "indexer access";
946 case ExprClass.Nothing:
949 throw new Exception ("Should not happen");
954 /// Reports that we were expecting `expr' to be of class `expected'
956 public void Error_UnexpectedKind (DeclSpace ds, string expected, Location loc)
958 Error_UnexpectedKind (ds, expected, ExprClassName, loc);
961 public void Error_UnexpectedKind (DeclSpace ds, string expected, string was, Location loc)
963 string name = GetSignatureForError ();
965 name = ds.GetSignatureForError () + '.' + name;
967 Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
968 name, was, expected);
971 public void Error_UnexpectedKind (ResolveFlags flags, Location loc)
973 string [] valid = new string [4];
976 if ((flags & ResolveFlags.VariableOrValue) != 0) {
977 valid [count++] = "variable";
978 valid [count++] = "value";
981 if ((flags & ResolveFlags.Type) != 0)
982 valid [count++] = "type";
984 if ((flags & ResolveFlags.MethodGroup) != 0)
985 valid [count++] = "method group";
988 valid [count++] = "unknown";
990 StringBuilder sb = new StringBuilder (valid [0]);
991 for (int i = 1; i < count - 1; i++) {
993 sb.Append (valid [i]);
996 sb.Append ("' or `");
997 sb.Append (valid [count - 1]);
1000 Report.Error (119, loc,
1001 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1004 public static void UnsafeError (Location loc)
1006 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1010 // Load the object from the pointer.
1012 public static void LoadFromPtr (ILGenerator ig, Type t)
1014 if (t == TypeManager.int32_type)
1015 ig.Emit (OpCodes.Ldind_I4);
1016 else if (t == TypeManager.uint32_type)
1017 ig.Emit (OpCodes.Ldind_U4);
1018 else if (t == TypeManager.short_type)
1019 ig.Emit (OpCodes.Ldind_I2);
1020 else if (t == TypeManager.ushort_type)
1021 ig.Emit (OpCodes.Ldind_U2);
1022 else if (t == TypeManager.char_type)
1023 ig.Emit (OpCodes.Ldind_U2);
1024 else if (t == TypeManager.byte_type)
1025 ig.Emit (OpCodes.Ldind_U1);
1026 else if (t == TypeManager.sbyte_type)
1027 ig.Emit (OpCodes.Ldind_I1);
1028 else if (t == TypeManager.uint64_type)
1029 ig.Emit (OpCodes.Ldind_I8);
1030 else if (t == TypeManager.int64_type)
1031 ig.Emit (OpCodes.Ldind_I8);
1032 else if (t == TypeManager.float_type)
1033 ig.Emit (OpCodes.Ldind_R4);
1034 else if (t == TypeManager.double_type)
1035 ig.Emit (OpCodes.Ldind_R8);
1036 else if (t == TypeManager.bool_type)
1037 ig.Emit (OpCodes.Ldind_I1);
1038 else if (t == TypeManager.intptr_type)
1039 ig.Emit (OpCodes.Ldind_I);
1040 else if (TypeManager.IsEnumType (t)) {
1041 if (t == TypeManager.enum_type)
1042 ig.Emit (OpCodes.Ldind_Ref);
1044 LoadFromPtr (ig, TypeManager.EnumToUnderlying (t));
1045 } else if (t.IsValueType || t.IsGenericParameter)
1046 ig.Emit (OpCodes.Ldobj, t);
1047 else if (t.IsPointer)
1048 ig.Emit (OpCodes.Ldind_I);
1050 ig.Emit (OpCodes.Ldind_Ref);
1054 // The stack contains the pointer and the value of type `type'
1056 public static void StoreFromPtr (ILGenerator ig, Type type)
1058 if (TypeManager.IsEnumType (type))
1059 type = TypeManager.EnumToUnderlying (type);
1060 if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
1061 ig.Emit (OpCodes.Stind_I4);
1062 else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
1063 ig.Emit (OpCodes.Stind_I8);
1064 else if (type == TypeManager.char_type || type == TypeManager.short_type ||
1065 type == TypeManager.ushort_type)
1066 ig.Emit (OpCodes.Stind_I2);
1067 else if (type == TypeManager.float_type)
1068 ig.Emit (OpCodes.Stind_R4);
1069 else if (type == TypeManager.double_type)
1070 ig.Emit (OpCodes.Stind_R8);
1071 else if (type == TypeManager.byte_type || type == TypeManager.sbyte_type ||
1072 type == TypeManager.bool_type)
1073 ig.Emit (OpCodes.Stind_I1);
1074 else if (type == TypeManager.intptr_type)
1075 ig.Emit (OpCodes.Stind_I);
1076 else if (type.IsValueType || type.IsGenericParameter)
1077 ig.Emit (OpCodes.Stobj, type);
1079 ig.Emit (OpCodes.Stind_Ref);
1083 // Returns the size of type `t' if known, otherwise, 0
1085 public static int GetTypeSize (Type t)
1087 t = TypeManager.TypeToCoreType (t);
1088 if (t == TypeManager.int32_type ||
1089 t == TypeManager.uint32_type ||
1090 t == TypeManager.float_type)
1092 else if (t == TypeManager.int64_type ||
1093 t == TypeManager.uint64_type ||
1094 t == TypeManager.double_type)
1096 else if (t == TypeManager.byte_type ||
1097 t == TypeManager.sbyte_type ||
1098 t == TypeManager.bool_type)
1100 else if (t == TypeManager.short_type ||
1101 t == TypeManager.char_type ||
1102 t == TypeManager.ushort_type)
1104 else if (t == TypeManager.decimal_type)
1110 public static void Error_NegativeArrayIndex (Location loc)
1112 Report.Error (248, loc, "Cannot create an array with a negative size");
1115 protected void Error_CannotCallAbstractBase (string name)
1117 Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
1121 // Converts `source' to an int, uint, long or ulong.
1123 public Expression ExpressionToArrayArgument (EmitContext ec, Expression source, Location loc)
1127 using (ec.With (EmitContext.Flags.CheckState, true)) {
1128 target = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, loc);
1130 target = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, loc);
1132 target = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, loc);
1134 target = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, loc);
1136 if (target == null) {
1137 source.Error_ValueCannotBeConverted (loc, TypeManager.int32_type, false);
1143 // Only positive constants are allowed at compile time
1145 if (target is Constant){
1146 if (target is IntConstant){
1147 if (((IntConstant) target).Value < 0){
1148 Error_NegativeArrayIndex (loc);
1153 if (target is LongConstant){
1154 if (((LongConstant) target).Value < 0){
1155 Error_NegativeArrayIndex (loc);
1168 /// This is just a base class for expressions that can
1169 /// appear on statements (invocations, object creation,
1170 /// assignments, post/pre increment and decrement). The idea
1171 /// being that they would support an extra Emition interface that
1172 /// does not leave a result on the stack.
1174 public abstract class ExpressionStatement : Expression {
1176 public virtual ExpressionStatement ResolveStatement (EmitContext ec)
1178 Expression e = Resolve (ec);
1182 ExpressionStatement es = e as ExpressionStatement;
1184 Error (201, "Only assignment, call, increment, decrement and new object " +
1185 "expressions can be used as a statement");
1191 /// Requests the expression to be emitted in a `statement'
1192 /// context. This means that no new value is left on the
1193 /// stack after invoking this method (constrasted with
1194 /// Emit that will always leave a value on the stack).
1196 public abstract void EmitStatement (EmitContext ec);
1200 /// This kind of cast is used to encapsulate the child
1201 /// whose type is child.Type into an expression that is
1202 /// reported to return "return_type". This is used to encapsulate
1203 /// expressions which have compatible types, but need to be dealt
1204 /// at higher levels with.
1206 /// For example, a "byte" expression could be encapsulated in one
1207 /// of these as an "unsigned int". The type for the expression
1208 /// would be "unsigned int".
1211 public class EmptyCast : Expression {
1212 protected readonly Expression child;
1214 public EmptyCast (Expression child, Type return_type)
1216 eclass = child.eclass;
1217 loc = child.Location;
1222 public override Expression DoResolve (EmitContext ec)
1224 // This should never be invoked, we are born in fully
1225 // initialized state.
1230 public override void Emit (EmitContext ec)
1235 public override bool GetAttributableValue (Type valueType, out object value)
1237 return child.GetAttributableValue (valueType, out value);
1242 /// This is a numeric cast to a Decimal
1244 public class CastToDecimal : EmptyCast {
1246 MethodInfo conversion_operator;
1248 public CastToDecimal (Expression child)
1249 : this (child, false)
1253 public CastToDecimal (Expression child, bool find_explicit)
1254 : base (child, TypeManager.decimal_type)
1256 conversion_operator = GetConversionOperator (find_explicit);
1258 if (conversion_operator == null)
1259 throw new InternalErrorException ("Outer conversion routine is out of sync");
1262 // Returns the implicit operator that converts from
1263 // 'child.Type' to System.Decimal.
1264 MethodInfo GetConversionOperator (bool find_explicit)
1266 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1268 MemberInfo [] mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1269 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1271 foreach (MethodInfo oper in mi) {
1272 ParameterData pd = TypeManager.GetParameterData (oper);
1274 if (pd.ParameterType (0) == child.Type && oper.ReturnType == type)
1280 public override void Emit (EmitContext ec)
1282 ILGenerator ig = ec.ig;
1285 ig.Emit (OpCodes.Call, conversion_operator);
1290 /// This is an explicit numeric cast from a Decimal
1292 public class CastFromDecimal : EmptyCast
1294 static IDictionary operators;
1296 public CastFromDecimal (Expression child, Type return_type)
1297 : base (child, return_type)
1299 if (child.Type != TypeManager.decimal_type)
1300 throw new InternalErrorException (
1301 "The expected type is Decimal, instead it is " + child.Type.FullName);
1304 // Returns the explicit operator that converts from an
1305 // express of type System.Decimal to 'type'.
1306 public Expression Resolve ()
1308 if (operators == null) {
1309 MemberInfo[] all_oper = TypeManager.MemberLookup (TypeManager.decimal_type,
1310 TypeManager.decimal_type, TypeManager.decimal_type, MemberTypes.Method,
1311 BindingFlags.Static | BindingFlags.Public, "op_Explicit", null);
1313 operators = new System.Collections.Specialized.HybridDictionary ();
1314 foreach (MethodInfo oper in all_oper) {
1315 ParameterData pd = TypeManager.GetParameterData (oper);
1316 if (pd.ParameterType (0) == TypeManager.decimal_type)
1317 operators.Add (oper.ReturnType, oper);
1321 return operators.Contains (type) ? this : null;
1324 public override void Emit (EmitContext ec)
1326 ILGenerator ig = ec.ig;
1329 ig.Emit (OpCodes.Call, (MethodInfo)operators [type]);
1334 // We need to special case this since an empty cast of
1335 // a NullLiteral is still a Constant
1337 public class NullCast : Constant {
1338 public Constant child;
1340 public NullCast (Constant child, Type return_type):
1341 base (Location.Null)
1343 eclass = child.eclass;
1348 override public string AsString ()
1353 public override object GetValue ()
1358 public override Expression DoResolve (EmitContext ec)
1360 // This should never be invoked, we are born in fully
1361 // initialized state.
1366 public override void Emit (EmitContext ec)
1371 public override Constant Increment ()
1373 throw new NotSupportedException ();
1376 public override bool IsDefaultValue {
1382 public override bool IsNegative {
1388 public override Constant Reduce (bool inCheckedContext, Type target_type)
1390 if (type == target_type)
1391 return child.Reduce (inCheckedContext, target_type);
1400 /// This class is used to wrap literals which belong inside Enums
1402 public class EnumConstant : Constant {
1403 public Constant Child;
1405 public EnumConstant (Constant child, Type enum_type):
1406 base (child.Location)
1408 eclass = child.eclass;
1413 public override Expression DoResolve (EmitContext ec)
1415 // This should never be invoked, we are born in fully
1416 // initialized state.
1421 public override void Emit (EmitContext ec)
1426 public override bool GetAttributableValue (Type valueType, out object value)
1428 value = GetTypedValue ();
1432 public override string GetSignatureForError()
1434 return TypeManager.CSharpName (Type);
1437 public override object GetValue ()
1439 return Child.GetValue ();
1442 public override object GetTypedValue ()
1444 // FIXME: runtime is not ready to work with just emited enums
1445 if (!RootContext.StdLib) {
1446 return Child.GetValue ();
1449 return System.Enum.ToObject (type, Child.GetValue ());
1452 public override string AsString ()
1454 return Child.AsString ();
1457 public override DoubleConstant ConvertToDouble ()
1459 return Child.ConvertToDouble ();
1462 public override FloatConstant ConvertToFloat ()
1464 return Child.ConvertToFloat ();
1467 public override ULongConstant ConvertToULong ()
1469 return Child.ConvertToULong ();
1472 public override LongConstant ConvertToLong ()
1474 return Child.ConvertToLong ();
1477 public override UIntConstant ConvertToUInt ()
1479 return Child.ConvertToUInt ();
1482 public override IntConstant ConvertToInt ()
1484 return Child.ConvertToInt ();
1487 public override Constant Increment()
1489 return new EnumConstant (Child.Increment (), type);
1492 public override bool IsDefaultValue {
1494 return Child.IsDefaultValue;
1498 public override bool IsZeroInteger {
1499 get { return Child.IsZeroInteger; }
1502 public override bool IsNegative {
1504 return Child.IsNegative;
1508 public override Constant Reduce(bool inCheckedContext, Type target_type)
1510 if (Child.Type == target_type)
1513 return Child.Reduce (inCheckedContext, target_type);
1516 public override Constant ToType (Type type, Location loc)
1519 // This is workaround of mono bug. It can be removed when the latest corlib spreads enough
1520 if (TypeManager.IsEnumType (type.UnderlyingSystemType))
1523 if (type.UnderlyingSystemType != Child.Type)
1524 Child = Child.ToType (type.UnderlyingSystemType, loc);
1528 if (!Convert.ImplicitStandardConversionExists (this, type)){
1529 Error_ValueCannotBeConverted (loc, type, false);
1533 return Child.ToType (type, loc);
1539 /// This kind of cast is used to encapsulate Value Types in objects.
1541 /// The effect of it is to box the value type emitted by the previous
1544 public class BoxedCast : EmptyCast {
1546 public BoxedCast (Expression expr, Type target_type)
1547 : base (expr, target_type)
1549 eclass = ExprClass.Value;
1552 public override Expression DoResolve (EmitContext ec)
1554 // This should never be invoked, we are born in fully
1555 // initialized state.
1560 public override void Emit (EmitContext ec)
1564 ec.ig.Emit (OpCodes.Box, child.Type);
1568 public class UnboxCast : EmptyCast {
1569 public UnboxCast (Expression expr, Type return_type)
1570 : base (expr, return_type)
1574 public override Expression DoResolve (EmitContext ec)
1576 // This should never be invoked, we are born in fully
1577 // initialized state.
1582 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1584 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
1585 Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
1586 return base.DoResolveLValue (ec, right_side);
1589 public override void Emit (EmitContext ec)
1592 ILGenerator ig = ec.ig;
1595 if (t.IsGenericParameter || t.IsGenericType && t.IsValueType)
1596 ig.Emit (OpCodes.Unbox_Any, t);
1598 ig.Emit (OpCodes.Unbox, t);
1600 LoadFromPtr (ig, t);
1606 /// This is used to perform explicit numeric conversions.
1608 /// Explicit numeric conversions might trigger exceptions in a checked
1609 /// context, so they should generate the conv.ovf opcodes instead of
1612 public class ConvCast : EmptyCast {
1613 public enum Mode : byte {
1614 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1616 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1617 U2_I1, U2_U1, U2_I2, U2_CH,
1618 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1619 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1620 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH,
1621 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH,
1622 CH_I1, CH_U1, CH_I2,
1623 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1624 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4
1629 public ConvCast (Expression child, Type return_type, Mode m)
1630 : base (child, return_type)
1635 public override Expression DoResolve (EmitContext ec)
1637 // This should never be invoked, we are born in fully
1638 // initialized state.
1643 public override string ToString ()
1645 return String.Format ("ConvCast ({0}, {1})", mode, child);
1648 public override void Emit (EmitContext ec)
1650 ILGenerator ig = ec.ig;
1656 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1657 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1658 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1659 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1660 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1662 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1663 case Mode.U1_CH: /* nothing */ break;
1665 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1666 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1667 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1668 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1669 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1670 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1672 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1673 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1674 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1675 case Mode.U2_CH: /* nothing */ break;
1677 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1678 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1679 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1680 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1681 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1682 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1683 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1685 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1686 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1687 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1688 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1689 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1690 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1692 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1693 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1694 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1695 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1696 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1697 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1698 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1699 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1701 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1702 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1703 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1704 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1705 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1706 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1707 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1708 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1710 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1711 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1712 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1714 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1715 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1716 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1717 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1718 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1719 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1720 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1721 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1722 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1724 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1725 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1726 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1727 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1728 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1729 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1730 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1731 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1732 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1733 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1737 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
1738 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
1739 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
1740 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
1741 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
1743 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
1744 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
1746 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
1747 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
1748 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
1749 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
1750 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
1751 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
1753 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
1754 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
1755 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
1756 case Mode.U2_CH: /* nothing */ break;
1758 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
1759 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
1760 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
1761 case Mode.I4_U4: /* nothing */ break;
1762 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
1763 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
1764 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
1766 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
1767 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
1768 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
1769 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
1770 case Mode.U4_I4: /* nothing */ break;
1771 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
1773 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
1774 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
1775 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
1776 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
1777 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
1778 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
1779 case Mode.I8_U8: /* nothing */ break;
1780 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
1782 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
1783 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
1784 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
1785 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
1786 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
1787 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
1788 case Mode.U8_I8: /* nothing */ break;
1789 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
1791 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
1792 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
1793 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
1795 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
1796 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
1797 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
1798 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
1799 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
1800 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
1801 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
1802 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
1803 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
1805 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
1806 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
1807 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
1808 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
1809 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
1810 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
1811 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
1812 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
1813 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
1814 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1820 public class OpcodeCast : EmptyCast {
1824 public OpcodeCast (Expression child, Type return_type, OpCode op)
1825 : base (child, return_type)
1829 second_valid = false;
1832 public OpcodeCast (Expression child, Type return_type, OpCode op, OpCode op2)
1833 : base (child, return_type)
1838 second_valid = true;
1841 public override Expression DoResolve (EmitContext ec)
1843 // This should never be invoked, we are born in fully
1844 // initialized state.
1849 public override void Emit (EmitContext ec)
1860 /// This kind of cast is used to encapsulate a child and cast it
1861 /// to the class requested
1863 public class ClassCast : EmptyCast {
1864 public ClassCast (Expression child, Type return_type)
1865 : base (child, return_type)
1870 public override Expression DoResolve (EmitContext ec)
1872 // This should never be invoked, we are born in fully
1873 // initialized state.
1878 public override void Emit (EmitContext ec)
1882 if (child.Type.IsGenericParameter)
1883 ec.ig.Emit (OpCodes.Box, child.Type);
1885 if (type.IsGenericParameter)
1886 ec.ig.Emit (OpCodes.Unbox_Any, type);
1888 ec.ig.Emit (OpCodes.Castclass, type);
1893 /// SimpleName expressions are formed of a single word and only happen at the beginning
1894 /// of a dotted-name.
1896 public class SimpleName : Expression {
1898 public readonly TypeArguments Arguments;
1901 public SimpleName (string name, Location l)
1907 public SimpleName (string name, TypeArguments args, Location l)
1914 public SimpleName (string name, TypeParameter[] type_params, Location l)
1919 Arguments = new TypeArguments (l);
1920 foreach (TypeParameter type_param in type_params)
1921 Arguments.Add (new TypeParameterExpr (type_param, l));
1924 public static string RemoveGenericArity (string name)
1927 StringBuilder sb = new StringBuilder ();
1928 while (start < name.Length) {
1929 int pos = name.IndexOf ('`', start);
1931 sb.Append (name.Substring (start));
1935 sb.Append (name.Substring (start, pos-start));
1938 while ((pos < name.Length) && Char.IsNumber (name [pos]))
1944 return sb.ToString ();
1947 public SimpleName GetMethodGroup ()
1949 return new SimpleName (RemoveGenericArity (Name), Arguments, loc);
1952 public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
1954 if (ec.IsFieldInitializer)
1955 Report.Error (236, l,
1956 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
1960 120, l, "`{0}': An object reference is required for the nonstatic field, method or property",
1964 public bool IdenticalNameAndTypeName (EmitContext ec, Expression resolved_to, Location loc)
1966 return resolved_to != null && resolved_to.Type != null &&
1967 resolved_to.Type.Name == Name &&
1968 (ec.DeclContainer.LookupType (Name, loc, /* ignore_cs0104 = */ true) != null);
1971 public override Expression DoResolve (EmitContext ec)
1973 return SimpleNameResolve (ec, null, false);
1976 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1978 return SimpleNameResolve (ec, right_side, false);
1982 public Expression DoResolve (EmitContext ec, bool intermediate)
1984 return SimpleNameResolve (ec, null, intermediate);
1987 private bool IsNestedChild (Type t, Type parent)
1992 while (parent != null) {
1993 parent = TypeManager.DropGenericTypeArguments (parent);
1994 if (TypeManager.IsNestedChildOf (t, parent))
1997 parent = parent.BaseType;
2003 FullNamedExpression ResolveNested (IResolveContext ec, Type t)
2005 if (!t.IsGenericTypeDefinition)
2008 DeclSpace ds = ec.DeclContainer;
2009 while (ds != null) {
2010 if (IsNestedChild (t, ds.TypeBuilder))
2019 Type[] gen_params = t.GetGenericArguments ();
2021 int arg_count = Arguments != null ? Arguments.Count : 0;
2023 for (; (ds != null) && ds.IsGeneric; ds = ds.Parent) {
2024 if (arg_count + ds.CountTypeParameters == gen_params.Length) {
2025 TypeArguments new_args = new TypeArguments (loc);
2026 foreach (TypeParameter param in ds.TypeParameters)
2027 new_args.Add (new TypeParameterExpr (param, loc));
2029 if (Arguments != null)
2030 new_args.Add (Arguments);
2032 return new ConstructedType (t, new_args, loc);
2039 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2041 FullNamedExpression fne = ec.DeclContainer.LookupGeneric (Name, loc);
2043 return fne.ResolveAsTypeStep (ec, silent);
2045 int errors = Report.Errors;
2046 fne = ec.DeclContainer.LookupType (Name, loc, /*ignore_cs0104=*/ false);
2049 if (fne.Type == null)
2052 FullNamedExpression nested = ResolveNested (ec, fne.Type);
2054 return nested.ResolveAsTypeStep (ec, false);
2056 if (Arguments != null) {
2057 ConstructedType ct = new ConstructedType (fne, Arguments, loc);
2058 return ct.ResolveAsTypeStep (ec, false);
2064 if (silent || errors != Report.Errors)
2067 MemberCore mc = ec.DeclContainer.GetDefinition (Name);
2069 Error_UnexpectedKind (ec.DeclContainer, "type", GetMemberType (mc), loc);
2073 string ns = ec.DeclContainer.NamespaceEntry.NS.Name;
2074 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2075 foreach (Assembly a in RootNamespace.Global.Assemblies) {
2076 Type type = a.GetType (fullname);
2078 Report.SymbolRelatedToPreviousError (type);
2079 Expression.ErrorIsInaccesible (loc, fullname);
2084 NamespaceEntry.Error_NamespaceNotFound (loc, Name);
2088 // TODO: I am still not convinced about this. If someone else will need it
2089 // implement this as virtual property in MemberCore hierarchy
2090 string GetMemberType (MemberCore mc)
2092 if (mc is PropertyBase)
2096 if (mc is FieldBase)
2098 if (mc is MethodCore)
2100 if (mc is EnumMember)
2106 Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2112 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2116 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2123 /// 7.5.2: Simple Names.
2125 /// Local Variables and Parameters are handled at
2126 /// parse time, so they never occur as SimpleNames.
2128 /// The `intermediate' flag is used by MemberAccess only
2129 /// and it is used to inform us that it is ok for us to
2130 /// avoid the static check, because MemberAccess might end
2131 /// up resolving the Name as a Type name and the access as
2132 /// a static type access.
2134 /// ie: Type Type; .... { Type.GetType (""); }
2136 /// Type is both an instance variable and a Type; Type.GetType
2137 /// is the static method not an instance method of type.
2139 Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2141 Expression e = null;
2144 // Stage 1: Performed by the parser (binding to locals or parameters).
2146 Block current_block = ec.CurrentBlock;
2147 if (current_block != null){
2148 LocalInfo vi = current_block.GetLocalInfo (Name);
2150 if (Arguments != null) {
2151 Report.Error (307, loc,
2152 "The variable `{0}' cannot be used with type arguments",
2157 LocalVariableReference var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2158 if (right_side != null) {
2159 return var.ResolveLValue (ec, right_side, loc);
2161 ResolveFlags rf = ResolveFlags.VariableOrValue;
2163 rf |= ResolveFlags.DisableFlowAnalysis;
2164 return var.Resolve (ec, rf);
2168 ParameterReference pref = current_block.Toplevel.GetParameterReference (Name, loc);
2170 if (Arguments != null) {
2171 Report.Error (307, loc,
2172 "The variable `{0}' cannot be used with type arguments",
2177 if (right_side != null)
2178 return pref.ResolveLValue (ec, right_side, loc);
2180 return pref.Resolve (ec);
2185 // Stage 2: Lookup members
2188 DeclSpace lookup_ds = ec.DeclContainer;
2189 Type almost_matched_type = null;
2190 ArrayList almost_matched = null;
2192 if (lookup_ds.TypeBuilder == null)
2195 e = MemberLookup (ec.ContainerType, lookup_ds.TypeBuilder, Name, loc);
2199 if (almost_matched == null && almostMatchedMembers.Count > 0) {
2200 almost_matched_type = lookup_ds.TypeBuilder;
2201 almost_matched = (ArrayList) almostMatchedMembers.Clone ();
2204 lookup_ds =lookup_ds.Parent;
2205 } while (lookup_ds != null);
2207 if (e == null && ec.ContainerType != null)
2208 e = MemberLookup (ec.ContainerType, ec.ContainerType, Name, loc);
2211 if (almost_matched == null && almostMatchedMembers.Count > 0) {
2212 almost_matched_type = ec.ContainerType;
2213 almost_matched = (ArrayList) almostMatchedMembers.Clone ();
2215 e = ResolveAsTypeStep (ec, true);
2219 if (almost_matched != null)
2220 almostMatchedMembers = almost_matched;
2221 if (almost_matched_type == null)
2222 almost_matched_type = ec.ContainerType;
2223 MemberLookupFailed (ec.ContainerType, null, almost_matched_type, ((SimpleName) this).Name, ec.DeclContainer.Name, true, loc);
2227 if (e is TypeExpr) {
2228 if (Arguments == null)
2231 ConstructedType ct = new ConstructedType (
2232 (FullNamedExpression) e, Arguments, loc);
2233 return ct.ResolveAsTypeStep (ec, false);
2236 if (e is MemberExpr) {
2237 MemberExpr me = (MemberExpr) e;
2240 if (me.IsInstance) {
2241 if (ec.IsStatic || ec.IsFieldInitializer) {
2243 // Note that an MemberExpr can be both IsInstance and IsStatic.
2244 // An unresolved MethodGroupExpr can contain both kinds of methods
2245 // and each predicate is true if the MethodGroupExpr contains
2246 // at least one of that kind of method.
2250 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2251 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2252 return EmptyExpression.Null;
2256 // Pass the buck to MemberAccess and Invocation.
2258 left = EmptyExpression.Null;
2260 left = ec.GetThis (loc);
2263 left = new TypeExpression (ec.ContainerType, loc);
2266 e = me.ResolveMemberAccess (ec, left, loc, null);
2270 me = e as MemberExpr;
2274 if (Arguments != null) {
2275 MethodGroupExpr mg = me as MethodGroupExpr;
2279 return mg.ResolveGeneric (ec, Arguments);
2283 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2284 me.InstanceExpression.Type != me.DeclaringType &&
2285 !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2286 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2287 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2288 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2292 return (right_side != null)
2293 ? me.DoResolveLValue (ec, right_side)
2294 : me.DoResolve (ec);
2300 public override void Emit (EmitContext ec)
2303 // If this is ever reached, then we failed to
2304 // find the name as a namespace
2307 Error (103, "The name `" + Name +
2308 "' does not exist in the class `" +
2309 ec.DeclContainer.Name + "'");
2312 public override string ToString ()
2317 public override string GetSignatureForError ()
2324 /// Represents a namespace or a type. The name of the class was inspired by
2325 /// section 10.8.1 (Fully Qualified Names).
2327 public abstract class FullNamedExpression : Expression {
2328 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2333 public abstract string FullName {
2339 /// Expression that evaluates to a type
2341 public abstract class TypeExpr : FullNamedExpression {
2342 override public FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2344 TypeExpr t = DoResolveAsTypeStep (ec);
2348 eclass = ExprClass.Type;
2352 override public Expression DoResolve (EmitContext ec)
2354 return ResolveAsTypeTerminal (ec, false);
2357 override public void Emit (EmitContext ec)
2359 throw new Exception ("Should never be called");
2362 public virtual bool CheckAccessLevel (DeclSpace ds)
2364 return ds.CheckAccessLevel (Type);
2367 public virtual bool AsAccessible (DeclSpace ds, int flags)
2369 return ds.AsAccessible (Type, flags);
2372 public virtual bool IsClass {
2373 get { return Type.IsClass; }
2376 public virtual bool IsValueType {
2377 get { return Type.IsValueType; }
2380 public virtual bool IsInterface {
2381 get { return Type.IsInterface; }
2384 public virtual bool IsSealed {
2385 get { return Type.IsSealed; }
2388 public virtual bool CanInheritFrom ()
2390 if (Type == TypeManager.enum_type ||
2391 (Type == TypeManager.value_type && RootContext.StdLib) ||
2392 Type == TypeManager.multicast_delegate_type ||
2393 Type == TypeManager.delegate_type ||
2394 Type == TypeManager.array_type)
2400 protected abstract TypeExpr DoResolveAsTypeStep (IResolveContext ec);
2402 public abstract string Name {
2406 public override bool Equals (object obj)
2408 TypeExpr tobj = obj as TypeExpr;
2412 return Type == tobj.Type;
2415 public override int GetHashCode ()
2417 return Type.GetHashCode ();
2420 public override string ToString ()
2427 /// Fully resolved Expression that already evaluated to a type
2429 public class TypeExpression : TypeExpr {
2430 public TypeExpression (Type t, Location l)
2433 eclass = ExprClass.Type;
2437 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2442 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2447 public override string Name {
2448 get { return Type.ToString (); }
2451 public override string FullName {
2452 get { return Type.FullName; }
2457 /// Used to create types from a fully qualified name. These are just used
2458 /// by the parser to setup the core types. A TypeLookupExpression is always
2459 /// classified as a type.
2461 public sealed class TypeLookupExpression : TypeExpr {
2462 readonly string name;
2464 public TypeLookupExpression (string name)
2467 eclass = ExprClass.Type;
2470 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2472 // It's null for corlib compilation only
2474 return DoResolveAsTypeStep (ec);
2479 static readonly char [] dot_array = { '.' };
2480 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2482 // If name is of the form `N.I', first lookup `N', then search a member `I' in it.
2484 string lookup_name = name;
2485 int pos = name.IndexOf ('.');
2487 rest = name.Substring (pos + 1);
2488 lookup_name = name.Substring (0, pos);
2491 FullNamedExpression resolved = RootNamespace.Global.Lookup (ec.DeclContainer, lookup_name, Location.Null);
2493 if (resolved != null && rest != null) {
2494 // Now handle the rest of the the name.
2495 string [] elements = rest.Split (dot_array);
2497 int count = elements.Length;
2499 while (i < count && resolved != null && resolved is Namespace) {
2500 Namespace ns = resolved as Namespace;
2501 element = elements [i++];
2502 lookup_name += "." + element;
2503 resolved = ns.Lookup (ec.DeclContainer, element, Location.Null);
2506 if (resolved != null && resolved is TypeExpr) {
2507 Type t = ((TypeExpr) resolved).Type;
2509 if (!ec.DeclContainer.CheckAccessLevel (t)) {
2511 lookup_name = t.FullName;
2518 t = TypeManager.GetNestedType (t, elements [i++]);
2523 if (resolved == null) {
2524 NamespaceEntry.Error_NamespaceNotFound (loc, lookup_name);
2528 if (!(resolved is TypeExpr)) {
2529 resolved.Error_UnexpectedKind (ec.DeclContainer, "type", loc);
2533 type = resolved.Type;
2537 public override string Name {
2538 get { return name; }
2541 public override string FullName {
2542 get { return name; }
2547 /// Represents an "unbound generic type", ie. typeof (Foo<>).
2550 public class UnboundTypeExpression : TypeExpr
2554 public UnboundTypeExpression (MemberName name, Location l)
2560 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2563 if (name.Left != null) {
2564 Expression lexpr = name.Left.GetTypeExpression ();
2565 expr = new MemberAccess (lexpr, name.Basename);
2567 expr = new SimpleName (name.Basename, loc);
2570 FullNamedExpression fne = expr.ResolveAsTypeStep (ec, false);
2575 return new TypeExpression (type, loc);
2578 public override string Name {
2579 get { return name.FullName; }
2582 public override string FullName {
2583 get { return name.FullName; }
2587 public class TypeAliasExpression : TypeExpr {
2588 FullNamedExpression alias;
2593 public TypeAliasExpression (FullNamedExpression alias, TypeArguments args, Location l)
2599 eclass = ExprClass.Type;
2601 name = alias.FullName + "<" + args.ToString () + ">";
2603 name = alias.FullName;
2606 public override string Name {
2607 get { return alias.FullName; }
2610 public override string FullName {
2611 get { return name; }
2614 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2616 texpr = alias.ResolveAsTypeTerminal (ec, false);
2620 Type type = texpr.Type;
2621 int num_args = TypeManager.GetNumberOfTypeArguments (type);
2624 if (num_args == 0) {
2625 Report.Error (308, loc,
2626 "The non-generic type `{0}' cannot " +
2627 "be used with type arguments.",
2628 TypeManager.CSharpName (type));
2632 ConstructedType ctype = new ConstructedType (type, args, loc);
2633 return ctype.ResolveAsTypeTerminal (ec, false);
2634 } else if (num_args > 0) {
2635 Report.Error (305, loc,
2636 "Using the generic type `{0}' " +
2637 "requires {1} type arguments",
2638 TypeManager.CSharpName (type), num_args.ToString ());
2645 public override bool CheckAccessLevel (DeclSpace ds)
2647 return texpr.CheckAccessLevel (ds);
2650 public override bool AsAccessible (DeclSpace ds, int flags)
2652 return texpr.AsAccessible (ds, flags);
2655 public override bool IsClass {
2656 get { return texpr.IsClass; }
2659 public override bool IsValueType {
2660 get { return texpr.IsValueType; }
2663 public override bool IsInterface {
2664 get { return texpr.IsInterface; }
2667 public override bool IsSealed {
2668 get { return texpr.IsSealed; }
2673 /// This class denotes an expression which evaluates to a member
2674 /// of a struct or a class.
2676 public abstract class MemberExpr : Expression
2679 /// The name of this member.
2681 public abstract string Name {
2686 /// Whether this is an instance member.
2688 public abstract bool IsInstance {
2693 /// Whether this is a static member.
2695 public abstract bool IsStatic {
2700 /// The type which declares this member.
2702 public abstract Type DeclaringType {
2707 /// The instance expression associated with this member, if it's a
2708 /// non-static member.
2710 public Expression InstanceExpression;
2712 public static void error176 (Location loc, string name)
2714 Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
2715 "with an instance reference, qualify it with a type name instead", name);
2718 // TODO: possible optimalization
2719 // Cache resolved constant result in FieldBuilder <-> expression map
2720 public virtual Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
2721 SimpleName original)
2725 // original == null || original.Resolve (...) ==> left
2728 if (left is TypeExpr) {
2730 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
2738 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
2741 error176 (loc, GetSignatureForError ());
2745 InstanceExpression = left;
2750 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
2755 if (InstanceExpression == EmptyExpression.Null) {
2756 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
2760 if (InstanceExpression.Type.IsValueType) {
2761 if (InstanceExpression is IMemoryLocation) {
2762 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
2764 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
2765 InstanceExpression.Emit (ec);
2767 t.AddressOf (ec, AddressOp.Store);
2770 InstanceExpression.Emit (ec);
2772 if (prepare_for_load)
2773 ec.ig.Emit (OpCodes.Dup);
2778 /// MethodGroup Expression.
2780 /// This is a fully resolved expression that evaluates to a type
2782 public class MethodGroupExpr : MemberExpr {
2783 public MethodBase [] Methods;
2784 bool has_type_arguments = false;
2785 bool identical_type_name = false;
2788 public MethodGroupExpr (MemberInfo [] mi, Location l)
2790 Methods = new MethodBase [mi.Length];
2791 mi.CopyTo (Methods, 0);
2792 eclass = ExprClass.MethodGroup;
2793 type = TypeManager.object_type;
2797 public MethodGroupExpr (ArrayList list, Location l)
2799 Methods = new MethodBase [list.Count];
2802 list.CopyTo (Methods, 0);
2804 foreach (MemberInfo m in list){
2805 if (!(m is MethodBase)){
2806 Console.WriteLine ("Name " + m.Name);
2807 Console.WriteLine ("Found a: " + m.GetType ().FullName);
2814 eclass = ExprClass.MethodGroup;
2815 type = TypeManager.object_type;
2818 public override Type DeclaringType {
2821 // We assume that the top-level type is in the end
2823 return Methods [Methods.Length - 1].DeclaringType;
2824 //return Methods [0].DeclaringType;
2828 public bool HasTypeArguments {
2830 return has_type_arguments;
2834 has_type_arguments = value;
2838 public bool IdenticalTypeName {
2840 return identical_type_name;
2844 identical_type_name = value;
2848 public bool IsBase {
2857 public override string GetSignatureForError ()
2859 return TypeManager.CSharpSignature (Methods [0]);
2862 public override string Name {
2864 return Methods [0].Name;
2868 public override bool IsInstance {
2870 foreach (MethodBase mb in Methods)
2878 public override bool IsStatic {
2880 foreach (MethodBase mb in Methods)
2888 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
2889 SimpleName original)
2891 if (!(left is TypeExpr) &&
2892 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
2893 IdenticalTypeName = true;
2895 return base.ResolveMemberAccess (ec, left, loc, original);
2898 override public Expression DoResolve (EmitContext ec)
2901 InstanceExpression = null;
2903 if (InstanceExpression != null) {
2904 InstanceExpression = InstanceExpression.DoResolve (ec);
2905 if (InstanceExpression == null)
2912 public void ReportUsageError ()
2914 Report.Error (654, loc, "Method `" + DeclaringType + "." +
2915 Name + "()' is referenced without parentheses");
2918 override public void Emit (EmitContext ec)
2920 ReportUsageError ();
2923 bool RemoveMethods (bool keep_static)
2925 ArrayList smethods = new ArrayList ();
2927 foreach (MethodBase mb in Methods){
2928 if (mb.IsStatic == keep_static)
2932 if (smethods.Count == 0)
2935 Methods = new MethodBase [smethods.Count];
2936 smethods.CopyTo (Methods, 0);
2942 /// Removes any instance methods from the MethodGroup, returns
2943 /// false if the resulting set is empty.
2945 public bool RemoveInstanceMethods ()
2947 return RemoveMethods (true);
2951 /// Removes any static methods from the MethodGroup, returns
2952 /// false if the resulting set is empty.
2954 public bool RemoveStaticMethods ()
2956 return RemoveMethods (false);
2959 public Expression ResolveGeneric (EmitContext ec, TypeArguments args)
2961 if (args.Resolve (ec) == false)
2964 Type[] atypes = args.Arguments;
2966 int first_count = 0;
2967 MethodInfo first = null;
2969 ArrayList list = new ArrayList ();
2970 foreach (MethodBase mb in Methods) {
2971 MethodInfo mi = mb as MethodInfo;
2972 if ((mi == null) || !mi.IsGenericMethod)
2975 Type[] gen_params = mi.GetGenericArguments ();
2977 if (first == null) {
2979 first_count = gen_params.Length;
2982 if (gen_params.Length != atypes.Length)
2985 list.Add (mi.MakeGenericMethod (atypes));
2988 if (list.Count > 0) {
2989 MethodGroupExpr new_mg = new MethodGroupExpr (list, Location);
2990 new_mg.InstanceExpression = InstanceExpression;
2991 new_mg.HasTypeArguments = true;
2992 new_mg.IsBase = IsBase;
2998 305, loc, "Using the generic method `{0}' " +
2999 "requires {1} type arguments", Name,
3000 first_count.ToString ());
3003 308, loc, "The non-generic method `{0}' " +
3004 "cannot be used with type arguments", Name);
3011 /// Fully resolved expression that evaluates to a Field
3013 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariable {
3014 public readonly FieldInfo FieldInfo;
3015 VariableInfo variable_info;
3017 LocalTemporary temp;
3019 bool in_initializer;
3021 public FieldExpr (FieldInfo fi, Location l, bool in_initializer):
3024 this.in_initializer = in_initializer;
3027 public FieldExpr (FieldInfo fi, Location l)
3030 eclass = ExprClass.Variable;
3031 type = TypeManager.TypeToCoreType (fi.FieldType);
3035 public override string Name {
3037 return FieldInfo.Name;
3041 public override bool IsInstance {
3043 return !FieldInfo.IsStatic;
3047 public override bool IsStatic {
3049 return FieldInfo.IsStatic;
3053 public override Type DeclaringType {
3055 return FieldInfo.DeclaringType;
3059 public override string GetSignatureForError ()
3061 return TypeManager.GetFullNameSignature (FieldInfo);
3064 public VariableInfo VariableInfo {
3066 return variable_info;
3070 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3071 SimpleName original)
3073 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
3075 Type t = fi.FieldType;
3077 if (fi.IsLiteral || (fi.IsInitOnly && t == TypeManager.decimal_type)) {
3078 IConstant ic = TypeManager.GetConstant (fi);
3081 ic = new ExternalConstant (fi);
3083 ic = ExternalConstant.CreateDecimal (fi);
3085 return base.ResolveMemberAccess (ec, left, loc, original);
3088 TypeManager.RegisterConstant (fi, ic);
3091 bool left_is_type = left is TypeExpr;
3092 if (!left_is_type && (original == null || !original.IdenticalNameAndTypeName (ec, left, loc))) {
3093 Report.SymbolRelatedToPreviousError (FieldInfo);
3094 error176 (loc, TypeManager.GetFullNameSignature (FieldInfo));
3098 if (ic.ResolveValue ()) {
3099 if (!ec.IsInObsoleteScope)
3100 ic.CheckObsoleteness (loc);
3106 if (t.IsPointer && !ec.InUnsafe) {
3111 return base.ResolveMemberAccess (ec, left, loc, original);
3114 override public Expression DoResolve (EmitContext ec)
3116 return DoResolve (ec, false, false);
3119 Expression DoResolve (EmitContext ec, bool lvalue_instance, bool out_access)
3121 if (!FieldInfo.IsStatic){
3122 if (InstanceExpression == null){
3124 // This can happen when referencing an instance field using
3125 // a fully qualified type expression: TypeName.InstanceField = xxx
3127 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3131 // Resolve the field's instance expression while flow analysis is turned
3132 // off: when accessing a field "a.b", we must check whether the field
3133 // "a.b" is initialized, not whether the whole struct "a" is initialized.
3135 if (lvalue_instance) {
3136 using (ec.With (EmitContext.Flags.DoFlowAnalysis, false)) {
3137 Expression right_side =
3138 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
3139 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side, loc);
3142 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
3143 InstanceExpression = InstanceExpression.Resolve (ec, rf);
3146 if (InstanceExpression == null)
3149 InstanceExpression.CheckMarshalByRefAccess ();
3152 if (!in_initializer && !ec.IsFieldInitializer) {
3153 ObsoleteAttribute oa;
3154 FieldBase f = TypeManager.GetField (FieldInfo);
3156 if (!ec.IsInObsoleteScope)
3157 f.CheckObsoleteness (loc);
3159 // To be sure that type is external because we do not register generated fields
3160 } else if (!(FieldInfo.DeclaringType is TypeBuilder)) {
3161 oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
3163 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
3167 AnonymousContainer am = ec.CurrentAnonymousMethod;
3169 if (!FieldInfo.IsStatic){
3170 if (!am.IsIterator && (ec.TypeContainer is Struct)){
3171 Report.Error (1673, loc,
3172 "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",
3176 if ((am.ContainerAnonymousMethod == null) && (InstanceExpression is This))
3177 ec.CaptureField (this);
3181 // If the instance expression is a local variable or parameter.
3182 IVariable var = InstanceExpression as IVariable;
3183 if ((var == null) || (var.VariableInfo == null))
3186 VariableInfo vi = var.VariableInfo;
3187 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
3190 variable_info = vi.GetSubStruct (FieldInfo.Name);
3194 static readonly int [] codes = {
3195 191, // instance, write access
3196 192, // instance, out access
3197 198, // static, write access
3198 199, // static, out access
3199 1648, // member of value instance, write access
3200 1649, // member of value instance, out access
3201 1650, // member of value static, write access
3202 1651 // member of value static, out access
3205 static readonly string [] msgs = {
3206 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
3207 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
3208 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
3209 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
3210 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
3211 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
3212 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
3213 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
3216 // The return value is always null. Returning a value simplifies calling code.
3217 Expression Report_AssignToReadonly (Expression right_side)
3220 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
3224 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
3226 Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
3231 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3233 IVariable var = InstanceExpression as IVariable;
3234 if ((var != null) && (var.VariableInfo != null))
3235 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
3237 bool lvalue_instance = !FieldInfo.IsStatic && FieldInfo.DeclaringType.IsValueType;
3238 bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
3240 Expression e = DoResolve (ec, lvalue_instance, out_access);
3245 FieldBase fb = TypeManager.GetField (FieldInfo);
3249 if (FieldInfo.IsInitOnly) {
3250 // InitOnly fields can only be assigned in constructors or initializers
3251 if (!ec.IsFieldInitializer && !ec.IsConstructor)
3252 return Report_AssignToReadonly (right_side);
3254 if (ec.IsConstructor) {
3255 Type ctype = ec.TypeContainer.CurrentType;
3257 ctype = ec.ContainerType;
3259 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
3260 if (!TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
3261 return Report_AssignToReadonly (right_side);
3262 // static InitOnly fields cannot be assigned-to in an instance constructor
3263 if (IsStatic && !ec.IsStatic)
3264 return Report_AssignToReadonly (right_side);
3265 // instance constructors can't modify InitOnly fields of other instances of the same type
3266 if (!IsStatic && !(InstanceExpression is This))
3267 return Report_AssignToReadonly (right_side);
3271 if (right_side == EmptyExpression.OutAccess &&
3272 !IsStatic && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
3273 Report.SymbolRelatedToPreviousError (DeclaringType);
3274 Report.Warning (197, 1, loc,
3275 "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",
3276 GetSignatureForError ());
3282 public override void CheckMarshalByRefAccess ()
3284 if (!IsStatic && Type.IsValueType && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
3285 Report.SymbolRelatedToPreviousError (DeclaringType);
3286 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",
3287 GetSignatureForError ());
3291 public bool VerifyFixed ()
3293 IVariable variable = InstanceExpression as IVariable;
3294 // A variable of the form V.I is fixed when V is a fixed variable of a struct type.
3295 // We defer the InstanceExpression check after the variable check to avoid a
3296 // separate null check on InstanceExpression.
3297 return variable != null && InstanceExpression.Type.IsValueType && variable.VerifyFixed ();
3300 public override int GetHashCode ()
3302 return FieldInfo.GetHashCode ();
3305 public override bool Equals (object obj)
3307 FieldExpr fe = obj as FieldExpr;
3311 if (FieldInfo != fe.FieldInfo)
3314 if (InstanceExpression == null || fe.InstanceExpression == null)
3317 return InstanceExpression.Equals (fe.InstanceExpression);
3320 public void Emit (EmitContext ec, bool leave_copy)
3322 ILGenerator ig = ec.ig;
3323 bool is_volatile = false;
3325 FieldBase f = TypeManager.GetField (FieldInfo);
3327 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
3330 f.SetMemberIsUsed ();
3333 if (FieldInfo.IsStatic){
3335 ig.Emit (OpCodes.Volatile);
3337 ig.Emit (OpCodes.Ldsfld, FieldInfo);
3340 EmitInstance (ec, false);
3343 ig.Emit (OpCodes.Volatile);
3345 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
3348 ig.Emit (OpCodes.Ldflda, FieldInfo);
3349 ig.Emit (OpCodes.Ldflda, ff.Element);
3352 ig.Emit (OpCodes.Ldfld, FieldInfo);
3357 ec.ig.Emit (OpCodes.Dup);
3358 if (!FieldInfo.IsStatic) {
3359 temp = new LocalTemporary (this.Type);
3365 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
3367 FieldAttributes fa = FieldInfo.Attributes;
3368 bool is_static = (fa & FieldAttributes.Static) != 0;
3369 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
3370 ILGenerator ig = ec.ig;
3371 prepared = prepare_for_load;
3373 if (is_readonly && !ec.IsConstructor){
3374 Report_AssignToReadonly (source);
3378 EmitInstance (ec, prepare_for_load);
3382 ec.ig.Emit (OpCodes.Dup);
3383 if (!FieldInfo.IsStatic) {
3384 temp = new LocalTemporary (this.Type);
3389 FieldBase f = TypeManager.GetField (FieldInfo);
3391 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
3392 ig.Emit (OpCodes.Volatile);
3398 ig.Emit (OpCodes.Stsfld, FieldInfo);
3400 ig.Emit (OpCodes.Stfld, FieldInfo);
3406 public override void Emit (EmitContext ec)
3411 public void AddressOf (EmitContext ec, AddressOp mode)
3413 ILGenerator ig = ec.ig;
3415 FieldBase f = TypeManager.GetField (FieldInfo);
3417 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
3418 Report.Warning (420, 1, loc, "`{0}': A volatile fields cannot be passed using a ref or out parameter",
3419 f.GetSignatureForError ());
3423 if ((mode & AddressOp.Store) != 0)
3425 if ((mode & AddressOp.Load) != 0)
3426 f.SetMemberIsUsed ();
3430 // Handle initonly fields specially: make a copy and then
3431 // get the address of the copy.
3434 if (FieldInfo.IsInitOnly){
3436 if (ec.IsConstructor){
3437 if (FieldInfo.IsStatic){
3449 local = ig.DeclareLocal (type);
3450 ig.Emit (OpCodes.Stloc, local);
3451 ig.Emit (OpCodes.Ldloca, local);
3456 if (FieldInfo.IsStatic){
3457 ig.Emit (OpCodes.Ldsflda, FieldInfo);
3460 EmitInstance (ec, false);
3461 ig.Emit (OpCodes.Ldflda, FieldInfo);
3467 // A FieldExpr whose address can not be taken
3469 public class FieldExprNoAddress : FieldExpr, IMemoryLocation {
3470 public FieldExprNoAddress (FieldInfo fi, Location loc) : base (fi, loc)
3474 public new void AddressOf (EmitContext ec, AddressOp mode)
3476 Report.Error (-215, "Report this: Taking the address of a remapped parameter not supported");
3481 /// Expression that evaluates to a Property. The Assign class
3482 /// might set the `Value' expression if we are in an assignment.
3484 /// This is not an LValue because we need to re-write the expression, we
3485 /// can not take data from the stack and store it.
3487 public class PropertyExpr : MemberExpr, IAssignMethod {
3488 public readonly PropertyInfo PropertyInfo;
3491 // This is set externally by the `BaseAccess' class
3494 MethodInfo getter, setter;
3499 LocalTemporary temp;
3502 internal static PtrHashtable AccessorTable = new PtrHashtable ();
3504 public PropertyExpr (Type containerType, PropertyInfo pi, Location l)
3507 eclass = ExprClass.PropertyAccess;
3511 type = TypeManager.TypeToCoreType (pi.PropertyType);
3513 ResolveAccessors (containerType);
3516 public override string Name {
3518 return PropertyInfo.Name;
3522 public override bool IsInstance {
3528 public override bool IsStatic {
3534 public override Type DeclaringType {
3536 return PropertyInfo.DeclaringType;
3540 public override string GetSignatureForError ()
3542 return TypeManager.GetFullNameSignature (PropertyInfo);
3545 void FindAccessors (Type invocation_type)
3547 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
3548 BindingFlags.Static | BindingFlags.Instance |
3549 BindingFlags.DeclaredOnly;
3551 Type current = PropertyInfo.DeclaringType;
3552 for (; current != null; current = current.BaseType) {
3553 MemberInfo[] group = TypeManager.MemberLookup (
3554 invocation_type, invocation_type, current,
3555 MemberTypes.Property, flags, PropertyInfo.Name, null);
3560 if (group.Length != 1)
3561 // Oooops, can this ever happen ?
3564 PropertyInfo pi = (PropertyInfo) group [0];
3567 getter = pi.GetGetMethod (true);
3570 setter = pi.GetSetMethod (true);
3572 MethodInfo accessor = getter != null ? getter : setter;
3574 if (!accessor.IsVirtual)
3580 // We also perform the permission checking here, as the PropertyInfo does not
3581 // hold the information for the accessibility of its setter/getter
3583 // TODO: can use TypeManager.GetProperty to boost performance
3584 void ResolveAccessors (Type containerType)
3586 FindAccessors (containerType);
3588 if (getter != null) {
3589 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
3590 IMethodData md = TypeManager.GetMethod (the_getter);
3592 md.SetMemberIsUsed ();
3594 AccessorTable [getter] = PropertyInfo;
3595 is_static = getter.IsStatic;
3598 if (setter != null) {
3599 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
3600 IMethodData md = TypeManager.GetMethod (the_setter);
3602 md.SetMemberIsUsed ();
3604 AccessorTable [setter] = PropertyInfo;
3605 is_static = setter.IsStatic;
3609 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
3612 InstanceExpression = null;
3616 if (InstanceExpression == null) {
3617 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3621 if (lvalue_instance)
3622 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
3624 InstanceExpression = InstanceExpression.DoResolve (ec);
3625 if (InstanceExpression == null)
3628 InstanceExpression.CheckMarshalByRefAccess ();
3630 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
3631 InstanceExpression.Type != ec.ContainerType &&
3632 ec.ContainerType.IsSubclassOf (PropertyInfo.DeclaringType) &&
3633 !InstanceExpression.Type.IsSubclassOf (ec.ContainerType)) {
3634 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
3641 void Error_PropertyNotFound (MethodInfo mi, bool getter)
3643 // TODO: correctly we should compare arguments but it will lead to bigger changes
3644 if (mi is MethodBuilder) {
3645 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
3649 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
3651 ParameterData iparams = TypeManager.GetParameterData (mi);
3652 sig.Append (getter ? "get_" : "set_");
3654 sig.Append (iparams.GetSignatureForError ());
3656 Report.SymbolRelatedToPreviousError (mi);
3657 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
3658 Name, sig.ToString ());
3661 override public Expression DoResolve (EmitContext ec)
3666 if (getter != null){
3667 if (TypeManager.GetParameterData (getter).Count != 0){
3668 Error_PropertyNotFound (getter, true);
3673 if (getter == null){
3675 // The following condition happens if the PropertyExpr was
3676 // created, but is invalid (ie, the property is inaccessible),
3677 // and we did not want to embed the knowledge about this in
3678 // the caller routine. This only avoids double error reporting.
3683 if (InstanceExpression != EmptyExpression.Null) {
3684 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
3685 TypeManager.GetFullNameSignature (PropertyInfo));
3690 bool must_do_cs1540_check = false;
3691 if (getter != null &&
3692 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
3693 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
3694 if (pm != null && pm.HasCustomAccessModifier) {
3695 Report.SymbolRelatedToPreviousError (pm);
3696 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
3697 TypeManager.CSharpSignature (getter));
3700 Report.SymbolRelatedToPreviousError (getter);
3701 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
3706 if (!InstanceResolve (ec, false, must_do_cs1540_check))
3710 // Only base will allow this invocation to happen.
3712 if (IsBase && getter.IsAbstract) {
3713 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
3717 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
3727 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3729 if (right_side == EmptyExpression.OutAccess) {
3730 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
3731 GetSignatureForError ());
3735 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
3736 Report.Error (1612, loc, "Cannot modify the return value of `{0}' because it is not a variable",
3737 GetSignatureForError ());
3741 if (setter == null){
3743 // The following condition happens if the PropertyExpr was
3744 // created, but is invalid (ie, the property is inaccessible),
3745 // and we did not want to embed the knowledge about this in
3746 // the caller routine. This only avoids double error reporting.
3750 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
3751 GetSignatureForError ());
3755 if (TypeManager.GetParameterData (setter).Count != 1){
3756 Error_PropertyNotFound (setter, false);
3760 bool must_do_cs1540_check;
3761 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
3762 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
3763 if (pm != null && pm.HasCustomAccessModifier) {
3764 Report.SymbolRelatedToPreviousError (pm);
3765 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
3766 TypeManager.CSharpSignature (setter));
3769 Report.SymbolRelatedToPreviousError (setter);
3770 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
3775 if (!InstanceResolve (ec, PropertyInfo.DeclaringType.IsValueType, must_do_cs1540_check))
3779 // Only base will allow this invocation to happen.
3781 if (IsBase && setter.IsAbstract){
3782 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
3789 public override void Emit (EmitContext ec)
3794 public void Emit (EmitContext ec, bool leave_copy)
3797 // Special case: length of single dimension array property is turned into ldlen
3799 if ((getter == TypeManager.system_int_array_get_length) ||
3800 (getter == TypeManager.int_array_get_length)){
3801 Type iet = InstanceExpression.Type;
3804 // System.Array.Length can be called, but the Type does not
3805 // support invoking GetArrayRank, so test for that case first
3807 if (iet != TypeManager.array_type && (iet.GetArrayRank () == 1)) {
3809 EmitInstance (ec, false);
3810 ec.ig.Emit (OpCodes.Ldlen);
3811 ec.ig.Emit (OpCodes.Conv_I4);
3816 Invocation.EmitCall (ec, IsBase, IsStatic, InstanceExpression, getter, null, loc, prepared, false);
3819 ec.ig.Emit (OpCodes.Dup);
3821 temp = new LocalTemporary (this.Type);
3828 // Implements the IAssignMethod interface for assignments
3830 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
3832 Expression my_source = source;
3834 prepared = prepare_for_load;
3839 ec.ig.Emit (OpCodes.Dup);
3841 temp = new LocalTemporary (this.Type);
3845 } else if (leave_copy) {
3848 temp = new LocalTemporary (this.Type);
3854 ArrayList args = new ArrayList (1);
3855 args.Add (new Argument (my_source, Argument.AType.Expression));
3857 Invocation.EmitCall (ec, IsBase, IsStatic, InstanceExpression, setter, args, loc, false, prepared);
3865 /// Fully resolved expression that evaluates to an Event
3867 public class EventExpr : MemberExpr {
3868 public readonly EventInfo EventInfo;
3871 MethodInfo add_accessor, remove_accessor;
3873 internal static PtrHashtable AccessorTable = new PtrHashtable ();
3875 public EventExpr (EventInfo ei, Location loc)
3879 eclass = ExprClass.EventAccess;
3881 add_accessor = TypeManager.GetAddMethod (ei);
3882 remove_accessor = TypeManager.GetRemoveMethod (ei);
3883 if (add_accessor != null)
3884 AccessorTable [add_accessor] = ei;
3885 if (remove_accessor != null)
3886 AccessorTable [remove_accessor] = ei;
3888 if (add_accessor.IsStatic || remove_accessor.IsStatic)
3891 if (EventInfo is MyEventBuilder){
3892 MyEventBuilder eb = (MyEventBuilder) EventInfo;
3893 type = eb.EventType;
3896 type = EventInfo.EventHandlerType;
3899 public override string Name {
3901 return EventInfo.Name;
3905 public override bool IsInstance {
3911 public override bool IsStatic {
3917 public override Type DeclaringType {
3919 return EventInfo.DeclaringType;
3923 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3924 SimpleName original)
3927 // If the event is local to this class, we transform ourselves into a FieldExpr
3930 if (EventInfo.DeclaringType == ec.ContainerType ||
3931 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
3932 MemberInfo mi = TypeManager.GetPrivateFieldOfEvent (EventInfo);
3935 MemberExpr ml = (MemberExpr) ExprClassFromMemberInfo (ec.ContainerType, mi, loc);
3938 Report.Error (-200, loc, "Internal error!!");
3942 InstanceExpression = null;
3944 return ml.ResolveMemberAccess (ec, left, loc, original);
3948 return base.ResolveMemberAccess (ec, left, loc, original);
3952 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
3955 InstanceExpression = null;
3959 if (InstanceExpression == null) {
3960 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3964 InstanceExpression = InstanceExpression.DoResolve (ec);
3965 if (InstanceExpression == null)
3969 // This is using the same mechanism as the CS1540 check in PropertyExpr.
3970 // However, in the Event case, we reported a CS0122 instead.
3972 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
3973 InstanceExpression.Type != ec.ContainerType &&
3974 ec.ContainerType.IsSubclassOf (InstanceExpression.Type)) {
3975 Report.SymbolRelatedToPreviousError (EventInfo);
3976 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
3983 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
3985 return DoResolve (ec);
3988 public override Expression DoResolve (EmitContext ec)
3990 bool must_do_cs1540_check;
3991 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
3992 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
3993 Report.SymbolRelatedToPreviousError (EventInfo);
3994 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
3998 if (!InstanceResolve (ec, must_do_cs1540_check))
4004 public override void Emit (EmitContext ec)
4006 if (InstanceExpression is This)
4007 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of += or -=", GetSignatureForError ());
4009 Report.Error (70, loc, "The event `{0}' can only appear on the left hand side of += or -= "+
4010 "(except on the defining type)", Name);
4013 public override string GetSignatureForError ()
4015 return TypeManager.CSharpSignature (EventInfo);
4018 public void EmitAddOrRemove (EmitContext ec, Expression source)
4020 BinaryDelegate source_del = (BinaryDelegate) source;
4021 Expression handler = source_del.Right;
4023 Argument arg = new Argument (handler, Argument.AType.Expression);
4024 ArrayList args = new ArrayList ();
4028 if (source_del.IsAddition)
4029 Invocation.EmitCall (
4030 ec, false, IsStatic, InstanceExpression, add_accessor, args, loc);
4032 Invocation.EmitCall (
4033 ec, false, IsStatic, InstanceExpression, remove_accessor, args, loc);
4038 public class TemporaryVariable : Expression, IMemoryLocation
4042 public TemporaryVariable (Type type, Location loc)
4046 eclass = ExprClass.Value;
4049 public override Expression DoResolve (EmitContext ec)
4054 TypeExpr te = new TypeExpression (type, loc);
4055 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
4056 if (!li.Resolve (ec))
4059 AnonymousContainer am = ec.CurrentAnonymousMethod;
4060 if ((am != null) && am.IsIterator)
4061 ec.CaptureVariable (li);
4066 public override void Emit (EmitContext ec)
4068 ILGenerator ig = ec.ig;
4070 if (li.FieldBuilder != null) {
4071 ig.Emit (OpCodes.Ldarg_0);
4072 ig.Emit (OpCodes.Ldfld, li.FieldBuilder);
4074 ig.Emit (OpCodes.Ldloc, li.LocalBuilder);
4078 public void EmitLoadAddress (EmitContext ec)
4080 ILGenerator ig = ec.ig;
4082 if (li.FieldBuilder != null) {
4083 ig.Emit (OpCodes.Ldarg_0);
4084 ig.Emit (OpCodes.Ldflda, li.FieldBuilder);
4086 ig.Emit (OpCodes.Ldloca, li.LocalBuilder);
4090 public void Store (EmitContext ec, Expression right_side)
4092 if (li.FieldBuilder != null)
4093 ec.ig.Emit (OpCodes.Ldarg_0);
4095 right_side.Emit (ec);
4096 if (li.FieldBuilder != null) {
4097 ec.ig.Emit (OpCodes.Stfld, li.FieldBuilder);
4099 ec.ig.Emit (OpCodes.Stloc, li.LocalBuilder);
4103 public void EmitThis (EmitContext ec)
4105 if (li.FieldBuilder != null) {
4106 ec.ig.Emit (OpCodes.Ldarg_0);
4110 public void EmitStore (ILGenerator ig)
4112 if (li.FieldBuilder != null)
4113 ig.Emit (OpCodes.Stfld, li.FieldBuilder);
4115 ig.Emit (OpCodes.Stloc, li.LocalBuilder);
4118 public void AddressOf (EmitContext ec, AddressOp mode)
4120 EmitLoadAddress (ec);